AwaitInstructionAwaiter.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. using System;
  2. using System.Runtime.CompilerServices;
  3. using System.Runtime.InteropServices;
  4. using System.Threading;
  5. using Object = UnityEngine.Object;
  6. namespace UnityAsync
  7. {
  8. public interface IAwaitInstructionAwaiter
  9. {
  10. bool Evaluate();
  11. FrameScheduler Scheduler { get; }
  12. }
  13. /// <summary>
  14. /// Encapsulates an <see cref="UnityAsync.IAwaitInstruction"/> with additional information about how the instruction
  15. /// will be queued and executed. Continuations are intended to be awaited after or shortly after instantiation.
  16. /// </summary>
  17. /// <typeparam name="T">The type of <see cref="UnityAsync.IAwaitInstruction"/> to encapsulate.</typeparam>
  18. [StructLayout(LayoutKind.Sequential, Pack = 1)]
  19. public struct AwaitInstructionAwaiter<T> : IAwaitInstructionAwaiter, INotifyCompletion where T : IAwaitInstruction
  20. {
  21. static Exception exception;
  22. Object owner;
  23. CancellationToken cancellationToken;
  24. /// <summary>
  25. /// Evaluate the encapsulated <see cref="UnityAsync.IAwaitInstruction"/>. If the instruction is finished, the
  26. /// continuation delegate is invoked and the method returns <code>true</code>. If the owner is destroyed, the
  27. /// method will return true without invoking the continuation delegate. If it was cancelled, an exception is
  28. /// is thrown when the continuation delegate is invoked. Otherwise, returns false (i.e. the instruction is not
  29. /// finished).
  30. /// </summary>
  31. /// <returns>
  32. /// <code>true</code> if the <see cref="UnityAsync.IAwaitInstruction"/> is finished, its owner destroyed,
  33. /// or has been cancelled, otherwise <code>false</code>.
  34. /// </returns>
  35. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  36. public bool Evaluate()
  37. {
  38. try
  39. {
  40. // if cancelled, throw exception
  41. cancellationToken.ThrowIfCancellationRequested();
  42. // if owner is destroyed, behaves like a UnityEngine.Coroutine, ie:
  43. // "With this object's death, the thread of prophecy is severed. Restore a saved game to restore the
  44. // weave of fate, or persist in the doomed world you have created."
  45. if(!owner)
  46. return true;
  47. // if not completed, return false to put it back into a queue for next frame
  48. if(!instruction.IsCompleted())
  49. return false;
  50. }
  51. catch(Exception e)
  52. {
  53. // store exception in static field
  54. exception = e;
  55. // exception is rethrown in GetResult, at start of continuation
  56. continuation();
  57. return true;
  58. }
  59. // if we get here, it completed without exceptions and we can call continuation and be done with it
  60. continuation();
  61. return true;
  62. }
  63. public FrameScheduler Scheduler { get; private set; }
  64. T instruction;
  65. Action continuation;
  66. public AwaitInstructionAwaiter(in T inst)
  67. {
  68. instruction = inst;
  69. continuation = null;
  70. owner = AsyncManager.Instance;
  71. exception = null;
  72. Scheduler = FrameScheduler.Update;
  73. }
  74. public AwaitInstructionAwaiter(in T inst, FrameScheduler scheduler)
  75. {
  76. instruction = inst;
  77. continuation = null;
  78. owner = AsyncManager.Instance;
  79. exception = null;
  80. Scheduler = scheduler;
  81. }
  82. public AwaitInstructionAwaiter(in T inst, CancellationToken cancellationToken, FrameScheduler scheduler)
  83. {
  84. instruction = inst;
  85. continuation = null;
  86. owner = AsyncManager.Instance;
  87. exception = null;
  88. this.cancellationToken = cancellationToken;
  89. Scheduler = scheduler;
  90. }
  91. public AwaitInstructionAwaiter(in T inst, Object owner, FrameScheduler scheduler)
  92. {
  93. instruction = inst;
  94. continuation = null;
  95. this.owner = owner;
  96. exception = null;
  97. Scheduler = scheduler;
  98. }
  99. public bool IsCompleted => false;
  100. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  101. public void OnCompleted(Action continuation)
  102. {
  103. this.continuation = continuation;
  104. AsyncManager.AddContinuation(this);
  105. }
  106. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  107. public void GetResult()
  108. {
  109. if(exception != null)
  110. {
  111. var e = exception;
  112. exception = null;
  113. throw e;
  114. }
  115. }
  116. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  117. public AwaitInstructionAwaiter<T> ConfigureAwait(Object owner)
  118. {
  119. this.owner = owner;
  120. return this;
  121. }
  122. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  123. public AwaitInstructionAwaiter<T> ConfigureAwait(CancellationToken cancellationToken)
  124. {
  125. this.cancellationToken = cancellationToken;
  126. return this;
  127. }
  128. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  129. public AwaitInstructionAwaiter<T> ConfigureAwait(FrameScheduler scheduler)
  130. {
  131. Scheduler = scheduler;
  132. return this;
  133. }
  134. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  135. public AwaitInstructionAwaiter<T> ConfigureAwait(Object owner, FrameScheduler scheduler)
  136. {
  137. this.owner = owner;
  138. Scheduler = scheduler;
  139. return this;
  140. }
  141. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  142. public AwaitInstructionAwaiter<T> ConfigureAwait(CancellationToken cancellationToken, FrameScheduler scheduler)
  143. {
  144. this.cancellationToken = cancellationToken;
  145. Scheduler = scheduler;
  146. return this;
  147. }
  148. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  149. public AwaitInstructionAwaiter<T> ConfigureAwait(Object owner, CancellationToken cancellationToken, FrameScheduler scheduler)
  150. {
  151. this.owner = owner;
  152. this.cancellationToken = cancellationToken;
  153. Scheduler = scheduler;
  154. return this;
  155. }
  156. }
  157. }