#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member using System; using System.Runtime.CompilerServices; using System.Threading; using UnityEngine; using UniRx.Async.Internal; #if ENABLE_UNITYWEBREQUEST using UnityEngine.Networking; #endif namespace UniRx.Async { public static partial class UnityAsyncExtensions { #region AsyncOperation 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(AsyncOperationConfiguredSource.Create(asyncOperation, PlayerLoopTiming.Update, null, CancellationToken.None, out var token), token); } public static UniTask ConfigureAwait(this AsyncOperation asyncOperation, IProgress progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellation = default(CancellationToken)) { Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation)); return new UniTask(AsyncOperationConfiguredSource.Create(asyncOperation, timing, progress, cancellation, out var token), token); } public struct AsyncOperationAwaiter : ICriticalNotifyCompletion { AsyncOperation asyncOperation; Action continuationAction; public AsyncOperationAwaiter(AsyncOperation asyncOperation) { this.asyncOperation = asyncOperation; this.continuationAction = null; } public bool IsCompleted => asyncOperation.isDone; public void GetResult() { 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(); // allocate delegate. asyncOperation.completed += continuationAction; } } class AsyncOperationConfiguredSource : IUniTaskSource, IPlayerLoopItem, IPromisePoolItem { static readonly PromisePool pool = new PromisePool(); AsyncOperation asyncOperation; IProgress progress; CancellationToken cancellationToken; UniTaskCompletionSourceCore core; AsyncOperationConfiguredSource() { } public static IUniTaskSource Create(AsyncOperation asyncOperation, PlayerLoopTiming timing, IProgress progress, CancellationToken cancellationToken, out short token) { if (cancellationToken.IsCancellationRequested) { return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token); } var result = pool.TryRent() ?? new AsyncOperationConfiguredSource(); result.asyncOperation = asyncOperation; result.progress = progress; result.cancellationToken = cancellationToken; TaskTracker.TrackActiveTask(result, 3); PlayerLoopHelper.AddAction(timing, result); token = result.core.Version; return result; } public void GetResult(short token) { try { TaskTracker.RemoveTracking(this); core.GetResult(token); } finally { pool.TryReturn(this); } } public UniTaskStatus GetStatus(short token) { return core.GetStatus(token); } public UniTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public bool MoveNext() { if (cancellationToken.IsCancellationRequested) { core.TrySetCanceled(cancellationToken); return false; } if (progress != null) { progress.Report(asyncOperation.progress); } if (asyncOperation.isDone) { core.TrySetResult(AsyncUnit.Default); return false; } return true; } public void Reset() { core.Reset(); asyncOperation = default; progress = default; cancellationToken = default; } ~AsyncOperationConfiguredSource() { if (pool.TryReturn(this)) { GC.ReRegisterForFinalize(this); } } } # endregion #region ResourceRequest public static ResourceRequestAwaiter GetAwaiter(this ResourceRequest asyncOperation) { Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation)); return new ResourceRequestAwaiter(asyncOperation); } public static UniTask ToUniTask(this ResourceRequest asyncOperation) { Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation)); return new UniTask(ResourceRequestConfiguredSource.Create(asyncOperation, PlayerLoopTiming.Update, null, CancellationToken.None, out var token), token); } public static UniTask ConfigureAwait(this ResourceRequest asyncOperation, IProgress progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellation = default(CancellationToken)) { Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation)); return new UniTask(ResourceRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellation, out var token), token); } public struct ResourceRequestAwaiter : ICriticalNotifyCompletion { ResourceRequest asyncOperation; Action continuationAction; UnityEngine.Object result; public ResourceRequestAwaiter(ResourceRequest asyncOperation) { this.asyncOperation = asyncOperation; this.continuationAction = null; this.result = default; } public bool IsCompleted => asyncOperation.isDone; public UnityEngine.Object GetResult() { if (continuationAction != null) { asyncOperation.completed -= continuationAction; asyncOperation = null; // remove reference. continuationAction = null; } else { asyncOperation = null; // remove reference. } return this.result; } public void OnCompleted(Action continuation) { UnsafeOnCompleted(continuation); } public void UnsafeOnCompleted(Action continuation) { Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction); continuationAction = continuation.AsFuncOfT(); // allocate delegate. asyncOperation.completed += continuationAction; } } 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; TaskTracker.TrackActiveTask(result, 3); PlayerLoopHelper.AddAction(timing, result); token = result.core.Version; return result; } public UnityEngine.Object GetResult(short token) { try { TaskTracker.RemoveTracking(this); 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 continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public bool MoveNext() { if (cancellationToken.IsCancellationRequested) { core.TrySetCanceled(cancellationToken); return false; } if (progress != null) { progress.Report(asyncOperation.progress); } if (asyncOperation.isDone) { core.TrySetResult(asyncOperation.asset); return false; } return true; } public void Reset() { core.Reset(); asyncOperation = default; progress = default; cancellationToken = default; } ~ResourceRequestConfiguredSource() { if (pool.TryReturn(this)) { GC.ReRegisterForFinalize(this); } } } # endregion #region AssetBundleRequest public static AssetBundleRequestAwaiter GetAwaiter(this AssetBundleRequest asyncOperation) { Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation)); return new AssetBundleRequestAwaiter(asyncOperation); } public static UniTask ToUniTask(this AssetBundleRequest asyncOperation) { Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation)); return new UniTask(AssetBundleRequestConfiguredSource.Create(asyncOperation, PlayerLoopTiming.Update, null, CancellationToken.None, out var token), token); } public static UniTask ConfigureAwait(this AssetBundleRequest asyncOperation, IProgress progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellation = default(CancellationToken)) { Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation)); return new UniTask(AssetBundleRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellation, out var token), token); } public struct AssetBundleRequestAwaiter : ICriticalNotifyCompletion { AssetBundleRequest asyncOperation; Action continuationAction; UnityEngine.Object result; public AssetBundleRequestAwaiter(AssetBundleRequest asyncOperation) { this.asyncOperation = asyncOperation; this.continuationAction = null; this.result = default; } public bool IsCompleted => asyncOperation.isDone; public UnityEngine.Object GetResult() { if (continuationAction != null) { asyncOperation.completed -= continuationAction; asyncOperation = null; // remove reference. continuationAction = null; } else { asyncOperation = null; // remove reference. } return this.result; } public void OnCompleted(Action continuation) { UnsafeOnCompleted(continuation); } public void UnsafeOnCompleted(Action continuation) { Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction); continuationAction = continuation.AsFuncOfT(); // allocate delegate. asyncOperation.completed += continuationAction; } } class AssetBundleRequestConfiguredSource : IUniTaskSource, IPlayerLoopItem, IPromisePoolItem { static readonly PromisePool pool = new PromisePool(); AssetBundleRequest asyncOperation; IProgress progress; CancellationToken cancellationToken; UniTaskCompletionSourceCore core; AssetBundleRequestConfiguredSource() { } public static IUniTaskSource Create(AssetBundleRequest asyncOperation, PlayerLoopTiming timing, IProgress progress, CancellationToken cancellationToken, out short token) { if (cancellationToken.IsCancellationRequested) { return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token); } var result = pool.TryRent() ?? new AssetBundleRequestConfiguredSource(); result.asyncOperation = asyncOperation; result.progress = progress; result.cancellationToken = cancellationToken; TaskTracker.TrackActiveTask(result, 3); PlayerLoopHelper.AddAction(timing, result); token = result.core.Version; return result; } public UnityEngine.Object GetResult(short token) { try { TaskTracker.RemoveTracking(this); 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 continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public bool MoveNext() { if (cancellationToken.IsCancellationRequested) { core.TrySetCanceled(cancellationToken); return false; } if (progress != null) { progress.Report(asyncOperation.progress); } if (asyncOperation.isDone) { core.TrySetResult(asyncOperation.asset); return false; } return true; } public void Reset() { core.Reset(); asyncOperation = default; progress = default; cancellationToken = default; } ~AssetBundleRequestConfiguredSource() { if (pool.TryReturn(this)) { GC.ReRegisterForFinalize(this); } } } # endregion #region AssetBundleCreateRequest public static AssetBundleCreateRequestAwaiter GetAwaiter(this AssetBundleCreateRequest asyncOperation) { Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation)); return new AssetBundleCreateRequestAwaiter(asyncOperation); } public static UniTask ToUniTask(this AssetBundleCreateRequest asyncOperation) { Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation)); return new UniTask(AssetBundleCreateRequestConfiguredSource.Create(asyncOperation, PlayerLoopTiming.Update, null, CancellationToken.None, out var token), token); } public static UniTask ConfigureAwait(this AssetBundleCreateRequest asyncOperation, IProgress progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellation = default(CancellationToken)) { Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation)); return new UniTask(AssetBundleCreateRequestConfiguredSource.Create(asyncOperation, timing, progress, cancellation, out var token), token); } public struct AssetBundleCreateRequestAwaiter : ICriticalNotifyCompletion { AssetBundleCreateRequest asyncOperation; Action continuationAction; AssetBundle result; public AssetBundleCreateRequestAwaiter(AssetBundleCreateRequest asyncOperation) { this.asyncOperation = asyncOperation; this.continuationAction = null; this.result = default; } public bool IsCompleted => asyncOperation.isDone; public AssetBundle GetResult() { if (continuationAction != null) { asyncOperation.completed -= continuationAction; asyncOperation = null; // remove reference. continuationAction = null; } else { asyncOperation = null; // remove reference. } return this.result; } public void OnCompleted(Action continuation) { UnsafeOnCompleted(continuation); } public void UnsafeOnCompleted(Action continuation) { Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction); continuationAction = continuation.AsFuncOfT(); // allocate delegate. asyncOperation.completed += continuationAction; } } class AssetBundleCreateRequestConfiguredSource : IUniTaskSource, IPlayerLoopItem, IPromisePoolItem { static readonly PromisePool pool = new PromisePool(); AssetBundleCreateRequest asyncOperation; IProgress progress; CancellationToken cancellationToken; UniTaskCompletionSourceCore core; AssetBundleCreateRequestConfiguredSource() { } public static IUniTaskSource Create(AssetBundleCreateRequest asyncOperation, PlayerLoopTiming timing, IProgress progress, CancellationToken cancellationToken, out short token) { if (cancellationToken.IsCancellationRequested) { return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token); } var result = pool.TryRent() ?? new AssetBundleCreateRequestConfiguredSource(); result.asyncOperation = asyncOperation; result.progress = progress; result.cancellationToken = cancellationToken; TaskTracker.TrackActiveTask(result, 3); PlayerLoopHelper.AddAction(timing, result); token = result.core.Version; return result; } public AssetBundle GetResult(short token) { try { TaskTracker.RemoveTracking(this); 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 continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public bool MoveNext() { if (cancellationToken.IsCancellationRequested) { core.TrySetCanceled(cancellationToken); return false; } if (progress != null) { progress.Report(asyncOperation.progress); } if (asyncOperation.isDone) { core.TrySetResult(asyncOperation.assetBundle); return false; } return true; } public void Reset() { core.Reset(); asyncOperation = default; progress = default; cancellationToken = default; } ~AssetBundleCreateRequestConfiguredSource() { if (pool.TryReturn(this)) { GC.ReRegisterForFinalize(this); } } } # endregion #if ENABLE_UNITYWEBREQUEST #region UnityWebRequestAsyncOperation 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(UnityWebRequestAsyncOperationConfiguredSource.Create(asyncOperation, PlayerLoopTiming.Update, null, CancellationToken.None, out var token), token); } public static UniTask ConfigureAwait(this UnityWebRequestAsyncOperation asyncOperation, IProgress progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellation = default(CancellationToken)) { Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation)); return new UniTask(UnityWebRequestAsyncOperationConfiguredSource.Create(asyncOperation, timing, progress, cancellation, out var token), token); } public struct UnityWebRequestAsyncOperationAwaiter : ICriticalNotifyCompletion { UnityWebRequestAsyncOperation asyncOperation; Action continuationAction; UnityWebRequest result; public UnityWebRequestAsyncOperationAwaiter(UnityWebRequestAsyncOperation asyncOperation) { this.asyncOperation = asyncOperation; this.continuationAction = null; this.result = default; } public bool IsCompleted => asyncOperation.isDone; public UnityWebRequest GetResult() { if (continuationAction != null) { asyncOperation.completed -= continuationAction; asyncOperation = null; // remove reference. continuationAction = null; } else { asyncOperation = null; // remove reference. } return this.result; } public void OnCompleted(Action continuation) { UnsafeOnCompleted(continuation); } public void UnsafeOnCompleted(Action continuation) { Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction); continuationAction = continuation.AsFuncOfT(); // allocate delegate. asyncOperation.completed += continuationAction; } } class UnityWebRequestAsyncOperationConfiguredSource : IUniTaskSource, IPlayerLoopItem, IPromisePoolItem { static readonly PromisePool pool = new PromisePool(); UnityWebRequestAsyncOperation asyncOperation; IProgress progress; CancellationToken cancellationToken; UniTaskCompletionSourceCore core; UnityWebRequestAsyncOperationConfiguredSource() { } public static IUniTaskSource Create(UnityWebRequestAsyncOperation asyncOperation, PlayerLoopTiming timing, IProgress progress, CancellationToken cancellationToken, out short token) { if (cancellationToken.IsCancellationRequested) { return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token); } var result = pool.TryRent() ?? new UnityWebRequestAsyncOperationConfiguredSource(); result.asyncOperation = asyncOperation; result.progress = progress; result.cancellationToken = cancellationToken; TaskTracker.TrackActiveTask(result, 3); PlayerLoopHelper.AddAction(timing, result); token = result.core.Version; return result; } public UnityWebRequest GetResult(short token) { try { TaskTracker.RemoveTracking(this); 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 continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public bool MoveNext() { if (cancellationToken.IsCancellationRequested) { core.TrySetCanceled(cancellationToken); return false; } if (progress != null) { progress.Report(asyncOperation.progress); } if (asyncOperation.isDone) { core.TrySetResult(asyncOperation.webRequest); return false; } return true; } public void Reset() { core.Reset(); asyncOperation = default; progress = default; cancellationToken = default; } ~UnityWebRequestAsyncOperationConfiguredSource() { if (pool.TryReturn(this)) { GC.ReRegisterForFinalize(this); } } } # endregion #endif } }