123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- 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; }
- }
- /// <summary>
- /// Encapsulates an <see cref="UnityAsync.IAwaitInstruction"/> with additional information about how the instruction
- /// will be queued and executed. Continuations are intended to be awaited after or shortly after instantiation.
- /// </summary>
- /// <typeparam name="T">The type of <see cref="UnityAsync.IAwaitInstruction"/> to encapsulate.</typeparam>
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- public struct AwaitInstructionAwaiter<T> : IAwaitInstructionAwaiter, INotifyCompletion where T : IAwaitInstruction
- {
- static Exception exception;
-
- Object owner;
- CancellationToken cancellationToken;
- /// <summary>
- /// Evaluate the encapsulated <see cref="UnityAsync.IAwaitInstruction"/>. If the instruction is finished, the
- /// continuation delegate is invoked and the method returns <code>true</code>. 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).
- /// </summary>
- /// <returns>
- /// <code>true</code> if the <see cref="UnityAsync.IAwaitInstruction"/> is finished, its owner destroyed,
- /// or has been cancelled, otherwise <code>false</code>.
- /// </returns>
- [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<T> ConfigureAwait(Object owner)
- {
- this.owner = owner;
- return this;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public AwaitInstructionAwaiter<T> ConfigureAwait(CancellationToken cancellationToken)
- {
- this.cancellationToken = cancellationToken;
- return this;
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public AwaitInstructionAwaiter<T> ConfigureAwait(FrameScheduler scheduler)
- {
- Scheduler = scheduler;
- return this;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public AwaitInstructionAwaiter<T> ConfigureAwait(Object owner, FrameScheduler scheduler)
- {
- this.owner = owner;
- Scheduler = scheduler;
- return this;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public AwaitInstructionAwaiter<T> ConfigureAwait(CancellationToken cancellationToken, FrameScheduler scheduler)
- {
- this.cancellationToken = cancellationToken;
- Scheduler = scheduler;
- return this;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public AwaitInstructionAwaiter<T> ConfigureAwait(Object owner, CancellationToken cancellationToken, FrameScheduler scheduler)
- {
- this.owner = owner;
- this.cancellationToken = cancellationToken;
- Scheduler = scheduler;
- return this;
- }
- }
- }
|