ETTaskCompletionSource.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. using System;
  2. using System.Diagnostics;
  3. using System.Runtime.CompilerServices;
  4. using System.Runtime.ExceptionServices;
  5. namespace ET
  6. {
  7. public class ETTaskCompletionSource: ICriticalNotifyCompletion
  8. {
  9. private AwaiterStatus state;
  10. private ExceptionDispatchInfo exception;
  11. private Action continuation; // action or list
  12. [DebuggerHidden]
  13. public ETTask Task => new ETTask(this);
  14. [DebuggerHidden]
  15. public AwaiterStatus Status => state;
  16. [DebuggerHidden]
  17. public bool IsCompleted => state != AwaiterStatus.Pending;
  18. [DebuggerHidden]
  19. public void UnsafeOnCompleted(Action action)
  20. {
  21. this.continuation = action;
  22. if (state != AwaiterStatus.Pending)
  23. {
  24. TryInvokeContinuation();
  25. }
  26. }
  27. [DebuggerHidden]
  28. public void OnCompleted(Action action)
  29. {
  30. this.UnsafeOnCompleted(action);
  31. }
  32. [DebuggerHidden]
  33. public void GetResult()
  34. {
  35. switch (this.state)
  36. {
  37. case AwaiterStatus.Succeeded:
  38. return;
  39. case AwaiterStatus.Faulted:
  40. this.exception?.Throw();
  41. this.exception = null;
  42. return;
  43. default:
  44. throw new NotSupportedException("ETTask does not allow call GetResult directly when task not completed. Please use 'await'.");
  45. }
  46. }
  47. [DebuggerHidden]
  48. public void SetResult()
  49. {
  50. if (this.TrySetResult())
  51. {
  52. return;
  53. }
  54. throw new InvalidOperationException("TaskT_TransitionToFinal_AlreadyCompleted");
  55. }
  56. [DebuggerHidden]
  57. public void SetException(Exception e)
  58. {
  59. if (this.TrySetException(e))
  60. {
  61. return;
  62. }
  63. throw new InvalidOperationException("TaskT_TransitionToFinal_AlreadyCompleted");
  64. }
  65. [DebuggerHidden]
  66. private void TryInvokeContinuation()
  67. {
  68. this.continuation?.Invoke();
  69. this.continuation = null;
  70. }
  71. [DebuggerHidden]
  72. private bool TrySetResult()
  73. {
  74. if (this.state != AwaiterStatus.Pending)
  75. {
  76. return false;
  77. }
  78. this.state = AwaiterStatus.Succeeded;
  79. this.TryInvokeContinuation();
  80. return true;
  81. }
  82. [DebuggerHidden]
  83. private bool TrySetException(Exception e)
  84. {
  85. if (this.state != AwaiterStatus.Pending)
  86. {
  87. return false;
  88. }
  89. this.state = AwaiterStatus.Faulted;
  90. this.exception = ExceptionDispatchInfo.Capture(e);
  91. this.TryInvokeContinuation();
  92. return true;
  93. }
  94. }
  95. public class ETTaskCompletionSource<T>: ICriticalNotifyCompletion
  96. {
  97. private AwaiterStatus state;
  98. private T value;
  99. private ExceptionDispatchInfo exception;
  100. private Action continuation; // action or list
  101. [DebuggerHidden]
  102. public ETTask<T> Task => new ETTask<T>(this);
  103. [DebuggerHidden]
  104. public ETTaskCompletionSource<T> GetAwaiter()
  105. {
  106. return this;
  107. }
  108. [DebuggerHidden]
  109. public T GetResult()
  110. {
  111. switch (this.state)
  112. {
  113. case AwaiterStatus.Succeeded:
  114. return this.value;
  115. case AwaiterStatus.Faulted:
  116. this.exception?.Throw();
  117. this.exception = null;
  118. return default;
  119. default:
  120. throw new NotSupportedException("ETask does not allow call GetResult directly when task not completed. Please use 'await'.");
  121. }
  122. }
  123. [DebuggerHidden]
  124. public bool IsCompleted => state != AwaiterStatus.Pending;
  125. [DebuggerHidden]
  126. public AwaiterStatus Status => state;
  127. [DebuggerHidden]
  128. public void UnsafeOnCompleted(Action action)
  129. {
  130. this.continuation = action;
  131. if (state != AwaiterStatus.Pending)
  132. {
  133. TryInvokeContinuation();
  134. }
  135. }
  136. [DebuggerHidden]
  137. public void OnCompleted(Action action)
  138. {
  139. this.UnsafeOnCompleted(action);
  140. }
  141. [DebuggerHidden]
  142. public void SetResult(T result)
  143. {
  144. if (this.TrySetResult(result))
  145. {
  146. return;
  147. }
  148. throw new InvalidOperationException("TaskT_TransitionToFinal_AlreadyCompleted");
  149. }
  150. [DebuggerHidden]
  151. public void SetException(Exception e)
  152. {
  153. if (this.TrySetException(e))
  154. {
  155. return;
  156. }
  157. throw new InvalidOperationException("TaskT_TransitionToFinal_AlreadyCompleted");
  158. }
  159. [DebuggerHidden]
  160. private void TryInvokeContinuation()
  161. {
  162. this.continuation?.Invoke();
  163. this.continuation = null;
  164. }
  165. [DebuggerHidden]
  166. private bool TrySetResult(T result)
  167. {
  168. if (this.state != AwaiterStatus.Pending)
  169. {
  170. return false;
  171. }
  172. this.state = AwaiterStatus.Succeeded;
  173. this.value = result;
  174. this.TryInvokeContinuation();
  175. return true;
  176. }
  177. [DebuggerHidden]
  178. private bool TrySetException(Exception e)
  179. {
  180. if (this.state != AwaiterStatus.Pending)
  181. {
  182. return false;
  183. }
  184. this.state = AwaiterStatus.Faulted;
  185. this.exception = ExceptionDispatchInfo.Capture(e);
  186. this.TryInvokeContinuation();
  187. return true;
  188. }
  189. }
  190. }