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;
}
}
}