using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using Object = UnityEngine.Object;
namespace UnityAsync
{
public interface IAwaitInstructionAwaiter
{
bool Evaluate();
FrameScheduler Scheduler { get; }
}
///
/// Encapsulates an with additional information about how the instruction
/// will be queued and executed. Continuations are intended to be awaited after or shortly after instantiation.
///
/// The type of to encapsulate.
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct AwaitInstructionAwaiter : IAwaitInstructionAwaiter, INotifyCompletion where T : IAwaitInstruction
{
static Exception exception;
Object owner;
CancellationToken cancellationToken;
///
/// Evaluate the encapsulated . If the instruction is finished, the
/// continuation delegate is invoked and the method returns true
. If the owner is destroyed, the
/// method will return true without invoking the continuation delegate. If it was cancelled, an exception is
/// is thrown when the continuation delegate is invoked. Otherwise, returns false (i.e. the instruction is not
/// finished).
///
///
/// true
if the is finished, its owner destroyed,
/// or has been cancelled, otherwise false
.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Evaluate()
{
try
{
// if cancelled, throw exception
cancellationToken.ThrowIfCancellationRequested();
// if owner is destroyed, behaves like a UnityEngine.Coroutine, ie:
// "With this object's death, the thread of prophecy is severed. Restore a saved game to restore the
// weave of fate, or persist in the doomed world you have created."
if(!owner)
return true;
// if not completed, return false to put it back into a queue for next frame
if(!instruction.IsCompleted())
return false;
}
catch(Exception e)
{
// store exception in static field
exception = e;
// exception is rethrown in GetResult, at start of continuation
continuation();
return true;
}
// if we get here, it completed without exceptions and we can call continuation and be done with it
continuation();
return true;
}
public FrameScheduler Scheduler { get; private set; }
T instruction;
Action continuation;
public AwaitInstructionAwaiter(in T inst)
{
instruction = inst;
continuation = null;
owner = AsyncManager.Instance;
exception = null;
Scheduler = FrameScheduler.Update;
}
public AwaitInstructionAwaiter(in T inst, FrameScheduler scheduler)
{
instruction = inst;
continuation = null;
owner = AsyncManager.Instance;
exception = null;
Scheduler = scheduler;
}
public AwaitInstructionAwaiter(in T inst, CancellationToken cancellationToken, FrameScheduler scheduler)
{
instruction = inst;
continuation = null;
owner = AsyncManager.Instance;
exception = null;
this.cancellationToken = cancellationToken;
Scheduler = scheduler;
}
public AwaitInstructionAwaiter(in T inst, Object owner, FrameScheduler scheduler)
{
instruction = inst;
continuation = null;
this.owner = owner;
exception = null;
Scheduler = scheduler;
}
public bool IsCompleted => false;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void OnCompleted(Action continuation)
{
this.continuation = continuation;
AsyncManager.AddContinuation(this);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void GetResult()
{
if(exception != null)
{
var e = exception;
exception = null;
throw e;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public AwaitInstructionAwaiter ConfigureAwait(Object owner)
{
this.owner = owner;
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public AwaitInstructionAwaiter ConfigureAwait(CancellationToken cancellationToken)
{
this.cancellationToken = cancellationToken;
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public AwaitInstructionAwaiter ConfigureAwait(FrameScheduler scheduler)
{
Scheduler = scheduler;
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public AwaitInstructionAwaiter ConfigureAwait(Object owner, FrameScheduler scheduler)
{
this.owner = owner;
Scheduler = scheduler;
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public AwaitInstructionAwaiter ConfigureAwait(CancellationToken cancellationToken, FrameScheduler scheduler)
{
this.cancellationToken = cancellationToken;
Scheduler = scheduler;
return this;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public AwaitInstructionAwaiter ConfigureAwait(Object owner, CancellationToken cancellationToken, FrameScheduler scheduler)
{
this.owner = owner;
this.cancellationToken = cancellationToken;
Scheduler = scheduler;
return this;
}
}
}