using System; using System.Collections.Generic; using System.Diagnostics; using System.Runtime.CompilerServices; namespace ETModel { /// /// Lightweight unity specified task-like object. /// [AsyncMethodBuilder(typeof (ETAsyncTaskMethodBuilder))] public partial struct ETTask: IEquatable { private static readonly ETTask DefaultAsyncUnitTask = new ETTask(AsyncUnit.Default); private readonly IAwaiter awaiter; [DebuggerHidden] public ETTask(IAwaiter awaiter) { this.awaiter = awaiter; } [DebuggerHidden] public ETTask(Func factory) { this.awaiter = new LazyPromise(factory); } [DebuggerHidden] public AwaiterStatus Status => awaiter?.Status ?? AwaiterStatus.Succeeded; [DebuggerHidden] public bool IsCompleted => awaiter?.IsCompleted ?? true; [DebuggerHidden] public void GetResult() { if (awaiter != null) { awaiter.GetResult(); } } [DebuggerHidden] public Awaiter GetAwaiter() { return new Awaiter(this); } /// /// returns (bool IsCanceled) instead of throws OperationCanceledException. /// public ETTask SuppressCancellationThrow() { AwaiterStatus status = Status; switch (status) { case AwaiterStatus.Succeeded: return CompletedTasks.False; case AwaiterStatus.Canceled: return CompletedTasks.True; default: return new ETTask(new IsCanceledAwaiter(this.awaiter)); } } public bool Equals(ETTask other) { if (this.awaiter == null && other.awaiter == null) { return true; } if (this.awaiter != null && other.awaiter != null) { return this.awaiter == other.awaiter; } return false; } public override int GetHashCode() { if (this.awaiter == null) { return 0; } return this.awaiter.GetHashCode(); } public override string ToString() { return this.awaiter == null? "()" : this.awaiter.Status == AwaiterStatus.Succeeded? "()" : "(" + this.awaiter.Status + ")"; } public static implicit operator ETTask(ETTask task) { if (task.awaiter == null) { return DefaultAsyncUnitTask; } if (task.awaiter.IsCompleted) { return DefaultAsyncUnitTask; } // UniTask -> UniTask is free but UniTask -> UniTask requires wrapping cost. return new ETTask(new AsyncUnitAwaiter(task.awaiter)); } private class AsyncUnitAwaiter: IAwaiter { private readonly IAwaiter awaiter; public AsyncUnitAwaiter(IAwaiter awaiter) { this.awaiter = awaiter; } public bool IsCompleted => awaiter.IsCompleted; public AwaiterStatus Status => awaiter.Status; public AsyncUnit GetResult() { awaiter.GetResult(); return AsyncUnit.Default; } public void OnCompleted(Action continuation) { awaiter.OnCompleted(continuation); } public void UnsafeOnCompleted(Action continuation) { awaiter.UnsafeOnCompleted(continuation); } void IAwaiter.GetResult() { awaiter.GetResult(); } } private class IsCanceledAwaiter: IAwaiter { private readonly IAwaiter awaiter; public IsCanceledAwaiter(IAwaiter awaiter) { this.awaiter = awaiter; } public bool IsCompleted => awaiter.IsCompleted; public AwaiterStatus Status => awaiter.Status; public bool GetResult() { if (awaiter.Status == AwaiterStatus.Canceled) { return true; } awaiter.GetResult(); return false; } public void OnCompleted(Action continuation) { awaiter.OnCompleted(continuation); } public void UnsafeOnCompleted(Action continuation) { awaiter.UnsafeOnCompleted(continuation); } void IAwaiter.GetResult() { awaiter.GetResult(); } } public struct Awaiter: IAwaiter { private readonly ETTask task; [DebuggerHidden] public Awaiter(ETTask task) { this.task = task; } [DebuggerHidden] public bool IsCompleted => task.IsCompleted; [DebuggerHidden] public AwaiterStatus Status => task.Status; [DebuggerHidden] public void GetResult() { task.GetResult(); } [DebuggerHidden] public void OnCompleted(Action continuation) { if (task.awaiter != null) { task.awaiter.OnCompleted(continuation); } else { continuation(); } } [DebuggerHidden] public void UnsafeOnCompleted(Action continuation) { if (task.awaiter != null) { task.awaiter.UnsafeOnCompleted(continuation); } else { continuation(); } } } } /// /// Lightweight unity specified task-like object. /// [AsyncMethodBuilder(typeof (AsyncUniTaskMethodBuilder<>))] public struct ETTask: IEquatable> { private readonly T result; private readonly IAwaiter awaiter; [DebuggerHidden] public ETTask(T result) { this.result = result; this.awaiter = null; } [DebuggerHidden] public ETTask(IAwaiter awaiter) { this.result = default; this.awaiter = awaiter; } [DebuggerHidden] public ETTask(Func> factory) { this.result = default; this.awaiter = new LazyPromise(factory); } [DebuggerHidden] public AwaiterStatus Status => awaiter?.Status ?? AwaiterStatus.Succeeded; [DebuggerHidden] public bool IsCompleted => awaiter?.IsCompleted ?? true; [DebuggerHidden] public T Result { get { if (awaiter == null) { return result; } return this.awaiter.GetResult(); } } [DebuggerHidden] public Awaiter GetAwaiter() { return new Awaiter(this); } /// /// returns (bool IsCanceled, T Result) instead of throws OperationCanceledException. /// public ETTask<(bool IsCanceled, T Result)> SuppressCancellationThrow() { var status = Status; if (status == AwaiterStatus.Succeeded) { return new ETTask<(bool, T)>((false, Result)); } if (status == AwaiterStatus.Canceled) { return new ETTask<(bool, T)>((true, default)); } return new ETTask<(bool, T)>(new IsCanceledAwaiter(awaiter)); } public bool Equals(ETTask other) { if (this.awaiter == null && other.awaiter == null) { return EqualityComparer.Default.Equals(this.result, other.result); } if (this.awaiter != null && other.awaiter != null) { return this.awaiter == other.awaiter; } return false; } public override int GetHashCode() { if (this.awaiter == null) { if (result == null) { return 0; } return result.GetHashCode(); } return this.awaiter.GetHashCode(); } public override string ToString() { return this.awaiter == null? result.ToString() : this.awaiter.Status == AwaiterStatus.Succeeded? this.awaiter.GetResult().ToString() : "(" + this.awaiter.Status + ")"; } public static implicit operator ETTask(ETTask task) { if (task.awaiter != null) { return new ETTask(task.awaiter); } return new ETTask(); } private class IsCanceledAwaiter: IAwaiter<(bool, T)> { private readonly IAwaiter awaiter; public IsCanceledAwaiter(IAwaiter awaiter) { this.awaiter = awaiter; } public bool IsCompleted => awaiter.IsCompleted; public AwaiterStatus Status => awaiter.Status; public (bool, T) GetResult() { if (awaiter.Status == AwaiterStatus.Canceled) { return (true, default); } return (false, awaiter.GetResult()); } public void OnCompleted(Action continuation) { awaiter.OnCompleted(continuation); } public void UnsafeOnCompleted(Action continuation) { awaiter.UnsafeOnCompleted(continuation); } void IAwaiter.GetResult() { awaiter.GetResult(); } } public struct Awaiter: IAwaiter { private readonly ETTask task; [DebuggerHidden] public Awaiter(ETTask task) { this.task = task; } [DebuggerHidden] public bool IsCompleted => task.IsCompleted; [DebuggerHidden] public AwaiterStatus Status => task.Status; [DebuggerHidden] void IAwaiter.GetResult() { GetResult(); } [DebuggerHidden] public T GetResult() { return task.Result; } [DebuggerHidden] public void OnCompleted(Action continuation) { if (task.awaiter != null) { task.awaiter.OnCompleted(continuation); } else { continuation(); } } [DebuggerHidden] public void UnsafeOnCompleted(Action continuation) { if (task.awaiter != null) { task.awaiter.UnsafeOnCompleted(continuation); } else { continuation(); } } } } }