#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6)) #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member using System; using System.Threading; using UniRx.Async.Internal; using UnityEngine; using UnityEngine.Networking; namespace UniRx.Async { public static partial class UnityAsyncExtensions { public static AsyncOperationAwaiter GetAwaiter(this AsyncOperation asyncOperation) { Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation)); return new AsyncOperationAwaiter(asyncOperation); } public static UniTask ToUniTask(this AsyncOperation asyncOperation) { Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation)); return new UniTask(new AsyncOperationAwaiter(asyncOperation)); } public static UniTask ConfigureAwait(this AsyncOperation asyncOperation, IProgress progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellation = default(CancellationToken)) { Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation)); var awaiter = new AsyncOperationConfiguredAwaiter(asyncOperation, progress, cancellation); if (!awaiter.IsCompleted) { PlayerLoopHelper.AddAction(timing, awaiter); } return new UniTask(awaiter); } public static ResourceRequestAwaiter GetAwaiter(this ResourceRequest resourceRequest) { Error.ThrowArgumentNullException(resourceRequest, nameof(resourceRequest)); return new ResourceRequestAwaiter(resourceRequest); } public static UniTask ToUniTask(this ResourceRequest resourceRequest) { Error.ThrowArgumentNullException(resourceRequest, nameof(resourceRequest)); return new UniTask(new ResourceRequestAwaiter(resourceRequest)); } public static UniTask ConfigureAwait(this ResourceRequest resourceRequest, IProgress progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellation = default(CancellationToken)) { Error.ThrowArgumentNullException(resourceRequest, nameof(resourceRequest)); var awaiter = new ResourceRequestConfiguredAwaiter(resourceRequest, progress, cancellation); if (!awaiter.IsCompleted) { PlayerLoopHelper.AddAction(timing, awaiter); } return new UniTask(awaiter); } public static AssetBundleRequestAwaiter GetAwaiter(this AssetBundleRequest resourceRequest) { Error.ThrowArgumentNullException(resourceRequest, nameof(resourceRequest)); return new AssetBundleRequestAwaiter(resourceRequest); } public static UniTask ToUniTask(this AssetBundleRequest resourceRequest) { Error.ThrowArgumentNullException(resourceRequest, nameof(resourceRequest)); return new UniTask(new AssetBundleRequestAwaiter(resourceRequest)); } public static UniTask ConfigureAwait(this AssetBundleRequest resourceRequest, IProgress progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellation = default(CancellationToken)) { Error.ThrowArgumentNullException(resourceRequest, nameof(resourceRequest)); var awaiter = new AssetBundleRequestConfiguredAwaiter(resourceRequest, progress, cancellation); if (!awaiter.IsCompleted) { PlayerLoopHelper.AddAction(timing, awaiter); } return new UniTask(awaiter); } public static AssetBundleCreateRequestAwaiter GetAwaiter(this AssetBundleCreateRequest resourceRequest) { Error.ThrowArgumentNullException(resourceRequest, nameof(resourceRequest)); return new AssetBundleCreateRequestAwaiter(resourceRequest); } public static UniTask ToUniTask(this AssetBundleCreateRequest resourceRequest) { Error.ThrowArgumentNullException(resourceRequest, nameof(resourceRequest)); return new UniTask(new AssetBundleCreateRequestAwaiter(resourceRequest)); } public static UniTask ConfigureAwait(this AssetBundleCreateRequest resourceRequest, IProgress progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellation = default(CancellationToken)) { Error.ThrowArgumentNullException(resourceRequest, nameof(resourceRequest)); var awaiter = new AssetBundleCreateRequestConfiguredAwaiter(resourceRequest, progress, cancellation); if (!awaiter.IsCompleted) { PlayerLoopHelper.AddAction(timing, awaiter); } return new UniTask(awaiter); } #if ENABLE_WWW #if UNITY_2018_3_OR_NEWER #pragma warning disable CS0618 #endif public static IAwaiter GetAwaiter(this WWW www) { Error.ThrowArgumentNullException(www, nameof(www)); var awaiter = new WWWConfiguredAwaiter(www, null, CancellationToken.None); if (!awaiter.IsCompleted) { PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, awaiter); } return awaiter; } public static UniTask ToUniTask(this WWW www) { Error.ThrowArgumentNullException(www, nameof(www)); var awaiter = new WWWConfiguredAwaiter(www, null, CancellationToken.None); if (!awaiter.IsCompleted) { PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, awaiter); } return new UniTask(awaiter); } public static UniTask ConfigureAwait(this WWW www, IProgress progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellation = default(CancellationToken)) { Error.ThrowArgumentNullException(www, nameof(www)); var awaiter = new WWWConfiguredAwaiter(www, progress, cancellation); if (!awaiter.IsCompleted) { PlayerLoopHelper.AddAction(timing, awaiter); } return new UniTask(awaiter); } #if UNITY_2018_3_OR_NEWER #pragma warning restore CS0618 #endif #endif #if ENABLE_UNITYWEBREQUEST public static UnityWebRequestAsyncOperationAwaiter GetAwaiter(this UnityWebRequestAsyncOperation asyncOperation) { Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation)); return new UnityWebRequestAsyncOperationAwaiter(asyncOperation); } public static UniTask ToUniTask(this UnityWebRequestAsyncOperation asyncOperation) { Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation)); return new UniTask(new UnityWebRequestAsyncOperationAwaiter(asyncOperation)); } public static UniTask ConfigureAwait(this UnityWebRequestAsyncOperation asyncOperation, IProgress progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellation = default(CancellationToken)) { Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation)); var awaiter = new UnityWebRequestAsyncOperationConfiguredAwaiter(asyncOperation, progress, cancellation); if (!awaiter.IsCompleted) { PlayerLoopHelper.AddAction(timing, awaiter); } return new UniTask(awaiter); } #endif public struct AsyncOperationAwaiter : IAwaiter { AsyncOperation asyncOperation; Action continuationAction; AwaiterStatus status; public AsyncOperationAwaiter(AsyncOperation asyncOperation) { this.status = asyncOperation.isDone ? AwaiterStatus.Succeeded : AwaiterStatus.Pending; this.asyncOperation = (this.status.IsCompleted()) ? null : asyncOperation; this.continuationAction = null; } public bool IsCompleted => status.IsCompleted(); public AwaiterStatus Status => status; public void GetResult() { if (status == AwaiterStatus.Succeeded) return; if (status == AwaiterStatus.Pending) { // first timing of call if (asyncOperation.isDone) { status = AwaiterStatus.Succeeded; } else { Error.ThrowNotYetCompleted(); } } if (continuationAction != null) { asyncOperation.completed -= continuationAction; asyncOperation = null; // remove reference. continuationAction = null; } else { asyncOperation = null; // remove reference. } } public void OnCompleted(Action continuation) { UnsafeOnCompleted(continuation); } public void UnsafeOnCompleted(Action continuation) { Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction); continuationAction = continuation.AsFuncOfT(); asyncOperation.completed += continuationAction; } } class AsyncOperationConfiguredAwaiter : IAwaiter, IPlayerLoopItem { AsyncOperation asyncOperation; IProgress progress; CancellationToken cancellationToken; AwaiterStatus status; Action continuation; public AsyncOperationConfiguredAwaiter(AsyncOperation asyncOperation, IProgress progress, CancellationToken cancellationToken) { this.status = cancellationToken.IsCancellationRequested ? AwaiterStatus.Canceled : asyncOperation.isDone ? AwaiterStatus.Succeeded : AwaiterStatus.Pending; if (this.status.IsCompleted()) return; this.asyncOperation = asyncOperation; this.progress = progress; this.cancellationToken = cancellationToken; this.continuation = null; TaskTracker.TrackActiveTask(this, 2); } public bool IsCompleted => status.IsCompleted(); public AwaiterStatus Status => status; public void GetResult() { if (status == AwaiterStatus.Succeeded) { return; } else if (status == AwaiterStatus.Canceled) { Error.ThrowOperationCanceledException(); } Error.ThrowNotYetCompleted(); } public bool MoveNext() { if (cancellationToken.IsCancellationRequested) { InvokeContinuation(AwaiterStatus.Canceled); return false; } if (progress != null) { progress.Report(asyncOperation.progress); } if (asyncOperation.isDone) { InvokeContinuation(AwaiterStatus.Succeeded); return false; } return true; } void InvokeContinuation(AwaiterStatus status) { this.status = status; var cont = this.continuation; // cleanup TaskTracker.RemoveTracking(this); this.continuation = null; this.cancellationToken = CancellationToken.None; this.progress = null; this.asyncOperation = null; if (cont != null) cont.Invoke(); } public void OnCompleted(Action continuation) { UnsafeOnCompleted(continuation); } public void UnsafeOnCompleted(Action continuation) { Error.ThrowWhenContinuationIsAlreadyRegistered(this.continuation); this.continuation = continuation; } } public struct ResourceRequestAwaiter : IAwaiter { ResourceRequest asyncOperation; Action continuationAction; AwaiterStatus status; UnityEngine.Object result; public ResourceRequestAwaiter(ResourceRequest asyncOperation) { this.status = asyncOperation.isDone ? AwaiterStatus.Succeeded : AwaiterStatus.Pending; this.asyncOperation = (this.status.IsCompleted()) ? null : asyncOperation; this.result = (this.status.IsCompletedSuccessfully()) ? asyncOperation.asset : null; this.continuationAction = null; } public bool IsCompleted => status.IsCompleted(); public AwaiterStatus Status => status; public UnityEngine.Object GetResult() { if (status == AwaiterStatus.Succeeded) return this.result; if (status == AwaiterStatus.Pending) { // first timing of call if (asyncOperation.isDone) { status = AwaiterStatus.Succeeded; } else { Error.ThrowNotYetCompleted(); } } this.result = asyncOperation.asset; if (continuationAction != null) { asyncOperation.completed -= continuationAction; asyncOperation = null; // remove reference. continuationAction = null; } else { asyncOperation = null; // remove reference. } return this.result; } void IAwaiter.GetResult() => GetResult(); public void OnCompleted(Action continuation) { UnsafeOnCompleted(continuation); } public void UnsafeOnCompleted(Action continuation) { Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction); continuationAction = continuation.AsFuncOfT(); asyncOperation.completed += continuationAction; } } class ResourceRequestConfiguredAwaiter : IAwaiter, IPlayerLoopItem { ResourceRequest asyncOperation; IProgress progress; CancellationToken cancellationToken; AwaiterStatus status; Action continuation; UnityEngine.Object result; public ResourceRequestConfiguredAwaiter(ResourceRequest asyncOperation, IProgress progress, CancellationToken cancellationToken) { this.status = cancellationToken.IsCancellationRequested ? AwaiterStatus.Canceled : asyncOperation.isDone ? AwaiterStatus.Succeeded : AwaiterStatus.Pending; if (this.status.IsCompletedSuccessfully()) this.result = asyncOperation.asset; if (this.status.IsCompleted()) return; this.asyncOperation = asyncOperation; this.progress = progress; this.cancellationToken = cancellationToken; this.continuation = null; this.result = null; TaskTracker.TrackActiveTask(this, 2); } public bool IsCompleted => status.IsCompleted(); public AwaiterStatus Status => status; void IAwaiter.GetResult() => GetResult(); public UnityEngine.Object GetResult() { if (status == AwaiterStatus.Succeeded) return this.result; if (status == AwaiterStatus.Canceled) { Error.ThrowOperationCanceledException(); } return Error.ThrowNotYetCompleted(); } public bool MoveNext() { if (cancellationToken.IsCancellationRequested) { InvokeContinuation(AwaiterStatus.Canceled); return false; } if (progress != null) { progress.Report(asyncOperation.progress); } if (asyncOperation.isDone) { this.result = asyncOperation.asset; InvokeContinuation(AwaiterStatus.Succeeded); return false; } return true; } void InvokeContinuation(AwaiterStatus status) { this.status = status; var cont = this.continuation; // cleanup TaskTracker.RemoveTracking(this); this.continuation = null; this.cancellationToken = CancellationToken.None; this.progress = null; this.asyncOperation = null; if (cont != null) cont.Invoke(); } public void OnCompleted(Action continuation) { Error.ThrowWhenContinuationIsAlreadyRegistered(this.continuation); this.continuation = continuation; } public void UnsafeOnCompleted(Action continuation) { Error.ThrowWhenContinuationIsAlreadyRegistered(this.continuation); this.continuation = continuation; } } // TODO: try to check API. class ResourceRequestConfiguredSource : IUniTaskSource, IPlayerLoopItem, IPromisePoolItem { static readonly PromisePool pool = new PromisePool(); ResourceRequest asyncOperation; IProgress progress; CancellationToken cancellationToken; UniTaskCompletionSourceCore core; ResourceRequestConfiguredSource() { } public static IUniTaskSource Create(ResourceRequest asyncOperation, PlayerLoopTiming timing, IProgress progress, CancellationToken cancellationToken, out short token) { if (cancellationToken.IsCancellationRequested) { return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token); } var result = pool.TryRent() ?? new ResourceRequestConfiguredSource(); result.asyncOperation = asyncOperation; result.progress = progress; result.cancellationToken = cancellationToken; #if UNITY_EDITOR // TODO:capture??? //var capturedStackTraceForDebugging = TaskTracker.CaptureStackTrace(2); // TODO:Add ActiveTask? // TaskTracker.TrackActiveTask( #endif PlayerLoopHelper.AddAction(timing, result); token = result.core.Version; return result; } public UnityEngine.Object GetResult(short token) { try { return core.GetResult(token); } finally { pool.TryReturn(this); } } void IUniTaskSource.GetResult(short token) { GetResult(token); } public AwaiterStatus GetStatus(short token) { return core.GetStatus(token); } public AwaiterStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public bool MoveNext() { if (cancellationToken.IsCancellationRequested) { // TODO:Remove Tracking // TaskTracker.RemoveTracking(); core.SetCanceled(cancellationToken); return false; } if (progress != null) { progress.Report(asyncOperation.progress); } if (asyncOperation.isDone) { // TODO:Remove Tracking // TaskTracker.RemoveTracking(); core.SetResult(asyncOperation.asset); return false; } return true; } public void Reset() { core.Reset(); asyncOperation = default; progress = default; cancellationToken = default; } } public struct AssetBundleRequestAwaiter : IAwaiter { AssetBundleRequest asyncOperation; Action continuationAction; AwaiterStatus status; UnityEngine.Object result; public AssetBundleRequestAwaiter(AssetBundleRequest asyncOperation) { this.status = asyncOperation.isDone ? AwaiterStatus.Succeeded : AwaiterStatus.Pending; this.asyncOperation = (this.status.IsCompleted()) ? null : asyncOperation; this.result = (this.status.IsCompletedSuccessfully()) ? asyncOperation.asset : null; this.continuationAction = null; } public bool IsCompleted => status.IsCompleted(); public AwaiterStatus Status => status; public UnityEngine.Object GetResult() { if (status == AwaiterStatus.Succeeded) return this.result; if (status == AwaiterStatus.Pending) { // first timing of call if (asyncOperation.isDone) { status = AwaiterStatus.Succeeded; } else { Error.ThrowNotYetCompleted(); } } this.result = asyncOperation.asset; if (continuationAction != null) { asyncOperation.completed -= continuationAction; asyncOperation = null; // remove reference. continuationAction = null; } else { asyncOperation = null; // remove reference. } return this.result; } void IAwaiter.GetResult() => GetResult(); public void OnCompleted(Action continuation) { UnsafeOnCompleted(continuation); } public void UnsafeOnCompleted(Action continuation) { Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction); continuationAction = continuation.AsFuncOfT(); asyncOperation.completed += continuationAction; } } class AssetBundleRequestConfiguredAwaiter : IAwaiter, IPlayerLoopItem { AssetBundleRequest asyncOperation; IProgress progress; CancellationToken cancellationToken; AwaiterStatus status; Action continuation; UnityEngine.Object result; public AssetBundleRequestConfiguredAwaiter(AssetBundleRequest asyncOperation, IProgress progress, CancellationToken cancellationToken) { this.status = cancellationToken.IsCancellationRequested ? AwaiterStatus.Canceled : asyncOperation.isDone ? AwaiterStatus.Succeeded : AwaiterStatus.Pending; if (this.status.IsCompletedSuccessfully()) this.result = asyncOperation.asset; if (this.status.IsCompleted()) return; this.asyncOperation = asyncOperation; this.progress = progress; this.cancellationToken = cancellationToken; this.continuation = null; this.result = null; TaskTracker.TrackActiveTask(this, 2); } public bool IsCompleted => status.IsCompleted(); public AwaiterStatus Status => status; void IAwaiter.GetResult() => GetResult(); public UnityEngine.Object GetResult() { if (status == AwaiterStatus.Succeeded) return this.result; if (status == AwaiterStatus.Canceled) { Error.ThrowOperationCanceledException(); } return Error.ThrowNotYetCompleted(); } public bool MoveNext() { if (cancellationToken.IsCancellationRequested) { InvokeContinuation(AwaiterStatus.Canceled); return false; } if (progress != null) { progress.Report(asyncOperation.progress); } if (asyncOperation.isDone) { this.result = asyncOperation.asset; InvokeContinuation(AwaiterStatus.Succeeded); return false; } return true; } void InvokeContinuation(AwaiterStatus status) { this.status = status; var cont = this.continuation; // cleanup TaskTracker.RemoveTracking(this); this.continuation = null; this.cancellationToken = CancellationToken.None; this.progress = null; this.asyncOperation = null; if (cont != null) cont.Invoke(); } public void OnCompleted(Action continuation) { Error.ThrowWhenContinuationIsAlreadyRegistered(this.continuation); this.continuation = continuation; } public void UnsafeOnCompleted(Action continuation) { Error.ThrowWhenContinuationIsAlreadyRegistered(this.continuation); this.continuation = continuation; } } public struct AssetBundleCreateRequestAwaiter : IAwaiter { AssetBundleCreateRequest asyncOperation; Action continuationAction; AwaiterStatus status; AssetBundle result; public AssetBundleCreateRequestAwaiter(AssetBundleCreateRequest asyncOperation) { this.status = asyncOperation.isDone ? AwaiterStatus.Succeeded : AwaiterStatus.Pending; this.asyncOperation = (this.status.IsCompleted()) ? null : asyncOperation; this.result = (this.status.IsCompletedSuccessfully()) ? asyncOperation.assetBundle : null; this.continuationAction = null; } public bool IsCompleted => status.IsCompleted(); public AwaiterStatus Status => status; public AssetBundle GetResult() { if (status == AwaiterStatus.Succeeded) return this.result; if (status == AwaiterStatus.Pending) { // first timing of call if (asyncOperation.isDone) { status = AwaiterStatus.Succeeded; } else { Error.ThrowNotYetCompleted(); } } this.result = asyncOperation.assetBundle; if (continuationAction != null) { asyncOperation.completed -= continuationAction; asyncOperation = null; // remove reference. continuationAction = null; } else { asyncOperation = null; // remove reference. } return this.result; } void IAwaiter.GetResult() => GetResult(); public void OnCompleted(Action continuation) { UnsafeOnCompleted(continuation); } public void UnsafeOnCompleted(Action continuation) { Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction); continuationAction = continuation.AsFuncOfT(); asyncOperation.completed += continuationAction; } } class AssetBundleCreateRequestConfiguredAwaiter : IAwaiter, IPlayerLoopItem { AssetBundleCreateRequest asyncOperation; IProgress progress; CancellationToken cancellationToken; AwaiterStatus status; Action continuation; AssetBundle result; public AssetBundleCreateRequestConfiguredAwaiter(AssetBundleCreateRequest asyncOperation, IProgress progress, CancellationToken cancellationToken) { this.status = cancellationToken.IsCancellationRequested ? AwaiterStatus.Canceled : asyncOperation.isDone ? AwaiterStatus.Succeeded : AwaiterStatus.Pending; if (this.status.IsCompletedSuccessfully()) this.result = asyncOperation.assetBundle; if (this.status.IsCompleted()) return; this.asyncOperation = asyncOperation; this.progress = progress; this.cancellationToken = cancellationToken; this.continuation = null; this.result = null; TaskTracker.TrackActiveTask(this, 2); } public bool IsCompleted => status.IsCompleted(); public AwaiterStatus Status => status; void IAwaiter.GetResult() => GetResult(); public AssetBundle GetResult() { if (status == AwaiterStatus.Succeeded) return this.result; if (status == AwaiterStatus.Canceled) { Error.ThrowOperationCanceledException(); } return Error.ThrowNotYetCompleted(); } public bool MoveNext() { if (cancellationToken.IsCancellationRequested) { InvokeContinuation(AwaiterStatus.Canceled); return false; } if (progress != null) { progress.Report(asyncOperation.progress); } if (asyncOperation.isDone) { this.result = asyncOperation.assetBundle; InvokeContinuation(AwaiterStatus.Succeeded); return false; } return true; } void InvokeContinuation(AwaiterStatus status) { this.status = status; var cont = this.continuation; // cleanup TaskTracker.RemoveTracking(this); this.continuation = null; this.cancellationToken = CancellationToken.None; this.progress = null; this.asyncOperation = null; if (cont != null) cont.Invoke(); } public void OnCompleted(Action continuation) { Error.ThrowWhenContinuationIsAlreadyRegistered(this.continuation); this.continuation = continuation; } public void UnsafeOnCompleted(Action continuation) { Error.ThrowWhenContinuationIsAlreadyRegistered(this.continuation); this.continuation = continuation; } } #if ENABLE_WWW #if UNITY_2018_3_OR_NEWER #pragma warning disable CS0618 #endif class WWWConfiguredAwaiter : IAwaiter, IPlayerLoopItem { WWW asyncOperation; IProgress progress; CancellationToken cancellationToken; AwaiterStatus status; Action continuation; public WWWConfiguredAwaiter(WWW asyncOperation, IProgress progress, CancellationToken cancellationToken) { this.status = cancellationToken.IsCancellationRequested ? AwaiterStatus.Canceled : asyncOperation.isDone ? AwaiterStatus.Succeeded : AwaiterStatus.Pending; if (this.status.IsCompleted()) return; this.asyncOperation = asyncOperation; this.progress = progress; this.cancellationToken = cancellationToken; this.continuation = null; TaskTracker.TrackActiveTask(this, 2); } public bool IsCompleted => status.IsCompleted(); public AwaiterStatus Status => status; public void GetResult() { if (status == AwaiterStatus.Succeeded) { return; } else if (status == AwaiterStatus.Canceled) { Error.ThrowOperationCanceledException(); } Error.ThrowNotYetCompleted(); } public bool MoveNext() { if (cancellationToken.IsCancellationRequested) { InvokeContinuation(AwaiterStatus.Canceled); return false; } if (progress != null) { progress.Report(asyncOperation.progress); } if (asyncOperation.isDone) { InvokeContinuation(AwaiterStatus.Succeeded); return false; } return true; } void InvokeContinuation(AwaiterStatus status) { this.status = status; var cont = this.continuation; // cleanup TaskTracker.RemoveTracking(this); this.continuation = null; this.cancellationToken = CancellationToken.None; this.progress = null; this.asyncOperation = null; if (cont != null) cont.Invoke(); } public void OnCompleted(Action continuation) { UnsafeOnCompleted(continuation); } public void UnsafeOnCompleted(Action continuation) { Error.ThrowWhenContinuationIsAlreadyRegistered(this.continuation); this.continuation = continuation; } } #if UNITY_2018_3_OR_NEWER #pragma warning restore CS0618 #endif #endif #if ENABLE_UNITYWEBREQUEST public struct UnityWebRequestAsyncOperationAwaiter : IAwaiter { UnityWebRequestAsyncOperation asyncOperation; Action continuationAction; AwaiterStatus status; UnityWebRequest result; public UnityWebRequestAsyncOperationAwaiter(UnityWebRequestAsyncOperation asyncOperation) { this.status = asyncOperation.isDone ? AwaiterStatus.Succeeded : AwaiterStatus.Pending; this.asyncOperation = (this.status.IsCompleted()) ? null : asyncOperation; this.result = (this.status.IsCompletedSuccessfully()) ? asyncOperation.webRequest : null; this.continuationAction = null; } public bool IsCompleted => status.IsCompleted(); public AwaiterStatus Status => status; public UnityWebRequest GetResult() { if (status == AwaiterStatus.Succeeded) return this.result; if (status == AwaiterStatus.Pending) { // first timing of call if (asyncOperation.isDone) { status = AwaiterStatus.Succeeded; } else { Error.ThrowNotYetCompleted(); } } this.result = asyncOperation.webRequest; if (continuationAction != null) { asyncOperation.completed -= continuationAction; asyncOperation = null; // remove reference. continuationAction = null; } else { asyncOperation = null; // remove reference. } return this.result; } void IAwaiter.GetResult() => GetResult(); public void OnCompleted(Action continuation) { UnsafeOnCompleted(continuation); } public void UnsafeOnCompleted(Action continuation) { Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction); continuationAction = continuation.AsFuncOfT(); asyncOperation.completed += continuationAction; } } class UnityWebRequestAsyncOperationConfiguredAwaiter : IAwaiter, IPlayerLoopItem { UnityWebRequestAsyncOperation asyncOperation; IProgress progress; CancellationToken cancellationToken; AwaiterStatus status; Action continuation; UnityWebRequest result; public UnityWebRequestAsyncOperationConfiguredAwaiter(UnityWebRequestAsyncOperation asyncOperation, IProgress progress, CancellationToken cancellationToken) { this.status = cancellationToken.IsCancellationRequested ? AwaiterStatus.Canceled : asyncOperation.isDone ? AwaiterStatus.Succeeded : AwaiterStatus.Pending; if (this.status.IsCompletedSuccessfully()) this.result = asyncOperation.webRequest; if (this.status.IsCompleted()) return; this.asyncOperation = asyncOperation; this.progress = progress; this.cancellationToken = cancellationToken; this.continuation = null; this.result = null; TaskTracker.TrackActiveTask(this, 2); } public bool IsCompleted => status.IsCompleted(); public AwaiterStatus Status => status; void IAwaiter.GetResult() => GetResult(); public UnityWebRequest GetResult() { if (status == AwaiterStatus.Succeeded) return this.result; if (status == AwaiterStatus.Canceled) { Error.ThrowOperationCanceledException(); } return Error.ThrowNotYetCompleted(); } public bool MoveNext() { if (cancellationToken.IsCancellationRequested) { InvokeContinuation(AwaiterStatus.Canceled); return false; } if (progress != null) { progress.Report(asyncOperation.progress); } if (asyncOperation.isDone) { this.result = asyncOperation.webRequest; InvokeContinuation(AwaiterStatus.Succeeded); return false; } return true; } void InvokeContinuation(AwaiterStatus status) { this.status = status; var cont = this.continuation; // cleanup TaskTracker.RemoveTracking(this); this.continuation = null; this.cancellationToken = CancellationToken.None; this.progress = null; this.asyncOperation = null; if (cont != null) cont.Invoke(); } public void OnCompleted(Action continuation) { Error.ThrowWhenContinuationIsAlreadyRegistered(this.continuation); this.continuation = continuation; } public void UnsafeOnCompleted(Action continuation) { Error.ThrowWhenContinuationIsAlreadyRegistered(this.continuation); this.continuation = continuation; } } #endif } } #endif