Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 

292 linhas
7.6 KiB

  1. using System;
  2. using System.Threading;
  3. namespace Cysharp.Threading.Tasks
  4. {
  5. public interface ITriggerHandler<T>
  6. {
  7. void OnNext(T value);
  8. void OnError(Exception ex);
  9. void OnCompleted();
  10. void OnCanceled(CancellationToken cancellationToken);
  11. // set/get from TriggerEvent<T>
  12. ITriggerHandler<T> Prev { get; set; }
  13. ITriggerHandler<T> Next { get; set; }
  14. }
  15. // be careful to use, itself is struct.
  16. public struct TriggerEvent<T>
  17. {
  18. ITriggerHandler<T> head; // head.prev is last
  19. ITriggerHandler<T> iteratingHead;
  20. ITriggerHandler<T> iteratingNode;
  21. void LogError(Exception ex)
  22. {
  23. #if UNITY_2018_3_OR_NEWER
  24. UnityEngine.Debug.LogException(ex);
  25. #else
  26. Console.WriteLine(ex);
  27. #endif
  28. }
  29. public void SetResult(T value)
  30. {
  31. if (iteratingNode != null)
  32. {
  33. throw new InvalidOperationException("Can not trigger itself in iterating.");
  34. }
  35. var h = head;
  36. while (h != null)
  37. {
  38. iteratingNode = h;
  39. try
  40. {
  41. h.OnNext(value);
  42. }
  43. catch (Exception ex)
  44. {
  45. LogError(ex);
  46. Remove(h);
  47. }
  48. // If `h` itself is removed by OnNext, h.Next is null.
  49. // Therefore, instead of looking at h.Next, the `iteratingNode` reference itself is replaced.
  50. h = h == iteratingNode ? h.Next : iteratingNode;
  51. }
  52. iteratingNode = null;
  53. if (iteratingHead != null)
  54. {
  55. Add(iteratingHead);
  56. iteratingHead = null;
  57. }
  58. }
  59. public void SetCanceled(CancellationToken cancellationToken)
  60. {
  61. if (iteratingNode != null)
  62. {
  63. throw new InvalidOperationException("Can not trigger itself in iterating.");
  64. }
  65. var h = head;
  66. while (h != null)
  67. {
  68. iteratingNode = h;
  69. try
  70. {
  71. h.OnCanceled(cancellationToken);
  72. }
  73. catch (Exception ex)
  74. {
  75. LogError(ex);
  76. }
  77. var next = h == iteratingNode ? h.Next : iteratingNode;
  78. iteratingNode = null;
  79. Remove(h);
  80. h = next;
  81. }
  82. iteratingNode = null;
  83. if (iteratingHead != null)
  84. {
  85. Add(iteratingHead);
  86. iteratingHead = null;
  87. }
  88. }
  89. public void SetCompleted()
  90. {
  91. if (iteratingNode != null)
  92. {
  93. throw new InvalidOperationException("Can not trigger itself in iterating.");
  94. }
  95. var h = head;
  96. while (h != null)
  97. {
  98. iteratingNode = h;
  99. try
  100. {
  101. h.OnCompleted();
  102. }
  103. catch (Exception ex)
  104. {
  105. LogError(ex);
  106. }
  107. var next = h == iteratingNode ? h.Next : iteratingNode;
  108. iteratingNode = null;
  109. Remove(h);
  110. h = next;
  111. }
  112. iteratingNode = null;
  113. if (iteratingHead != null)
  114. {
  115. Add(iteratingHead);
  116. iteratingHead = null;
  117. }
  118. }
  119. public void SetError(Exception exception)
  120. {
  121. if (iteratingNode != null)
  122. {
  123. throw new InvalidOperationException("Can not trigger itself in iterating.");
  124. }
  125. var h = head;
  126. while (h != null)
  127. {
  128. iteratingNode = h;
  129. try
  130. {
  131. h.OnError(exception);
  132. }
  133. catch (Exception ex)
  134. {
  135. LogError(ex);
  136. }
  137. var next = h == iteratingNode ? h.Next : iteratingNode;
  138. iteratingNode = null;
  139. Remove(h);
  140. h = next;
  141. }
  142. iteratingNode = null;
  143. if (iteratingHead != null)
  144. {
  145. Add(iteratingHead);
  146. iteratingHead = null;
  147. }
  148. }
  149. public void Add(ITriggerHandler<T> handler)
  150. {
  151. if (handler == null) throw new ArgumentNullException(nameof(handler));
  152. // zero node.
  153. if (head == null)
  154. {
  155. head = handler;
  156. return;
  157. }
  158. if (iteratingNode != null)
  159. {
  160. if (iteratingHead == null)
  161. {
  162. iteratingHead = handler;
  163. return;
  164. }
  165. var last = iteratingHead.Prev;
  166. if (last == null)
  167. {
  168. // single node.
  169. iteratingHead.Prev = handler;
  170. iteratingHead.Next = handler;
  171. handler.Prev = iteratingHead;
  172. }
  173. else
  174. {
  175. // multi node
  176. iteratingHead.Prev = handler;
  177. last.Next = handler;
  178. handler.Prev = last;
  179. }
  180. }
  181. else
  182. {
  183. var last = head.Prev;
  184. if (last == null)
  185. {
  186. // single node.
  187. head.Prev = handler;
  188. head.Next = handler;
  189. handler.Prev = head;
  190. }
  191. else
  192. {
  193. // multi node
  194. head.Prev = handler;
  195. last.Next = handler;
  196. handler.Prev = last;
  197. }
  198. }
  199. }
  200. public void Remove(ITriggerHandler<T> handler)
  201. {
  202. if (handler == null) throw new ArgumentNullException(nameof(handler));
  203. var prev = handler.Prev;
  204. var next = handler.Next;
  205. if (next != null)
  206. {
  207. next.Prev = prev;
  208. }
  209. if (handler == head)
  210. {
  211. head = next;
  212. }
  213. // when handler is head, prev indicate last so don't use it.
  214. else if (prev != null)
  215. {
  216. prev.Next = next;
  217. }
  218. if (handler == iteratingNode)
  219. {
  220. iteratingNode = next;
  221. }
  222. if (handler == iteratingHead)
  223. {
  224. iteratingHead = next;
  225. }
  226. if (head != null)
  227. {
  228. if (head.Prev == handler)
  229. {
  230. if (prev != head)
  231. {
  232. head.Prev = prev;
  233. }
  234. else
  235. {
  236. head.Prev = null;
  237. }
  238. }
  239. }
  240. if (iteratingHead != null)
  241. {
  242. if (iteratingHead.Prev == handler)
  243. {
  244. if (prev != iteratingHead.Prev)
  245. {
  246. iteratingHead.Prev = prev;
  247. }
  248. else
  249. {
  250. iteratingHead.Prev = null;
  251. }
  252. }
  253. }
  254. handler.Prev = null;
  255. handler.Next = null;
  256. }
  257. }
  258. }