You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
381 lines
10 KiB
C#
381 lines
10 KiB
C#
#pragma warning disable CS1591
|
|
|
|
using Cysharp.Threading.Tasks.Internal;
|
|
using System;
|
|
using System.Linq;
|
|
using System.Diagnostics;
|
|
using System.Runtime.CompilerServices;
|
|
|
|
namespace Cysharp.Threading.Tasks.CompilerServices
|
|
{
|
|
// #ENABLE_IL2CPP in this file is to avoid bug of IL2CPP VM.
|
|
// Issue is tracked on https://issuetracker.unity3d.com/issues/il2cpp-incorrect-results-when-calling-a-method-from-outside-class-in-a-struct
|
|
// but currently it is labeled `Won't Fix`.
|
|
|
|
internal interface IStateMachineRunner
|
|
{
|
|
Action MoveNext { get; }
|
|
void Return();
|
|
|
|
#if ENABLE_IL2CPP
|
|
Action ReturnAction { get; }
|
|
#endif
|
|
}
|
|
|
|
internal interface IStateMachineRunnerPromise : IUniTaskSource
|
|
{
|
|
Action MoveNext { get; }
|
|
UniTask Task { get; }
|
|
void SetResult();
|
|
void SetException(Exception exception);
|
|
}
|
|
|
|
internal interface IStateMachineRunnerPromise<T> : IUniTaskSource<T>
|
|
{
|
|
Action MoveNext { get; }
|
|
UniTask<T> Task { get; }
|
|
void SetResult(T result);
|
|
void SetException(Exception exception);
|
|
}
|
|
|
|
internal static class StateMachineUtility
|
|
{
|
|
// Get AsyncStateMachine internal state to check IL2CPP bug
|
|
public static int GetState(IAsyncStateMachine stateMachine)
|
|
{
|
|
var info = stateMachine.GetType().GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
|
|
.First(x => x.Name.EndsWith("__state"));
|
|
return (int)info.GetValue(stateMachine);
|
|
}
|
|
}
|
|
|
|
internal sealed class AsyncUniTaskVoid<TStateMachine> : IStateMachineRunner, ITaskPoolNode<AsyncUniTaskVoid<TStateMachine>>, IUniTaskSource
|
|
where TStateMachine : IAsyncStateMachine
|
|
{
|
|
static TaskPool<AsyncUniTaskVoid<TStateMachine>> pool;
|
|
|
|
#if ENABLE_IL2CPP
|
|
public Action ReturnAction { get; }
|
|
#endif
|
|
|
|
TStateMachine stateMachine;
|
|
|
|
public Action MoveNext { get; }
|
|
|
|
public AsyncUniTaskVoid()
|
|
{
|
|
MoveNext = Run;
|
|
#if ENABLE_IL2CPP
|
|
ReturnAction = Return;
|
|
#endif
|
|
}
|
|
|
|
public static void SetStateMachine(ref TStateMachine stateMachine, ref IStateMachineRunner runnerFieldRef)
|
|
{
|
|
if (!pool.TryPop(out var result))
|
|
{
|
|
result = new AsyncUniTaskVoid<TStateMachine>();
|
|
}
|
|
TaskTracker.TrackActiveTask(result, 3);
|
|
|
|
runnerFieldRef = result; // set runner before copied.
|
|
result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
|
|
}
|
|
|
|
static AsyncUniTaskVoid()
|
|
{
|
|
TaskPool.RegisterSizeGetter(typeof(AsyncUniTaskVoid<TStateMachine>), () => pool.Size);
|
|
}
|
|
|
|
AsyncUniTaskVoid<TStateMachine> nextNode;
|
|
public ref AsyncUniTaskVoid<TStateMachine> NextNode => ref nextNode;
|
|
|
|
public void Return()
|
|
{
|
|
TaskTracker.RemoveTracking(this);
|
|
stateMachine = default;
|
|
pool.TryPush(this);
|
|
}
|
|
|
|
[DebuggerHidden]
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
void Run()
|
|
{
|
|
stateMachine.MoveNext();
|
|
}
|
|
|
|
// dummy interface implementation for TaskTracker.
|
|
|
|
UniTaskStatus IUniTaskSource.GetStatus(short token)
|
|
{
|
|
return UniTaskStatus.Pending;
|
|
}
|
|
|
|
UniTaskStatus IUniTaskSource.UnsafeGetStatus()
|
|
{
|
|
return UniTaskStatus.Pending;
|
|
}
|
|
|
|
void IUniTaskSource.OnCompleted(Action<object> continuation, object state, short token)
|
|
{
|
|
}
|
|
|
|
void IUniTaskSource.GetResult(short token)
|
|
{
|
|
}
|
|
}
|
|
|
|
internal sealed class AsyncUniTask<TStateMachine> : IStateMachineRunnerPromise, IUniTaskSource, ITaskPoolNode<AsyncUniTask<TStateMachine>>
|
|
where TStateMachine : IAsyncStateMachine
|
|
{
|
|
static TaskPool<AsyncUniTask<TStateMachine>> pool;
|
|
|
|
#if ENABLE_IL2CPP
|
|
readonly Action returnDelegate;
|
|
#endif
|
|
public Action MoveNext { get; }
|
|
|
|
TStateMachine stateMachine;
|
|
UniTaskCompletionSourceCore<AsyncUnit> core;
|
|
|
|
AsyncUniTask()
|
|
{
|
|
MoveNext = Run;
|
|
#if ENABLE_IL2CPP
|
|
returnDelegate = Return;
|
|
#endif
|
|
}
|
|
|
|
public static void SetStateMachine(ref TStateMachine stateMachine, ref IStateMachineRunnerPromise runnerPromiseFieldRef)
|
|
{
|
|
if (!pool.TryPop(out var result))
|
|
{
|
|
result = new AsyncUniTask<TStateMachine>();
|
|
}
|
|
TaskTracker.TrackActiveTask(result, 3);
|
|
|
|
runnerPromiseFieldRef = result; // set runner before copied.
|
|
result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
|
|
}
|
|
|
|
AsyncUniTask<TStateMachine> nextNode;
|
|
public ref AsyncUniTask<TStateMachine> NextNode => ref nextNode;
|
|
|
|
static AsyncUniTask()
|
|
{
|
|
TaskPool.RegisterSizeGetter(typeof(AsyncUniTask<TStateMachine>), () => pool.Size);
|
|
}
|
|
|
|
void Return()
|
|
{
|
|
TaskTracker.RemoveTracking(this);
|
|
core.Reset();
|
|
stateMachine = default;
|
|
pool.TryPush(this);
|
|
}
|
|
|
|
bool TryReturn()
|
|
{
|
|
TaskTracker.RemoveTracking(this);
|
|
core.Reset();
|
|
stateMachine = default;
|
|
return pool.TryPush(this);
|
|
}
|
|
|
|
[DebuggerHidden]
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
void Run()
|
|
{
|
|
stateMachine.MoveNext();
|
|
}
|
|
|
|
public UniTask Task
|
|
{
|
|
[DebuggerHidden]
|
|
get
|
|
{
|
|
return new UniTask(this, core.Version);
|
|
}
|
|
}
|
|
|
|
[DebuggerHidden]
|
|
public void SetResult()
|
|
{
|
|
core.TrySetResult(AsyncUnit.Default);
|
|
}
|
|
|
|
[DebuggerHidden]
|
|
public void SetException(Exception exception)
|
|
{
|
|
core.TrySetException(exception);
|
|
}
|
|
|
|
[DebuggerHidden]
|
|
public void GetResult(short token)
|
|
{
|
|
try
|
|
{
|
|
core.GetResult(token);
|
|
}
|
|
finally
|
|
{
|
|
#if ENABLE_IL2CPP
|
|
// workaround for IL2CPP bug.
|
|
PlayerLoopHelper.AddContinuation(PlayerLoopTiming.LastPostLateUpdate, returnDelegate);
|
|
#else
|
|
TryReturn();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
[DebuggerHidden]
|
|
public UniTaskStatus GetStatus(short token)
|
|
{
|
|
return core.GetStatus(token);
|
|
}
|
|
|
|
[DebuggerHidden]
|
|
public UniTaskStatus UnsafeGetStatus()
|
|
{
|
|
return core.UnsafeGetStatus();
|
|
}
|
|
|
|
[DebuggerHidden]
|
|
public void OnCompleted(Action<object> continuation, object state, short token)
|
|
{
|
|
core.OnCompleted(continuation, state, token);
|
|
}
|
|
}
|
|
|
|
internal sealed class AsyncUniTask<TStateMachine, T> : IStateMachineRunnerPromise<T>, IUniTaskSource<T>, ITaskPoolNode<AsyncUniTask<TStateMachine, T>>
|
|
where TStateMachine : IAsyncStateMachine
|
|
{
|
|
static TaskPool<AsyncUniTask<TStateMachine, T>> pool;
|
|
|
|
#if ENABLE_IL2CPP
|
|
readonly Action returnDelegate;
|
|
#endif
|
|
|
|
public Action MoveNext { get; }
|
|
|
|
TStateMachine stateMachine;
|
|
UniTaskCompletionSourceCore<T> core;
|
|
|
|
AsyncUniTask()
|
|
{
|
|
MoveNext = Run;
|
|
#if ENABLE_IL2CPP
|
|
returnDelegate = Return;
|
|
#endif
|
|
}
|
|
|
|
public static void SetStateMachine(ref TStateMachine stateMachine, ref IStateMachineRunnerPromise<T> runnerPromiseFieldRef)
|
|
{
|
|
if (!pool.TryPop(out var result))
|
|
{
|
|
result = new AsyncUniTask<TStateMachine, T>();
|
|
}
|
|
TaskTracker.TrackActiveTask(result, 3);
|
|
|
|
runnerPromiseFieldRef = result; // set runner before copied.
|
|
result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
|
|
}
|
|
|
|
AsyncUniTask<TStateMachine, T> nextNode;
|
|
public ref AsyncUniTask<TStateMachine, T> NextNode => ref nextNode;
|
|
|
|
static AsyncUniTask()
|
|
{
|
|
TaskPool.RegisterSizeGetter(typeof(AsyncUniTask<TStateMachine, T>), () => pool.Size);
|
|
}
|
|
|
|
void Return()
|
|
{
|
|
TaskTracker.RemoveTracking(this);
|
|
core.Reset();
|
|
stateMachine = default;
|
|
pool.TryPush(this);
|
|
}
|
|
|
|
bool TryReturn()
|
|
{
|
|
TaskTracker.RemoveTracking(this);
|
|
core.Reset();
|
|
stateMachine = default;
|
|
return pool.TryPush(this);
|
|
}
|
|
|
|
[DebuggerHidden]
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
void Run()
|
|
{
|
|
// UnityEngine.Debug.Log($"MoveNext State:" + StateMachineUtility.GetState(stateMachine));
|
|
stateMachine.MoveNext();
|
|
}
|
|
|
|
public UniTask<T> Task
|
|
{
|
|
[DebuggerHidden]
|
|
get
|
|
{
|
|
return new UniTask<T>(this, core.Version);
|
|
}
|
|
}
|
|
|
|
[DebuggerHidden]
|
|
public void SetResult(T result)
|
|
{
|
|
core.TrySetResult(result);
|
|
}
|
|
|
|
[DebuggerHidden]
|
|
public void SetException(Exception exception)
|
|
{
|
|
core.TrySetException(exception);
|
|
}
|
|
|
|
[DebuggerHidden]
|
|
public T GetResult(short token)
|
|
{
|
|
try
|
|
{
|
|
return core.GetResult(token);
|
|
}
|
|
finally
|
|
{
|
|
#if ENABLE_IL2CPP
|
|
// workaround for IL2CPP bug.
|
|
PlayerLoopHelper.AddContinuation(PlayerLoopTiming.LastPostLateUpdate, returnDelegate);
|
|
#else
|
|
TryReturn();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
[DebuggerHidden]
|
|
void IUniTaskSource.GetResult(short token)
|
|
{
|
|
GetResult(token);
|
|
}
|
|
|
|
[DebuggerHidden]
|
|
public UniTaskStatus GetStatus(short token)
|
|
{
|
|
return core.GetStatus(token);
|
|
}
|
|
|
|
[DebuggerHidden]
|
|
public UniTaskStatus UnsafeGetStatus()
|
|
{
|
|
return core.UnsafeGetStatus();
|
|
}
|
|
|
|
[DebuggerHidden]
|
|
public void OnCompleted(Action<object> continuation, object state, short token)
|
|
{
|
|
core.OnCompleted(continuation, state, token);
|
|
}
|
|
}
|
|
}
|
|
|