UniTask/Assets/UniRx.Async/UnityAsyncExtensions.cs

1203 lines
42 KiB
C#

#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.Runtime.CompilerServices;
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<float> 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<UnityEngine.Object> ToUniTask(this ResourceRequest resourceRequest)
{
Error.ThrowArgumentNullException(resourceRequest, nameof(resourceRequest));
return new UniTask<UnityEngine.Object>(new ResourceRequestAwaiter(resourceRequest));
}
public static UniTask<UnityEngine.Object> ConfigureAwait(this ResourceRequest resourceRequest, IProgress<float> 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<UnityEngine.Object>(awaiter);
}
public static AssetBundleRequestAwaiter GetAwaiter(this AssetBundleRequest resourceRequest)
{
Error.ThrowArgumentNullException(resourceRequest, nameof(resourceRequest));
return new AssetBundleRequestAwaiter(resourceRequest);
}
public static UniTask<UnityEngine.Object> ToUniTask(this AssetBundleRequest resourceRequest)
{
Error.ThrowArgumentNullException(resourceRequest, nameof(resourceRequest));
return new UniTask<UnityEngine.Object>(new AssetBundleRequestAwaiter(resourceRequest));
}
public static UniTask<UnityEngine.Object> ConfigureAwait(this AssetBundleRequest resourceRequest, IProgress<float> 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<UnityEngine.Object>(awaiter);
}
public static AssetBundleCreateRequestAwaiter GetAwaiter(this AssetBundleCreateRequest resourceRequest)
{
Error.ThrowArgumentNullException(resourceRequest, nameof(resourceRequest));
return new AssetBundleCreateRequestAwaiter(resourceRequest);
}
public static UniTask<AssetBundle> ToUniTask(this AssetBundleCreateRequest resourceRequest)
{
Error.ThrowArgumentNullException(resourceRequest, nameof(resourceRequest));
return new UniTask<AssetBundle>(new AssetBundleCreateRequestAwaiter(resourceRequest));
}
public static UniTask<AssetBundle> ConfigureAwait(this AssetBundleCreateRequest resourceRequest, IProgress<float> 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<AssetBundle>(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<float> 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<UnityWebRequest> ToUniTask(this UnityWebRequestAsyncOperation asyncOperation)
{
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
return new UniTask<UnityWebRequest>(new UnityWebRequestAsyncOperationAwaiter(asyncOperation));
}
public static UniTask<UnityWebRequest> ConfigureAwait(this UnityWebRequestAsyncOperation asyncOperation, IProgress<float> 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<UnityWebRequest>(awaiter);
}
#endif
public struct AsyncOperationAwaiter : ICriticalNotifyCompletion
{
AsyncOperation asyncOperation;
Action<AsyncOperation> continuationAction;
// UniTaskStatus status;
public AsyncOperationAwaiter(AsyncOperation asyncOperation)
{
this.status = asyncOperation.isDone ? UniTaskStatus.Succeeded : UniTaskStatus.Pending;
this.asyncOperation = (this.status.IsCompleted()) ? null : asyncOperation;
this.continuationAction = null;
}
public bool IsCompleted => asyncOperation.isDone;
public void GetResult()
{
//*/ if (status == UniTaskStatus.Succeeded) return;
/*
if (status == UniTaskStatus.Pending)
{
// first timing of call
if (asyncOperation.isDone)
{
status = UniTaskStatus.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>(); // allocate delegate.
asyncOperation.completed += continuationAction;
}
}
class AsyncOperationConfiguredAwaiter : IAwaiter, IPlayerLoopItem
{
AsyncOperation asyncOperation;
IProgress<float> progress;
CancellationToken cancellationToken;
UniTaskStatus status;
Action continuation;
public AsyncOperationConfiguredAwaiter(AsyncOperation asyncOperation, IProgress<float> progress, CancellationToken cancellationToken)
{
this.status = cancellationToken.IsCancellationRequested ? UniTaskStatus.Canceled
: asyncOperation.isDone ? UniTaskStatus.Succeeded
: UniTaskStatus.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 UniTaskStatus Status => status;
public void GetResult()
{
if (status == UniTaskStatus.Succeeded)
{
return;
}
else if (status == UniTaskStatus.Canceled)
{
Error.ThrowOperationCanceledException();
}
Error.ThrowNotYetCompleted();
}
public bool MoveNext()
{
if (cancellationToken.IsCancellationRequested)
{
InvokeContinuation(UniTaskStatus.Canceled);
return false;
}
if (progress != null)
{
progress.Report(asyncOperation.progress);
}
if (asyncOperation.isDone)
{
InvokeContinuation(UniTaskStatus.Succeeded);
return false;
}
return true;
}
void InvokeContinuation(UniTaskStatus 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<UnityEngine.Object>
{
ResourceRequest asyncOperation;
Action<AsyncOperation> continuationAction;
UniTaskStatus status;
UnityEngine.Object result;
public ResourceRequestAwaiter(ResourceRequest asyncOperation)
{
this.status = asyncOperation.isDone ? UniTaskStatus.Succeeded : UniTaskStatus.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 UniTaskStatus Status => status;
public UnityEngine.Object GetResult()
{
if (status == UniTaskStatus.Succeeded) return this.result;
if (status == UniTaskStatus.Pending)
{
// first timing of call
if (asyncOperation.isDone)
{
status = UniTaskStatus.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>();
asyncOperation.completed += continuationAction;
}
}
class ResourceRequestConfiguredAwaiter : IAwaiter<UnityEngine.Object>, IPlayerLoopItem
{
ResourceRequest asyncOperation;
IProgress<float> progress;
CancellationToken cancellationToken;
UniTaskStatus status;
Action continuation;
UnityEngine.Object result;
public ResourceRequestConfiguredAwaiter(ResourceRequest asyncOperation, IProgress<float> progress, CancellationToken cancellationToken)
{
this.status = cancellationToken.IsCancellationRequested ? UniTaskStatus.Canceled
: asyncOperation.isDone ? UniTaskStatus.Succeeded
: UniTaskStatus.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 UniTaskStatus Status => status;
void IAwaiter.GetResult() => GetResult();
public UnityEngine.Object GetResult()
{
if (status == UniTaskStatus.Succeeded) return this.result;
if (status == UniTaskStatus.Canceled)
{
Error.ThrowOperationCanceledException();
}
return Error.ThrowNotYetCompleted<UnityEngine.Object>();
}
public bool MoveNext()
{
if (cancellationToken.IsCancellationRequested)
{
InvokeContinuation(UniTaskStatus.Canceled);
return false;
}
if (progress != null)
{
progress.Report(asyncOperation.progress);
}
if (asyncOperation.isDone)
{
this.result = asyncOperation.asset;
InvokeContinuation(UniTaskStatus.Succeeded);
return false;
}
return true;
}
void InvokeContinuation(UniTaskStatus 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<UnityEngine.Object>, IPlayerLoopItem, IPromisePoolItem
{
static readonly PromisePool<ResourceRequestConfiguredSource> pool = new PromisePool<ResourceRequestConfiguredSource>();
ResourceRequest asyncOperation;
IProgress<float> progress;
CancellationToken cancellationToken;
UniTaskCompletionSourceCore<UnityEngine.Object> core;
ResourceRequestConfiguredSource()
{
}
public static IUniTaskSource<UnityEngine.Object> Create(ResourceRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token)
{
if (cancellationToken.IsCancellationRequested)
{
return AutoResetUniTaskCompletionSource<UnityEngine.Object>.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 UniTaskStatus GetStatus(short token)
{
return core.GetStatus(token);
}
public UniTaskStatus UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
core.OnCompleted(continuation, state, token);
}
public bool MoveNext()
{
if (cancellationToken.IsCancellationRequested)
{
// TODO:Remove Tracking
// TaskTracker.RemoveTracking();
core.TrySetCanceled(cancellationToken);
return false;
}
if (progress != null)
{
progress.Report(asyncOperation.progress);
}
if (asyncOperation.isDone)
{
// TODO:Remove Tracking
// TaskTracker.RemoveTracking();
core.TrySetResult(asyncOperation.asset);
return false;
}
return true;
}
public void Reset()
{
core.Reset();
asyncOperation = default;
progress = default;
cancellationToken = default;
}
}
public struct AssetBundleRequestAwaiter : IAwaiter<UnityEngine.Object>
{
AssetBundleRequest asyncOperation;
Action<AsyncOperation> continuationAction;
UniTaskStatus status;
UnityEngine.Object result;
public AssetBundleRequestAwaiter(AssetBundleRequest asyncOperation)
{
this.status = asyncOperation.isDone ? UniTaskStatus.Succeeded : UniTaskStatus.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 UniTaskStatus Status => status;
public UnityEngine.Object GetResult()
{
if (status == UniTaskStatus.Succeeded) return this.result;
if (status == UniTaskStatus.Pending)
{
// first timing of call
if (asyncOperation.isDone)
{
status = UniTaskStatus.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>();
asyncOperation.completed += continuationAction;
}
}
class AssetBundleRequestConfiguredAwaiter : IAwaiter<UnityEngine.Object>, IPlayerLoopItem
{
AssetBundleRequest asyncOperation;
IProgress<float> progress;
CancellationToken cancellationToken;
UniTaskStatus status;
Action continuation;
UnityEngine.Object result;
public AssetBundleRequestConfiguredAwaiter(AssetBundleRequest asyncOperation, IProgress<float> progress, CancellationToken cancellationToken)
{
this.status = cancellationToken.IsCancellationRequested ? UniTaskStatus.Canceled
: asyncOperation.isDone ? UniTaskStatus.Succeeded
: UniTaskStatus.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 UniTaskStatus Status => status;
void IAwaiter.GetResult() => GetResult();
public UnityEngine.Object GetResult()
{
if (status == UniTaskStatus.Succeeded) return this.result;
if (status == UniTaskStatus.Canceled)
{
Error.ThrowOperationCanceledException();
}
return Error.ThrowNotYetCompleted<UnityEngine.Object>();
}
public bool MoveNext()
{
if (cancellationToken.IsCancellationRequested)
{
InvokeContinuation(UniTaskStatus.Canceled);
return false;
}
if (progress != null)
{
progress.Report(asyncOperation.progress);
}
if (asyncOperation.isDone)
{
this.result = asyncOperation.asset;
InvokeContinuation(UniTaskStatus.Succeeded);
return false;
}
return true;
}
void InvokeContinuation(UniTaskStatus 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<AssetBundle>
{
AssetBundleCreateRequest asyncOperation;
Action<AsyncOperation> continuationAction;
UniTaskStatus status;
AssetBundle result;
public AssetBundleCreateRequestAwaiter(AssetBundleCreateRequest asyncOperation)
{
this.status = asyncOperation.isDone ? UniTaskStatus.Succeeded : UniTaskStatus.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 UniTaskStatus Status => status;
public AssetBundle GetResult()
{
if (status == UniTaskStatus.Succeeded) return this.result;
if (status == UniTaskStatus.Pending)
{
// first timing of call
if (asyncOperation.isDone)
{
status = UniTaskStatus.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>();
asyncOperation.completed += continuationAction;
}
}
class AssetBundleCreateRequestConfiguredAwaiter : IAwaiter<AssetBundle>, IPlayerLoopItem
{
AssetBundleCreateRequest asyncOperation;
IProgress<float> progress;
CancellationToken cancellationToken;
UniTaskStatus status;
Action continuation;
AssetBundle result;
public AssetBundleCreateRequestConfiguredAwaiter(AssetBundleCreateRequest asyncOperation, IProgress<float> progress, CancellationToken cancellationToken)
{
this.status = cancellationToken.IsCancellationRequested ? UniTaskStatus.Canceled
: asyncOperation.isDone ? UniTaskStatus.Succeeded
: UniTaskStatus.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 UniTaskStatus Status => status;
void IAwaiter.GetResult() => GetResult();
public AssetBundle GetResult()
{
if (status == UniTaskStatus.Succeeded) return this.result;
if (status == UniTaskStatus.Canceled)
{
Error.ThrowOperationCanceledException();
}
return Error.ThrowNotYetCompleted<AssetBundle>();
}
public bool MoveNext()
{
if (cancellationToken.IsCancellationRequested)
{
InvokeContinuation(UniTaskStatus.Canceled);
return false;
}
if (progress != null)
{
progress.Report(asyncOperation.progress);
}
if (asyncOperation.isDone)
{
this.result = asyncOperation.assetBundle;
InvokeContinuation(UniTaskStatus.Succeeded);
return false;
}
return true;
}
void InvokeContinuation(UniTaskStatus 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<float> progress;
CancellationToken cancellationToken;
UniTaskStatus status;
Action continuation;
public WWWConfiguredAwaiter(WWW asyncOperation, IProgress<float> progress, CancellationToken cancellationToken)
{
this.status = cancellationToken.IsCancellationRequested ? UniTaskStatus.Canceled
: asyncOperation.isDone ? UniTaskStatus.Succeeded
: UniTaskStatus.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 UniTaskStatus Status => status;
public void GetResult()
{
if (status == UniTaskStatus.Succeeded)
{
return;
}
else if (status == UniTaskStatus.Canceled)
{
Error.ThrowOperationCanceledException();
}
Error.ThrowNotYetCompleted();
}
public bool MoveNext()
{
if (cancellationToken.IsCancellationRequested)
{
InvokeContinuation(UniTaskStatus.Canceled);
return false;
}
if (progress != null)
{
progress.Report(asyncOperation.progress);
}
if (asyncOperation.isDone)
{
InvokeContinuation(UniTaskStatus.Succeeded);
return false;
}
return true;
}
void InvokeContinuation(UniTaskStatus 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<UnityWebRequest>
{
UnityWebRequestAsyncOperation asyncOperation;
Action<AsyncOperation> continuationAction;
UniTaskStatus status;
UnityWebRequest result;
public UnityWebRequestAsyncOperationAwaiter(UnityWebRequestAsyncOperation asyncOperation)
{
this.status = asyncOperation.isDone ? UniTaskStatus.Succeeded : UniTaskStatus.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 UniTaskStatus Status => status;
public UnityWebRequest GetResult()
{
if (status == UniTaskStatus.Succeeded) return this.result;
if (status == UniTaskStatus.Pending)
{
// first timing of call
if (asyncOperation.isDone)
{
status = UniTaskStatus.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>();
asyncOperation.completed += continuationAction;
}
}
class UnityWebRequestAsyncOperationConfiguredAwaiter : IAwaiter<UnityWebRequest>, IPlayerLoopItem
{
UnityWebRequestAsyncOperation asyncOperation;
IProgress<float> progress;
CancellationToken cancellationToken;
UniTaskStatus status;
Action continuation;
UnityWebRequest result;
public UnityWebRequestAsyncOperationConfiguredAwaiter(UnityWebRequestAsyncOperation asyncOperation, IProgress<float> progress, CancellationToken cancellationToken)
{
this.status = cancellationToken.IsCancellationRequested ? UniTaskStatus.Canceled
: asyncOperation.isDone ? UniTaskStatus.Succeeded
: UniTaskStatus.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 UniTaskStatus Status => status;
void IAwaiter.GetResult() => GetResult();
public UnityWebRequest GetResult()
{
if (status == UniTaskStatus.Succeeded) return this.result;
if (status == UniTaskStatus.Canceled)
{
Error.ThrowOperationCanceledException();
}
return Error.ThrowNotYetCompleted<UnityWebRequest>();
}
public bool MoveNext()
{
if (cancellationToken.IsCancellationRequested)
{
InvokeContinuation(UniTaskStatus.Canceled);
return false;
}
if (progress != null)
{
progress.Report(asyncOperation.progress);
}
if (asyncOperation.isDone)
{
this.result = asyncOperation.webRequest;
InvokeContinuation(UniTaskStatus.Succeeded);
return false;
}
return true;
}
void InvokeContinuation(UniTaskStatus 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