UnityAsyncExtensions.uGUI.cs 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858
  1. #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
  2. #if !UNITY_2019_1_OR_NEWER || UNITASK_UGUI_SUPPORT
  3. using System;
  4. using System.Threading;
  5. using UnityEngine;
  6. using UnityEngine.Events;
  7. using UnityEngine.UI;
  8. namespace Cysharp.Threading.Tasks
  9. {
  10. public static partial class UnityAsyncExtensions
  11. {
  12. public static AsyncUnityEventHandler GetAsyncEventHandler(this UnityEvent unityEvent, CancellationToken cancellationToken)
  13. {
  14. return new AsyncUnityEventHandler(unityEvent, cancellationToken, false);
  15. }
  16. public static UniTask OnInvokeAsync(this UnityEvent unityEvent, CancellationToken cancellationToken)
  17. {
  18. return new AsyncUnityEventHandler(unityEvent, cancellationToken, true).OnInvokeAsync();
  19. }
  20. public static IUniTaskAsyncEnumerable<AsyncUnit> OnInvokeAsAsyncEnumerable(this UnityEvent unityEvent, CancellationToken cancellationToken)
  21. {
  22. return new UnityEventHandlerAsyncEnumerable(unityEvent, cancellationToken);
  23. }
  24. public static AsyncUnityEventHandler<T> GetAsyncEventHandler<T>(this UnityEvent<T> unityEvent, CancellationToken cancellationToken)
  25. {
  26. return new AsyncUnityEventHandler<T>(unityEvent, cancellationToken, false);
  27. }
  28. public static UniTask<T> OnInvokeAsync<T>(this UnityEvent<T> unityEvent, CancellationToken cancellationToken)
  29. {
  30. return new AsyncUnityEventHandler<T>(unityEvent, cancellationToken, true).OnInvokeAsync();
  31. }
  32. public static IUniTaskAsyncEnumerable<T> OnInvokeAsAsyncEnumerable<T>(this UnityEvent<T> unityEvent, CancellationToken cancellationToken)
  33. {
  34. return new UnityEventHandlerAsyncEnumerable<T>(unityEvent, cancellationToken);
  35. }
  36. public static IAsyncClickEventHandler GetAsyncClickEventHandler(this Button button)
  37. {
  38. return new AsyncUnityEventHandler(button.onClick, button.GetCancellationTokenOnDestroy(), false);
  39. }
  40. public static IAsyncClickEventHandler GetAsyncClickEventHandler(this Button button, CancellationToken cancellationToken)
  41. {
  42. return new AsyncUnityEventHandler(button.onClick, cancellationToken, false);
  43. }
  44. public static UniTask OnClickAsync(this Button button)
  45. {
  46. return new AsyncUnityEventHandler(button.onClick, button.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
  47. }
  48. public static UniTask OnClickAsync(this Button button, CancellationToken cancellationToken)
  49. {
  50. return new AsyncUnityEventHandler(button.onClick, cancellationToken, true).OnInvokeAsync();
  51. }
  52. public static IUniTaskAsyncEnumerable<AsyncUnit> OnClickAsAsyncEnumerable(this Button button)
  53. {
  54. return new UnityEventHandlerAsyncEnumerable(button.onClick, button.GetCancellationTokenOnDestroy());
  55. }
  56. public static IUniTaskAsyncEnumerable<AsyncUnit> OnClickAsAsyncEnumerable(this Button button, CancellationToken cancellationToken)
  57. {
  58. return new UnityEventHandlerAsyncEnumerable(button.onClick, cancellationToken);
  59. }
  60. public static IAsyncValueChangedEventHandler<bool> GetAsyncValueChangedEventHandler(this Toggle toggle)
  61. {
  62. return new AsyncUnityEventHandler<bool>(toggle.onValueChanged, toggle.GetCancellationTokenOnDestroy(), false);
  63. }
  64. public static IAsyncValueChangedEventHandler<bool> GetAsyncValueChangedEventHandler(this Toggle toggle, CancellationToken cancellationToken)
  65. {
  66. return new AsyncUnityEventHandler<bool>(toggle.onValueChanged, cancellationToken, false);
  67. }
  68. public static UniTask<bool> OnValueChangedAsync(this Toggle toggle)
  69. {
  70. return new AsyncUnityEventHandler<bool>(toggle.onValueChanged, toggle.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
  71. }
  72. public static UniTask<bool> OnValueChangedAsync(this Toggle toggle, CancellationToken cancellationToken)
  73. {
  74. return new AsyncUnityEventHandler<bool>(toggle.onValueChanged, cancellationToken, true).OnInvokeAsync();
  75. }
  76. public static IUniTaskAsyncEnumerable<bool> OnValueChangedAsAsyncEnumerable(this Toggle toggle)
  77. {
  78. return new UnityEventHandlerAsyncEnumerable<bool>(toggle.onValueChanged, toggle.GetCancellationTokenOnDestroy());
  79. }
  80. public static IUniTaskAsyncEnumerable<bool> OnValueChangedAsAsyncEnumerable(this Toggle toggle, CancellationToken cancellationToken)
  81. {
  82. return new UnityEventHandlerAsyncEnumerable<bool>(toggle.onValueChanged, cancellationToken);
  83. }
  84. public static IAsyncValueChangedEventHandler<float> GetAsyncValueChangedEventHandler(this Scrollbar scrollbar)
  85. {
  86. return new AsyncUnityEventHandler<float>(scrollbar.onValueChanged, scrollbar.GetCancellationTokenOnDestroy(), false);
  87. }
  88. public static IAsyncValueChangedEventHandler<float> GetAsyncValueChangedEventHandler(this Scrollbar scrollbar, CancellationToken cancellationToken)
  89. {
  90. return new AsyncUnityEventHandler<float>(scrollbar.onValueChanged, cancellationToken, false);
  91. }
  92. public static UniTask<float> OnValueChangedAsync(this Scrollbar scrollbar)
  93. {
  94. return new AsyncUnityEventHandler<float>(scrollbar.onValueChanged, scrollbar.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
  95. }
  96. public static UniTask<float> OnValueChangedAsync(this Scrollbar scrollbar, CancellationToken cancellationToken)
  97. {
  98. return new AsyncUnityEventHandler<float>(scrollbar.onValueChanged, cancellationToken, true).OnInvokeAsync();
  99. }
  100. public static IUniTaskAsyncEnumerable<float> OnValueChangedAsAsyncEnumerable(this Scrollbar scrollbar)
  101. {
  102. return new UnityEventHandlerAsyncEnumerable<float>(scrollbar.onValueChanged, scrollbar.GetCancellationTokenOnDestroy());
  103. }
  104. public static IUniTaskAsyncEnumerable<float> OnValueChangedAsAsyncEnumerable(this Scrollbar scrollbar, CancellationToken cancellationToken)
  105. {
  106. return new UnityEventHandlerAsyncEnumerable<float>(scrollbar.onValueChanged, cancellationToken);
  107. }
  108. public static IAsyncValueChangedEventHandler<Vector2> GetAsyncValueChangedEventHandler(this ScrollRect scrollRect)
  109. {
  110. return new AsyncUnityEventHandler<Vector2>(scrollRect.onValueChanged, scrollRect.GetCancellationTokenOnDestroy(), false);
  111. }
  112. public static IAsyncValueChangedEventHandler<Vector2> GetAsyncValueChangedEventHandler(this ScrollRect scrollRect, CancellationToken cancellationToken)
  113. {
  114. return new AsyncUnityEventHandler<Vector2>(scrollRect.onValueChanged, cancellationToken, false);
  115. }
  116. public static UniTask<Vector2> OnValueChangedAsync(this ScrollRect scrollRect)
  117. {
  118. return new AsyncUnityEventHandler<Vector2>(scrollRect.onValueChanged, scrollRect.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
  119. }
  120. public static UniTask<Vector2> OnValueChangedAsync(this ScrollRect scrollRect, CancellationToken cancellationToken)
  121. {
  122. return new AsyncUnityEventHandler<Vector2>(scrollRect.onValueChanged, cancellationToken, true).OnInvokeAsync();
  123. }
  124. public static IUniTaskAsyncEnumerable<Vector2> OnValueChangedAsAsyncEnumerable(this ScrollRect scrollRect)
  125. {
  126. return new UnityEventHandlerAsyncEnumerable<Vector2>(scrollRect.onValueChanged, scrollRect.GetCancellationTokenOnDestroy());
  127. }
  128. public static IUniTaskAsyncEnumerable<Vector2> OnValueChangedAsAsyncEnumerable(this ScrollRect scrollRect, CancellationToken cancellationToken)
  129. {
  130. return new UnityEventHandlerAsyncEnumerable<Vector2>(scrollRect.onValueChanged, cancellationToken);
  131. }
  132. public static IAsyncValueChangedEventHandler<float> GetAsyncValueChangedEventHandler(this Slider slider)
  133. {
  134. return new AsyncUnityEventHandler<float>(slider.onValueChanged, slider.GetCancellationTokenOnDestroy(), false);
  135. }
  136. public static IAsyncValueChangedEventHandler<float> GetAsyncValueChangedEventHandler(this Slider slider, CancellationToken cancellationToken)
  137. {
  138. return new AsyncUnityEventHandler<float>(slider.onValueChanged, cancellationToken, false);
  139. }
  140. public static UniTask<float> OnValueChangedAsync(this Slider slider)
  141. {
  142. return new AsyncUnityEventHandler<float>(slider.onValueChanged, slider.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
  143. }
  144. public static UniTask<float> OnValueChangedAsync(this Slider slider, CancellationToken cancellationToken)
  145. {
  146. return new AsyncUnityEventHandler<float>(slider.onValueChanged, cancellationToken, true).OnInvokeAsync();
  147. }
  148. public static IUniTaskAsyncEnumerable<float> OnValueChangedAsAsyncEnumerable(this Slider slider)
  149. {
  150. return new UnityEventHandlerAsyncEnumerable<float>(slider.onValueChanged, slider.GetCancellationTokenOnDestroy());
  151. }
  152. public static IUniTaskAsyncEnumerable<float> OnValueChangedAsAsyncEnumerable(this Slider slider, CancellationToken cancellationToken)
  153. {
  154. return new UnityEventHandlerAsyncEnumerable<float>(slider.onValueChanged, cancellationToken);
  155. }
  156. public static IAsyncEndEditEventHandler<string> GetAsyncEndEditEventHandler(this InputField inputField)
  157. {
  158. return new AsyncUnityEventHandler<string>(inputField.onEndEdit, inputField.GetCancellationTokenOnDestroy(), false);
  159. }
  160. public static IAsyncEndEditEventHandler<string> GetAsyncEndEditEventHandler(this InputField inputField, CancellationToken cancellationToken)
  161. {
  162. return new AsyncUnityEventHandler<string>(inputField.onEndEdit, cancellationToken, false);
  163. }
  164. public static UniTask<string> OnEndEditAsync(this InputField inputField)
  165. {
  166. return new AsyncUnityEventHandler<string>(inputField.onEndEdit, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
  167. }
  168. public static UniTask<string> OnEndEditAsync(this InputField inputField, CancellationToken cancellationToken)
  169. {
  170. return new AsyncUnityEventHandler<string>(inputField.onEndEdit, cancellationToken, true).OnInvokeAsync();
  171. }
  172. public static IUniTaskAsyncEnumerable<string> OnEndEditAsAsyncEnumerable(this InputField inputField)
  173. {
  174. return new UnityEventHandlerAsyncEnumerable<string>(inputField.onEndEdit, inputField.GetCancellationTokenOnDestroy());
  175. }
  176. public static IUniTaskAsyncEnumerable<string> OnEndEditAsAsyncEnumerable(this InputField inputField, CancellationToken cancellationToken)
  177. {
  178. return new UnityEventHandlerAsyncEnumerable<string>(inputField.onEndEdit, cancellationToken);
  179. }
  180. public static IAsyncValueChangedEventHandler<string> GetAsyncValueChangedEventHandler(this InputField inputField)
  181. {
  182. return new AsyncUnityEventHandler<string>(inputField.onValueChanged, inputField.GetCancellationTokenOnDestroy(), false);
  183. }
  184. public static IAsyncValueChangedEventHandler<string> GetAsyncValueChangedEventHandler(this InputField inputField, CancellationToken cancellationToken)
  185. {
  186. return new AsyncUnityEventHandler<string>(inputField.onValueChanged, cancellationToken, false);
  187. }
  188. public static UniTask<string> OnValueChangedAsync(this InputField inputField)
  189. {
  190. return new AsyncUnityEventHandler<string>(inputField.onValueChanged, inputField.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
  191. }
  192. public static UniTask<string> OnValueChangedAsync(this InputField inputField, CancellationToken cancellationToken)
  193. {
  194. return new AsyncUnityEventHandler<string>(inputField.onValueChanged, cancellationToken, true).OnInvokeAsync();
  195. }
  196. public static IUniTaskAsyncEnumerable<string> OnValueChangedAsAsyncEnumerable(this InputField inputField)
  197. {
  198. return new UnityEventHandlerAsyncEnumerable<string>(inputField.onValueChanged, inputField.GetCancellationTokenOnDestroy());
  199. }
  200. public static IUniTaskAsyncEnumerable<string> OnValueChangedAsAsyncEnumerable(this InputField inputField, CancellationToken cancellationToken)
  201. {
  202. return new UnityEventHandlerAsyncEnumerable<string>(inputField.onValueChanged, cancellationToken);
  203. }
  204. public static IAsyncValueChangedEventHandler<int> GetAsyncValueChangedEventHandler(this Dropdown dropdown)
  205. {
  206. return new AsyncUnityEventHandler<int>(dropdown.onValueChanged, dropdown.GetCancellationTokenOnDestroy(), false);
  207. }
  208. public static IAsyncValueChangedEventHandler<int> GetAsyncValueChangedEventHandler(this Dropdown dropdown, CancellationToken cancellationToken)
  209. {
  210. return new AsyncUnityEventHandler<int>(dropdown.onValueChanged, cancellationToken, false);
  211. }
  212. public static UniTask<int> OnValueChangedAsync(this Dropdown dropdown)
  213. {
  214. return new AsyncUnityEventHandler<int>(dropdown.onValueChanged, dropdown.GetCancellationTokenOnDestroy(), true).OnInvokeAsync();
  215. }
  216. public static UniTask<int> OnValueChangedAsync(this Dropdown dropdown, CancellationToken cancellationToken)
  217. {
  218. return new AsyncUnityEventHandler<int>(dropdown.onValueChanged, cancellationToken, true).OnInvokeAsync();
  219. }
  220. public static IUniTaskAsyncEnumerable<int> OnValueChangedAsAsyncEnumerable(this Dropdown dropdown)
  221. {
  222. return new UnityEventHandlerAsyncEnumerable<int>(dropdown.onValueChanged, dropdown.GetCancellationTokenOnDestroy());
  223. }
  224. public static IUniTaskAsyncEnumerable<int> OnValueChangedAsAsyncEnumerable(this Dropdown dropdown, CancellationToken cancellationToken)
  225. {
  226. return new UnityEventHandlerAsyncEnumerable<int>(dropdown.onValueChanged, cancellationToken);
  227. }
  228. }
  229. public interface IAsyncClickEventHandler : IDisposable
  230. {
  231. UniTask OnClickAsync();
  232. }
  233. public interface IAsyncValueChangedEventHandler<T> : IDisposable
  234. {
  235. UniTask<T> OnValueChangedAsync();
  236. }
  237. public interface IAsyncEndEditEventHandler<T> : IDisposable
  238. {
  239. UniTask<T> OnEndEditAsync();
  240. }
  241. // for TMP_PRO
  242. public interface IAsyncEndTextSelectionEventHandler<T> : IDisposable
  243. {
  244. UniTask<T> OnEndTextSelectionAsync();
  245. }
  246. public interface IAsyncTextSelectionEventHandler<T> : IDisposable
  247. {
  248. UniTask<T> OnTextSelectionAsync();
  249. }
  250. public interface IAsyncDeselectEventHandler<T> : IDisposable
  251. {
  252. UniTask<T> OnDeselectAsync();
  253. }
  254. public interface IAsyncSelectEventHandler<T> : IDisposable
  255. {
  256. UniTask<T> OnSelectAsync();
  257. }
  258. public interface IAsyncSubmitEventHandler<T> : IDisposable
  259. {
  260. UniTask<T> OnSubmitAsync();
  261. }
  262. internal class TextSelectionEventConverter : UnityEvent<(string, int, int)>, IDisposable
  263. {
  264. readonly UnityEvent<string, int, int> innerEvent;
  265. readonly UnityAction<string, int, int> invokeDelegate;
  266. public TextSelectionEventConverter(UnityEvent<string, int, int> unityEvent)
  267. {
  268. this.innerEvent = unityEvent;
  269. this.invokeDelegate = InvokeCore;
  270. innerEvent.AddListener(invokeDelegate);
  271. }
  272. void InvokeCore(string item1, int item2, int item3)
  273. {
  274. innerEvent.Invoke(item1, item2, item3);
  275. }
  276. public void Dispose()
  277. {
  278. innerEvent.RemoveListener(invokeDelegate);
  279. }
  280. }
  281. public class AsyncUnityEventHandler : IUniTaskSource, IDisposable, IAsyncClickEventHandler
  282. {
  283. static Action<object> cancellationCallback = CancellationCallback;
  284. readonly UnityAction action;
  285. readonly UnityEvent unityEvent;
  286. CancellationToken cancellationToken;
  287. CancellationTokenRegistration registration;
  288. bool isDisposed;
  289. bool callOnce;
  290. UniTaskCompletionSourceCore<AsyncUnit> core;
  291. public AsyncUnityEventHandler(UnityEvent unityEvent, CancellationToken cancellationToken, bool callOnce)
  292. {
  293. this.cancellationToken = cancellationToken;
  294. if (cancellationToken.IsCancellationRequested)
  295. {
  296. isDisposed = true;
  297. return;
  298. }
  299. this.action = Invoke;
  300. this.unityEvent = unityEvent;
  301. this.callOnce = callOnce;
  302. unityEvent.AddListener(action);
  303. if (cancellationToken.CanBeCanceled)
  304. {
  305. registration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, this);
  306. }
  307. TaskTracker.TrackActiveTask(this, 3);
  308. }
  309. public UniTask OnInvokeAsync()
  310. {
  311. core.Reset();
  312. if (isDisposed)
  313. {
  314. core.TrySetCanceled(this.cancellationToken);
  315. }
  316. return new UniTask(this, core.Version);
  317. }
  318. void Invoke()
  319. {
  320. core.TrySetResult(AsyncUnit.Default);
  321. }
  322. static void CancellationCallback(object state)
  323. {
  324. var self = (AsyncUnityEventHandler)state;
  325. self.Dispose();
  326. }
  327. public void Dispose()
  328. {
  329. if (!isDisposed)
  330. {
  331. isDisposed = true;
  332. TaskTracker.RemoveTracking(this);
  333. registration.Dispose();
  334. if (unityEvent != null)
  335. {
  336. unityEvent.RemoveListener(action);
  337. }
  338. core.TrySetCanceled(cancellationToken);
  339. }
  340. }
  341. UniTask IAsyncClickEventHandler.OnClickAsync()
  342. {
  343. return OnInvokeAsync();
  344. }
  345. void IUniTaskSource.GetResult(short token)
  346. {
  347. try
  348. {
  349. core.GetResult(token);
  350. }
  351. finally
  352. {
  353. if (callOnce)
  354. {
  355. Dispose();
  356. }
  357. }
  358. }
  359. UniTaskStatus IUniTaskSource.GetStatus(short token)
  360. {
  361. return core.GetStatus(token);
  362. }
  363. UniTaskStatus IUniTaskSource.UnsafeGetStatus()
  364. {
  365. return core.UnsafeGetStatus();
  366. }
  367. void IUniTaskSource.OnCompleted(Action<object> continuation, object state, short token)
  368. {
  369. core.OnCompleted(continuation, state, token);
  370. }
  371. }
  372. public class AsyncUnityEventHandler<T> : IUniTaskSource<T>, IDisposable, IAsyncValueChangedEventHandler<T>, IAsyncEndEditEventHandler<T>
  373. , IAsyncEndTextSelectionEventHandler<T>, IAsyncTextSelectionEventHandler<T>, IAsyncDeselectEventHandler<T>, IAsyncSelectEventHandler<T>, IAsyncSubmitEventHandler<T>
  374. {
  375. static Action<object> cancellationCallback = CancellationCallback;
  376. readonly UnityAction<T> action;
  377. readonly UnityEvent<T> unityEvent;
  378. CancellationToken cancellationToken;
  379. CancellationTokenRegistration registration;
  380. bool isDisposed;
  381. bool callOnce;
  382. UniTaskCompletionSourceCore<T> core;
  383. public AsyncUnityEventHandler(UnityEvent<T> unityEvent, CancellationToken cancellationToken, bool callOnce)
  384. {
  385. this.cancellationToken = cancellationToken;
  386. if (cancellationToken.IsCancellationRequested)
  387. {
  388. isDisposed = true;
  389. return;
  390. }
  391. this.action = Invoke;
  392. this.unityEvent = unityEvent;
  393. this.callOnce = callOnce;
  394. unityEvent.AddListener(action);
  395. if (cancellationToken.CanBeCanceled)
  396. {
  397. registration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, this);
  398. }
  399. TaskTracker.TrackActiveTask(this, 3);
  400. }
  401. public UniTask<T> OnInvokeAsync()
  402. {
  403. core.Reset();
  404. if (isDisposed)
  405. {
  406. core.TrySetCanceled(this.cancellationToken);
  407. }
  408. return new UniTask<T>(this, core.Version);
  409. }
  410. void Invoke(T result)
  411. {
  412. core.TrySetResult(result);
  413. }
  414. static void CancellationCallback(object state)
  415. {
  416. var self = (AsyncUnityEventHandler<T>)state;
  417. self.Dispose();
  418. }
  419. public void Dispose()
  420. {
  421. if (!isDisposed)
  422. {
  423. isDisposed = true;
  424. TaskTracker.RemoveTracking(this);
  425. registration.Dispose();
  426. if (unityEvent != null)
  427. {
  428. // Dispose inner delegate for TextSelectionEventConverter
  429. if (unityEvent is IDisposable disp)
  430. {
  431. disp.Dispose();
  432. }
  433. unityEvent.RemoveListener(action);
  434. }
  435. core.TrySetCanceled();
  436. }
  437. }
  438. UniTask<T> IAsyncValueChangedEventHandler<T>.OnValueChangedAsync()
  439. {
  440. return OnInvokeAsync();
  441. }
  442. UniTask<T> IAsyncEndEditEventHandler<T>.OnEndEditAsync()
  443. {
  444. return OnInvokeAsync();
  445. }
  446. UniTask<T> IAsyncEndTextSelectionEventHandler<T>.OnEndTextSelectionAsync()
  447. {
  448. return OnInvokeAsync();
  449. }
  450. UniTask<T> IAsyncTextSelectionEventHandler<T>.OnTextSelectionAsync()
  451. {
  452. return OnInvokeAsync();
  453. }
  454. UniTask<T> IAsyncDeselectEventHandler<T>.OnDeselectAsync()
  455. {
  456. return OnInvokeAsync();
  457. }
  458. UniTask<T> IAsyncSelectEventHandler<T>.OnSelectAsync()
  459. {
  460. return OnInvokeAsync();
  461. }
  462. UniTask<T> IAsyncSubmitEventHandler<T>.OnSubmitAsync()
  463. {
  464. return OnInvokeAsync();
  465. }
  466. T IUniTaskSource<T>.GetResult(short token)
  467. {
  468. try
  469. {
  470. return core.GetResult(token);
  471. }
  472. finally
  473. {
  474. if (callOnce)
  475. {
  476. Dispose();
  477. }
  478. }
  479. }
  480. void IUniTaskSource.GetResult(short token)
  481. {
  482. ((IUniTaskSource<T>)this).GetResult(token);
  483. }
  484. UniTaskStatus IUniTaskSource.GetStatus(short token)
  485. {
  486. return core.GetStatus(token);
  487. }
  488. UniTaskStatus IUniTaskSource.UnsafeGetStatus()
  489. {
  490. return core.UnsafeGetStatus();
  491. }
  492. void IUniTaskSource.OnCompleted(Action<object> continuation, object state, short token)
  493. {
  494. core.OnCompleted(continuation, state, token);
  495. }
  496. }
  497. public class UnityEventHandlerAsyncEnumerable : IUniTaskAsyncEnumerable<AsyncUnit>
  498. {
  499. readonly UnityEvent unityEvent;
  500. readonly CancellationToken cancellationToken1;
  501. public UnityEventHandlerAsyncEnumerable(UnityEvent unityEvent, CancellationToken cancellationToken)
  502. {
  503. this.unityEvent = unityEvent;
  504. this.cancellationToken1 = cancellationToken;
  505. }
  506. public IUniTaskAsyncEnumerator<AsyncUnit> GetAsyncEnumerator(CancellationToken cancellationToken = default)
  507. {
  508. if (this.cancellationToken1 == cancellationToken)
  509. {
  510. return new UnityEventHandlerAsyncEnumerator(unityEvent, this.cancellationToken1, CancellationToken.None);
  511. }
  512. else
  513. {
  514. return new UnityEventHandlerAsyncEnumerator(unityEvent, this.cancellationToken1, cancellationToken);
  515. }
  516. }
  517. class UnityEventHandlerAsyncEnumerator : MoveNextSource, IUniTaskAsyncEnumerator<AsyncUnit>
  518. {
  519. static readonly Action<object> cancel1 = OnCanceled1;
  520. static readonly Action<object> cancel2 = OnCanceled2;
  521. readonly UnityEvent unityEvent;
  522. CancellationToken cancellationToken1;
  523. CancellationToken cancellationToken2;
  524. UnityAction unityAction;
  525. CancellationTokenRegistration registration1;
  526. CancellationTokenRegistration registration2;
  527. bool isDisposed;
  528. public UnityEventHandlerAsyncEnumerator(UnityEvent unityEvent, CancellationToken cancellationToken1, CancellationToken cancellationToken2)
  529. {
  530. this.unityEvent = unityEvent;
  531. this.cancellationToken1 = cancellationToken1;
  532. this.cancellationToken2 = cancellationToken2;
  533. }
  534. public AsyncUnit Current => default;
  535. public UniTask<bool> MoveNextAsync()
  536. {
  537. cancellationToken1.ThrowIfCancellationRequested();
  538. cancellationToken2.ThrowIfCancellationRequested();
  539. completionSource.Reset();
  540. if (unityAction == null)
  541. {
  542. unityAction = Invoke;
  543. TaskTracker.TrackActiveTask(this, 3);
  544. unityEvent.AddListener(unityAction);
  545. if (cancellationToken1.CanBeCanceled)
  546. {
  547. registration1 = cancellationToken1.RegisterWithoutCaptureExecutionContext(cancel1, this);
  548. }
  549. if (cancellationToken2.CanBeCanceled)
  550. {
  551. registration2 = cancellationToken2.RegisterWithoutCaptureExecutionContext(cancel2, this);
  552. }
  553. }
  554. return new UniTask<bool>(this, completionSource.Version);
  555. }
  556. void Invoke()
  557. {
  558. completionSource.TrySetResult(true);
  559. }
  560. static void OnCanceled1(object state)
  561. {
  562. var self = (UnityEventHandlerAsyncEnumerator)state;
  563. try
  564. {
  565. self.completionSource.TrySetCanceled(self.cancellationToken1);
  566. }
  567. finally
  568. {
  569. self.DisposeAsync().Forget();
  570. }
  571. }
  572. static void OnCanceled2(object state)
  573. {
  574. var self = (UnityEventHandlerAsyncEnumerator)state;
  575. try
  576. {
  577. self.completionSource.TrySetCanceled(self.cancellationToken2);
  578. }
  579. finally
  580. {
  581. self.DisposeAsync().Forget();
  582. }
  583. }
  584. public UniTask DisposeAsync()
  585. {
  586. if (!isDisposed)
  587. {
  588. isDisposed = true;
  589. TaskTracker.RemoveTracking(this);
  590. registration1.Dispose();
  591. registration2.Dispose();
  592. unityEvent.RemoveListener(unityAction);
  593. completionSource.TrySetCanceled();
  594. }
  595. return default;
  596. }
  597. }
  598. }
  599. public class UnityEventHandlerAsyncEnumerable<T> : IUniTaskAsyncEnumerable<T>
  600. {
  601. readonly UnityEvent<T> unityEvent;
  602. readonly CancellationToken cancellationToken1;
  603. public UnityEventHandlerAsyncEnumerable(UnityEvent<T> unityEvent, CancellationToken cancellationToken)
  604. {
  605. this.unityEvent = unityEvent;
  606. this.cancellationToken1 = cancellationToken;
  607. }
  608. public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
  609. {
  610. if (this.cancellationToken1 == cancellationToken)
  611. {
  612. return new UnityEventHandlerAsyncEnumerator(unityEvent, this.cancellationToken1, CancellationToken.None);
  613. }
  614. else
  615. {
  616. return new UnityEventHandlerAsyncEnumerator(unityEvent, this.cancellationToken1, cancellationToken);
  617. }
  618. }
  619. class UnityEventHandlerAsyncEnumerator : MoveNextSource, IUniTaskAsyncEnumerator<T>
  620. {
  621. static readonly Action<object> cancel1 = OnCanceled1;
  622. static readonly Action<object> cancel2 = OnCanceled2;
  623. readonly UnityEvent<T> unityEvent;
  624. CancellationToken cancellationToken1;
  625. CancellationToken cancellationToken2;
  626. UnityAction<T> unityAction;
  627. CancellationTokenRegistration registration1;
  628. CancellationTokenRegistration registration2;
  629. bool isDisposed;
  630. public UnityEventHandlerAsyncEnumerator(UnityEvent<T> unityEvent, CancellationToken cancellationToken1, CancellationToken cancellationToken2)
  631. {
  632. this.unityEvent = unityEvent;
  633. this.cancellationToken1 = cancellationToken1;
  634. this.cancellationToken2 = cancellationToken2;
  635. }
  636. public T Current { get; private set; }
  637. public UniTask<bool> MoveNextAsync()
  638. {
  639. cancellationToken1.ThrowIfCancellationRequested();
  640. cancellationToken2.ThrowIfCancellationRequested();
  641. completionSource.Reset();
  642. if (unityAction == null)
  643. {
  644. unityAction = Invoke;
  645. TaskTracker.TrackActiveTask(this, 3);
  646. unityEvent.AddListener(unityAction);
  647. if (cancellationToken1.CanBeCanceled)
  648. {
  649. registration1 = cancellationToken1.RegisterWithoutCaptureExecutionContext(cancel1, this);
  650. }
  651. if (cancellationToken2.CanBeCanceled)
  652. {
  653. registration2 = cancellationToken2.RegisterWithoutCaptureExecutionContext(cancel2, this);
  654. }
  655. }
  656. return new UniTask<bool>(this, completionSource.Version);
  657. }
  658. void Invoke(T value)
  659. {
  660. Current = value;
  661. completionSource.TrySetResult(true);
  662. }
  663. static void OnCanceled1(object state)
  664. {
  665. var self = (UnityEventHandlerAsyncEnumerator)state;
  666. try
  667. {
  668. self.completionSource.TrySetCanceled(self.cancellationToken1);
  669. }
  670. finally
  671. {
  672. self.DisposeAsync().Forget();
  673. }
  674. }
  675. static void OnCanceled2(object state)
  676. {
  677. var self = (UnityEventHandlerAsyncEnumerator)state;
  678. try
  679. {
  680. self.completionSource.TrySetCanceled(self.cancellationToken2);
  681. }
  682. finally
  683. {
  684. self.DisposeAsync().Forget();
  685. }
  686. }
  687. public UniTask DisposeAsync()
  688. {
  689. if (!isDisposed)
  690. {
  691. isDisposed = true;
  692. TaskTracker.RemoveTracking(this);
  693. registration1.Dispose();
  694. registration2.Dispose();
  695. if (unityEvent is IDisposable disp)
  696. {
  697. disp.Dispose();
  698. }
  699. unityEvent.RemoveListener(unityAction);
  700. completionSource.TrySetCanceled();
  701. }
  702. return default;
  703. }
  704. }
  705. }
  706. }
  707. #endif