using System; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using UnityEngine; namespace Unity.Services.Core.Internal { /// /// Task-based implementation of IAsyncOperation. /// /// awaitable in tasks /// yieldable in coroutines /// class TaskAsyncOperation : AsyncOperationBase, INotifyCompletion { /// /// The scheduler is also used by the because /// can't be used in generic objects. /// internal static TaskScheduler Scheduler; Task m_Task; /// public override bool IsCompleted => m_Task.IsCompleted; /// public override AsyncOperationStatus Status { get { if (m_Task == null) { return AsyncOperationStatus.None; } if (!m_Task.IsCompleted) { return AsyncOperationStatus.InProgress; } if (m_Task.IsCanceled) { return AsyncOperationStatus.Cancelled; } if (m_Task.IsFaulted) { return AsyncOperationStatus.Failed; } return AsyncOperationStatus.Succeeded; } } /// public override Exception Exception => m_Task?.Exception; /// public override void GetResult() {} /// public override AsyncOperationBase GetAwaiter() { return this; } /// /// Creates a new TaskAsyncOperation from a provided Task. /// Returns on Unity's main thread context. /// /// /// The task tracked by this TaskAsyncOperation. /// public TaskAsyncOperation(Task task) { // Tests don't run `RuntimeInitializeOnLoadMethod`s? if (Scheduler == null) { SetScheduler(); } m_Task = task; task.ContinueWith((t, state) => { var self = (TaskAsyncOperation)state; self.DidComplete(); }, this, CancellationToken.None, TaskContinuationOptions.None, Scheduler); } /// /// Creates and starts a task from the provided Action executing on the C# thread pool. /// Returns on Unity's main thread context. /// /// /// The Action to execute asynchronously. /// /// /// A TaskAsyncOperation tracking the execution of the provided Action. /// public static TaskAsyncOperation Run(Action action) { var task = new Task(action); var ret = new TaskAsyncOperation(task); task.Start(); return ret; } [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] internal static void SetScheduler() { Scheduler = TaskScheduler.FromCurrentSynchronizationContext(); } } /// /// Task-based implementation of IAsyncOperation. /// /// awaitable in tasks /// yieldable in coroutines /// /// /// The return type of the operation's result. /// class TaskAsyncOperation : AsyncOperationBase { Task m_Task; /// public override bool IsCompleted => m_Task.IsCompleted; /// public override T Result => m_Task.Result; /// public override T GetResult() { return m_Task.GetAwaiter().GetResult(); } /// public override AsyncOperationBase GetAwaiter() { return this; } /// public override AsyncOperationStatus Status { get { if (m_Task == null) { return AsyncOperationStatus.None; } if (!m_Task.IsCompleted) { return AsyncOperationStatus.InProgress; } if (m_Task.IsCanceled) { return AsyncOperationStatus.Cancelled; } if (m_Task.IsFaulted) { return AsyncOperationStatus.Failed; } return AsyncOperationStatus.Succeeded; } } /// public override Exception Exception => m_Task?.Exception; /// /// Creates a new TaskAsyncOperation from a provided Task. /// Returns on Unity's main thread context. /// /// /// The task tracked by this TaskAsyncOperation. /// public TaskAsyncOperation(Task task) { // Tests don't run `RuntimeInitializeOnLoadMethod`s? if (TaskAsyncOperation.Scheduler == null) { TaskAsyncOperation.SetScheduler(); } m_Task = task; task.ContinueWith((t, state) => { var self = (TaskAsyncOperation)state; self.DidComplete(); }, this, CancellationToken.None, TaskContinuationOptions.None, TaskAsyncOperation.Scheduler); } /// /// Creates and starts a task from the provided Action executing on the C# thread pool. /// Returns on Unity's main thread context. /// /// /// The Action to execute asynchronously. /// /// /// A TaskAsyncOperation tracking the execution of the provided Action. /// public static TaskAsyncOperation Run(Func func) { var task = new Task(func); var ret = new TaskAsyncOperation(task); task.Start(); return ret; } } }