UniTaskExtensions.cs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921
  1. #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
  2. using System;
  3. using System.Collections;
  4. using System.Runtime.ExceptionServices;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. using Cysharp.Threading.Tasks.Internal;
  8. namespace Cysharp.Threading.Tasks
  9. {
  10. public static partial class UniTaskExtensions
  11. {
  12. /// <summary>
  13. /// Convert Task[T] -> UniTask[T].
  14. /// </summary>
  15. public static UniTask<T> AsUniTask<T>(this Task<T> task, bool useCurrentSynchronizationContext = true)
  16. {
  17. var promise = new UniTaskCompletionSource<T>();
  18. task.ContinueWith((x, state) =>
  19. {
  20. var p = (UniTaskCompletionSource<T>)state;
  21. switch (x.Status)
  22. {
  23. case TaskStatus.Canceled:
  24. p.TrySetCanceled();
  25. break;
  26. case TaskStatus.Faulted:
  27. p.TrySetException(x.Exception);
  28. break;
  29. case TaskStatus.RanToCompletion:
  30. p.TrySetResult(x.Result);
  31. break;
  32. default:
  33. throw new NotSupportedException();
  34. }
  35. }, promise, useCurrentSynchronizationContext ? TaskScheduler.FromCurrentSynchronizationContext() : TaskScheduler.Current);
  36. return promise.Task;
  37. }
  38. /// <summary>
  39. /// Convert Task -> UniTask.
  40. /// </summary>
  41. public static UniTask AsUniTask(this Task task, bool useCurrentSynchronizationContext = true)
  42. {
  43. var promise = new UniTaskCompletionSource();
  44. task.ContinueWith((x, state) =>
  45. {
  46. var p = (UniTaskCompletionSource)state;
  47. switch (x.Status)
  48. {
  49. case TaskStatus.Canceled:
  50. p.TrySetCanceled();
  51. break;
  52. case TaskStatus.Faulted:
  53. p.TrySetException(x.Exception);
  54. break;
  55. case TaskStatus.RanToCompletion:
  56. p.TrySetResult();
  57. break;
  58. default:
  59. throw new NotSupportedException();
  60. }
  61. }, promise, useCurrentSynchronizationContext ? TaskScheduler.FromCurrentSynchronizationContext() : TaskScheduler.Current);
  62. return promise.Task;
  63. }
  64. public static Task<T> AsTask<T>(this UniTask<T> task)
  65. {
  66. try
  67. {
  68. UniTask<T>.Awaiter awaiter;
  69. try
  70. {
  71. awaiter = task.GetAwaiter();
  72. }
  73. catch (Exception ex)
  74. {
  75. return Task.FromException<T>(ex);
  76. }
  77. if (awaiter.IsCompleted)
  78. {
  79. try
  80. {
  81. var result = awaiter.GetResult();
  82. return Task.FromResult(result);
  83. }
  84. catch (Exception ex)
  85. {
  86. return Task.FromException<T>(ex);
  87. }
  88. }
  89. var tcs = new TaskCompletionSource<T>();
  90. awaiter.SourceOnCompleted(state =>
  91. {
  92. using (var tuple = (StateTuple<TaskCompletionSource<T>, UniTask<T>.Awaiter>)state)
  93. {
  94. var (inTcs, inAwaiter) = tuple;
  95. try
  96. {
  97. var result = inAwaiter.GetResult();
  98. inTcs.SetResult(result);
  99. }
  100. catch (Exception ex)
  101. {
  102. inTcs.SetException(ex);
  103. }
  104. }
  105. }, StateTuple.Create(tcs, awaiter));
  106. return tcs.Task;
  107. }
  108. catch (Exception ex)
  109. {
  110. return Task.FromException<T>(ex);
  111. }
  112. }
  113. public static Task AsTask(this UniTask task)
  114. {
  115. try
  116. {
  117. UniTask.Awaiter awaiter;
  118. try
  119. {
  120. awaiter = task.GetAwaiter();
  121. }
  122. catch (Exception ex)
  123. {
  124. return Task.FromException(ex);
  125. }
  126. if (awaiter.IsCompleted)
  127. {
  128. try
  129. {
  130. awaiter.GetResult(); // check token valid on Succeeded
  131. return Task.CompletedTask;
  132. }
  133. catch (Exception ex)
  134. {
  135. return Task.FromException(ex);
  136. }
  137. }
  138. var tcs = new TaskCompletionSource<object>();
  139. awaiter.SourceOnCompleted(state =>
  140. {
  141. using (var tuple = (StateTuple<TaskCompletionSource<object>, UniTask.Awaiter>)state)
  142. {
  143. var (inTcs, inAwaiter) = tuple;
  144. try
  145. {
  146. inAwaiter.GetResult();
  147. inTcs.SetResult(null);
  148. }
  149. catch (Exception ex)
  150. {
  151. inTcs.SetException(ex);
  152. }
  153. }
  154. }, StateTuple.Create(tcs, awaiter));
  155. return tcs.Task;
  156. }
  157. catch (Exception ex)
  158. {
  159. return Task.FromException(ex);
  160. }
  161. }
  162. public static AsyncLazy ToAsyncLazy(this UniTask task)
  163. {
  164. return new AsyncLazy(task);
  165. }
  166. public static AsyncLazy<T> ToAsyncLazy<T>(this UniTask<T> task)
  167. {
  168. return new AsyncLazy<T>(task);
  169. }
  170. /// <summary>
  171. /// Ignore task result when cancel raised first.
  172. /// </summary>
  173. public static UniTask AttachExternalCancellation(this UniTask task, CancellationToken cancellationToken)
  174. {
  175. if (!cancellationToken.CanBeCanceled)
  176. {
  177. return task;
  178. }
  179. if (cancellationToken.IsCancellationRequested)
  180. {
  181. return UniTask.FromCanceled(cancellationToken);
  182. }
  183. if (task.Status.IsCompleted())
  184. {
  185. return task;
  186. }
  187. return new UniTask(new AttachExternalCancellationSource(task, cancellationToken), 0);
  188. }
  189. /// <summary>
  190. /// Ignore task result when cancel raised first.
  191. /// </summary>
  192. public static UniTask<T> AttachExternalCancellation<T>(this UniTask<T> task, CancellationToken cancellationToken)
  193. {
  194. if (!cancellationToken.CanBeCanceled)
  195. {
  196. return task;
  197. }
  198. if (cancellationToken.IsCancellationRequested)
  199. {
  200. return UniTask.FromCanceled<T>(cancellationToken);
  201. }
  202. if (task.Status.IsCompleted())
  203. {
  204. return task;
  205. }
  206. return new UniTask<T>(new AttachExternalCancellationSource<T>(task, cancellationToken), 0);
  207. }
  208. sealed class AttachExternalCancellationSource : IUniTaskSource
  209. {
  210. static readonly Action<object> cancellationCallbackDelegate = CancellationCallback;
  211. CancellationToken cancellationToken;
  212. CancellationTokenRegistration tokenRegistration;
  213. UniTaskCompletionSourceCore<AsyncUnit> core;
  214. public AttachExternalCancellationSource(UniTask task, CancellationToken cancellationToken)
  215. {
  216. this.cancellationToken = cancellationToken;
  217. this.tokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallbackDelegate, this);
  218. RunTask(task).Forget();
  219. }
  220. async UniTaskVoid RunTask(UniTask task)
  221. {
  222. try
  223. {
  224. await task;
  225. core.TrySetResult(AsyncUnit.Default);
  226. }
  227. catch (Exception ex)
  228. {
  229. core.TrySetException(ex);
  230. }
  231. finally
  232. {
  233. tokenRegistration.Dispose();
  234. }
  235. }
  236. static void CancellationCallback(object state)
  237. {
  238. var self = (AttachExternalCancellationSource)state;
  239. self.core.TrySetCanceled(self.cancellationToken);
  240. }
  241. public void GetResult(short token)
  242. {
  243. core.GetResult(token);
  244. }
  245. public UniTaskStatus GetStatus(short token)
  246. {
  247. return core.GetStatus(token);
  248. }
  249. public void OnCompleted(Action<object> continuation, object state, short token)
  250. {
  251. core.OnCompleted(continuation, state, token);
  252. }
  253. public UniTaskStatus UnsafeGetStatus()
  254. {
  255. return core.UnsafeGetStatus();
  256. }
  257. }
  258. sealed class AttachExternalCancellationSource<T> : IUniTaskSource<T>
  259. {
  260. static readonly Action<object> cancellationCallbackDelegate = CancellationCallback;
  261. CancellationToken cancellationToken;
  262. CancellationTokenRegistration tokenRegistration;
  263. UniTaskCompletionSourceCore<T> core;
  264. public AttachExternalCancellationSource(UniTask<T> task, CancellationToken cancellationToken)
  265. {
  266. this.cancellationToken = cancellationToken;
  267. this.tokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallbackDelegate, this);
  268. RunTask(task).Forget();
  269. }
  270. async UniTaskVoid RunTask(UniTask<T> task)
  271. {
  272. try
  273. {
  274. core.TrySetResult(await task);
  275. }
  276. catch (Exception ex)
  277. {
  278. core.TrySetException(ex);
  279. }
  280. finally
  281. {
  282. tokenRegistration.Dispose();
  283. }
  284. }
  285. static void CancellationCallback(object state)
  286. {
  287. var self = (AttachExternalCancellationSource<T>)state;
  288. self.core.TrySetCanceled(self.cancellationToken);
  289. }
  290. void IUniTaskSource.GetResult(short token)
  291. {
  292. core.GetResult(token);
  293. }
  294. public T GetResult(short token)
  295. {
  296. return core.GetResult(token);
  297. }
  298. public UniTaskStatus GetStatus(short token)
  299. {
  300. return core.GetStatus(token);
  301. }
  302. public void OnCompleted(Action<object> continuation, object state, short token)
  303. {
  304. core.OnCompleted(continuation, state, token);
  305. }
  306. public UniTaskStatus UnsafeGetStatus()
  307. {
  308. return core.UnsafeGetStatus();
  309. }
  310. }
  311. #if UNITY_2018_3_OR_NEWER
  312. public static IEnumerator ToCoroutine<T>(this UniTask<T> task, Action<T> resultHandler = null, Action<Exception> exceptionHandler = null)
  313. {
  314. return new ToCoroutineEnumerator<T>(task, resultHandler, exceptionHandler);
  315. }
  316. public static IEnumerator ToCoroutine(this UniTask task, Action<Exception> exceptionHandler = null)
  317. {
  318. return new ToCoroutineEnumerator(task, exceptionHandler);
  319. }
  320. public static async UniTask Timeout(this UniTask task, TimeSpan timeout, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming timeoutCheckTiming = PlayerLoopTiming.Update, CancellationTokenSource taskCancellationTokenSource = null)
  321. {
  322. var delayCancellationTokenSource = new CancellationTokenSource();
  323. var timeoutTask = UniTask.Delay(timeout, delayType, timeoutCheckTiming, delayCancellationTokenSource.Token).SuppressCancellationThrow();
  324. int winArgIndex;
  325. bool taskResultIsCanceled;
  326. try
  327. {
  328. (winArgIndex, taskResultIsCanceled, _) = await UniTask.WhenAny(task.SuppressCancellationThrow(), timeoutTask);
  329. }
  330. catch
  331. {
  332. delayCancellationTokenSource.Cancel();
  333. delayCancellationTokenSource.Dispose();
  334. throw;
  335. }
  336. // timeout
  337. if (winArgIndex == 1)
  338. {
  339. if (taskCancellationTokenSource != null)
  340. {
  341. taskCancellationTokenSource.Cancel();
  342. taskCancellationTokenSource.Dispose();
  343. }
  344. throw new TimeoutException("Exceed Timeout:" + timeout);
  345. }
  346. else
  347. {
  348. delayCancellationTokenSource.Cancel();
  349. delayCancellationTokenSource.Dispose();
  350. }
  351. if (taskResultIsCanceled)
  352. {
  353. Error.ThrowOperationCanceledException();
  354. }
  355. }
  356. public static async UniTask<T> Timeout<T>(this UniTask<T> task, TimeSpan timeout, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming timeoutCheckTiming = PlayerLoopTiming.Update, CancellationTokenSource taskCancellationTokenSource = null)
  357. {
  358. var delayCancellationTokenSource = new CancellationTokenSource();
  359. var timeoutTask = UniTask.Delay(timeout, delayType, timeoutCheckTiming, delayCancellationTokenSource.Token).SuppressCancellationThrow();
  360. int winArgIndex;
  361. (bool IsCanceled, T Result) taskResult;
  362. try
  363. {
  364. (winArgIndex, taskResult, _) = await UniTask.WhenAny(task.SuppressCancellationThrow(), timeoutTask);
  365. }
  366. catch
  367. {
  368. delayCancellationTokenSource.Cancel();
  369. delayCancellationTokenSource.Dispose();
  370. throw;
  371. }
  372. // timeout
  373. if (winArgIndex == 1)
  374. {
  375. if (taskCancellationTokenSource != null)
  376. {
  377. taskCancellationTokenSource.Cancel();
  378. taskCancellationTokenSource.Dispose();
  379. }
  380. throw new TimeoutException("Exceed Timeout:" + timeout);
  381. }
  382. else
  383. {
  384. delayCancellationTokenSource.Cancel();
  385. delayCancellationTokenSource.Dispose();
  386. }
  387. if (taskResult.IsCanceled)
  388. {
  389. Error.ThrowOperationCanceledException();
  390. }
  391. return taskResult.Result;
  392. }
  393. /// <summary>
  394. /// Timeout with suppress OperationCanceledException. Returns (bool, IsCacneled).
  395. /// </summary>
  396. public static async UniTask<bool> TimeoutWithoutException(this UniTask task, TimeSpan timeout, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming timeoutCheckTiming = PlayerLoopTiming.Update, CancellationTokenSource taskCancellationTokenSource = null)
  397. {
  398. var delayCancellationTokenSource = new CancellationTokenSource();
  399. var timeoutTask = UniTask.Delay(timeout, delayType, timeoutCheckTiming, delayCancellationTokenSource.Token).SuppressCancellationThrow();
  400. int winArgIndex;
  401. bool taskResultIsCanceled;
  402. try
  403. {
  404. (winArgIndex, taskResultIsCanceled, _) = await UniTask.WhenAny(task.SuppressCancellationThrow(), timeoutTask);
  405. }
  406. catch
  407. {
  408. delayCancellationTokenSource.Cancel();
  409. delayCancellationTokenSource.Dispose();
  410. return true;
  411. }
  412. // timeout
  413. if (winArgIndex == 1)
  414. {
  415. if (taskCancellationTokenSource != null)
  416. {
  417. taskCancellationTokenSource.Cancel();
  418. taskCancellationTokenSource.Dispose();
  419. }
  420. return true;
  421. }
  422. else
  423. {
  424. delayCancellationTokenSource.Cancel();
  425. delayCancellationTokenSource.Dispose();
  426. }
  427. if (taskResultIsCanceled)
  428. {
  429. return true;
  430. }
  431. return false;
  432. }
  433. /// <summary>
  434. /// Timeout with suppress OperationCanceledException. Returns (bool IsTimeout, T Result).
  435. /// </summary>
  436. public static async UniTask<(bool IsTimeout, T Result)> TimeoutWithoutException<T>(this UniTask<T> task, TimeSpan timeout, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming timeoutCheckTiming = PlayerLoopTiming.Update, CancellationTokenSource taskCancellationTokenSource = null)
  437. {
  438. var delayCancellationTokenSource = new CancellationTokenSource();
  439. var timeoutTask = UniTask.Delay(timeout, delayType, timeoutCheckTiming, delayCancellationTokenSource.Token).SuppressCancellationThrow();
  440. int winArgIndex;
  441. (bool IsCanceled, T Result) taskResult;
  442. try
  443. {
  444. (winArgIndex, taskResult, _) = await UniTask.WhenAny(task.SuppressCancellationThrow(), timeoutTask);
  445. }
  446. catch
  447. {
  448. delayCancellationTokenSource.Cancel();
  449. delayCancellationTokenSource.Dispose();
  450. return (true, default);
  451. }
  452. // timeout
  453. if (winArgIndex == 1)
  454. {
  455. if (taskCancellationTokenSource != null)
  456. {
  457. taskCancellationTokenSource.Cancel();
  458. taskCancellationTokenSource.Dispose();
  459. }
  460. return (true, default);
  461. }
  462. else
  463. {
  464. delayCancellationTokenSource.Cancel();
  465. delayCancellationTokenSource.Dispose();
  466. }
  467. if (taskResult.IsCanceled)
  468. {
  469. return (true, default);
  470. }
  471. return (false, taskResult.Result);
  472. }
  473. #endif
  474. public static void Forget(this UniTask task)
  475. {
  476. var awaiter = task.GetAwaiter();
  477. if (awaiter.IsCompleted)
  478. {
  479. try
  480. {
  481. awaiter.GetResult();
  482. }
  483. catch (Exception ex)
  484. {
  485. UniTaskScheduler.PublishUnobservedTaskException(ex);
  486. }
  487. }
  488. else
  489. {
  490. awaiter.SourceOnCompleted(state =>
  491. {
  492. using (var t = (StateTuple<UniTask.Awaiter>)state)
  493. {
  494. try
  495. {
  496. t.Item1.GetResult();
  497. }
  498. catch (Exception ex)
  499. {
  500. UniTaskScheduler.PublishUnobservedTaskException(ex);
  501. }
  502. }
  503. }, StateTuple.Create(awaiter));
  504. }
  505. }
  506. public static void Forget(this UniTask task, Action<Exception> exceptionHandler, bool handleExceptionOnMainThread = true)
  507. {
  508. if (exceptionHandler == null)
  509. {
  510. Forget(task);
  511. }
  512. else
  513. {
  514. ForgetCoreWithCatch(task, exceptionHandler, handleExceptionOnMainThread).Forget();
  515. }
  516. }
  517. static async UniTaskVoid ForgetCoreWithCatch(UniTask task, Action<Exception> exceptionHandler, bool handleExceptionOnMainThread)
  518. {
  519. try
  520. {
  521. await task;
  522. }
  523. catch (Exception ex)
  524. {
  525. try
  526. {
  527. if (handleExceptionOnMainThread)
  528. {
  529. #if UNITY_2018_3_OR_NEWER
  530. await UniTask.SwitchToMainThread();
  531. #endif
  532. }
  533. exceptionHandler(ex);
  534. }
  535. catch (Exception ex2)
  536. {
  537. UniTaskScheduler.PublishUnobservedTaskException(ex2);
  538. }
  539. }
  540. }
  541. public static void Forget<T>(this UniTask<T> task)
  542. {
  543. var awaiter = task.GetAwaiter();
  544. if (awaiter.IsCompleted)
  545. {
  546. try
  547. {
  548. awaiter.GetResult();
  549. }
  550. catch (Exception ex)
  551. {
  552. UniTaskScheduler.PublishUnobservedTaskException(ex);
  553. }
  554. }
  555. else
  556. {
  557. awaiter.SourceOnCompleted(state =>
  558. {
  559. using (var t = (StateTuple<UniTask<T>.Awaiter>)state)
  560. {
  561. try
  562. {
  563. t.Item1.GetResult();
  564. }
  565. catch (Exception ex)
  566. {
  567. UniTaskScheduler.PublishUnobservedTaskException(ex);
  568. }
  569. }
  570. }, StateTuple.Create(awaiter));
  571. }
  572. }
  573. public static void Forget<T>(this UniTask<T> task, Action<Exception> exceptionHandler, bool handleExceptionOnMainThread = true)
  574. {
  575. if (exceptionHandler == null)
  576. {
  577. task.Forget();
  578. }
  579. else
  580. {
  581. ForgetCoreWithCatch(task, exceptionHandler, handleExceptionOnMainThread).Forget();
  582. }
  583. }
  584. static async UniTaskVoid ForgetCoreWithCatch<T>(UniTask<T> task, Action<Exception> exceptionHandler, bool handleExceptionOnMainThread)
  585. {
  586. try
  587. {
  588. await task;
  589. }
  590. catch (Exception ex)
  591. {
  592. try
  593. {
  594. if (handleExceptionOnMainThread)
  595. {
  596. #if UNITY_2018_3_OR_NEWER
  597. await UniTask.SwitchToMainThread();
  598. #endif
  599. }
  600. exceptionHandler(ex);
  601. }
  602. catch (Exception ex2)
  603. {
  604. UniTaskScheduler.PublishUnobservedTaskException(ex2);
  605. }
  606. }
  607. }
  608. public static async UniTask ContinueWith<T>(this UniTask<T> task, Action<T> continuationFunction)
  609. {
  610. continuationFunction(await task);
  611. }
  612. public static async UniTask ContinueWith<T>(this UniTask<T> task, Func<T, UniTask> continuationFunction)
  613. {
  614. await continuationFunction(await task);
  615. }
  616. public static async UniTask<TR> ContinueWith<T, TR>(this UniTask<T> task, Func<T, TR> continuationFunction)
  617. {
  618. return continuationFunction(await task);
  619. }
  620. public static async UniTask<TR> ContinueWith<T, TR>(this UniTask<T> task, Func<T, UniTask<TR>> continuationFunction)
  621. {
  622. return await continuationFunction(await task);
  623. }
  624. public static async UniTask ContinueWith(this UniTask task, Action continuationFunction)
  625. {
  626. await task;
  627. continuationFunction();
  628. }
  629. public static async UniTask ContinueWith(this UniTask task, Func<UniTask> continuationFunction)
  630. {
  631. await task;
  632. await continuationFunction();
  633. }
  634. public static async UniTask<T> ContinueWith<T>(this UniTask task, Func<T> continuationFunction)
  635. {
  636. await task;
  637. return continuationFunction();
  638. }
  639. public static async UniTask<T> ContinueWith<T>(this UniTask task, Func<UniTask<T>> continuationFunction)
  640. {
  641. await task;
  642. return await continuationFunction();
  643. }
  644. public static async UniTask<T> Unwrap<T>(this UniTask<UniTask<T>> task)
  645. {
  646. return await await task;
  647. }
  648. public static async UniTask Unwrap(this UniTask<UniTask> task)
  649. {
  650. await await task;
  651. }
  652. public static async UniTask<T> Unwrap<T>(this Task<UniTask<T>> task)
  653. {
  654. return await await task;
  655. }
  656. public static async UniTask<T> Unwrap<T>(this Task<UniTask<T>> task, bool continueOnCapturedContext)
  657. {
  658. return await await task.ConfigureAwait(continueOnCapturedContext);
  659. }
  660. public static async UniTask Unwrap(this Task<UniTask> task)
  661. {
  662. await await task;
  663. }
  664. public static async UniTask Unwrap(this Task<UniTask> task, bool continueOnCapturedContext)
  665. {
  666. await await task.ConfigureAwait(continueOnCapturedContext);
  667. }
  668. public static async UniTask<T> Unwrap<T>(this UniTask<Task<T>> task)
  669. {
  670. return await await task;
  671. }
  672. public static async UniTask<T> Unwrap<T>(this UniTask<Task<T>> task, bool continueOnCapturedContext)
  673. {
  674. return await (await task).ConfigureAwait(continueOnCapturedContext);
  675. }
  676. public static async UniTask Unwrap(this UniTask<Task> task)
  677. {
  678. await await task;
  679. }
  680. public static async UniTask Unwrap(this UniTask<Task> task, bool continueOnCapturedContext)
  681. {
  682. await (await task).ConfigureAwait(continueOnCapturedContext);
  683. }
  684. #if UNITY_2018_3_OR_NEWER
  685. sealed class ToCoroutineEnumerator : IEnumerator
  686. {
  687. bool completed;
  688. UniTask task;
  689. Action<Exception> exceptionHandler = null;
  690. bool isStarted = false;
  691. ExceptionDispatchInfo exception;
  692. public ToCoroutineEnumerator(UniTask task, Action<Exception> exceptionHandler)
  693. {
  694. completed = false;
  695. this.exceptionHandler = exceptionHandler;
  696. this.task = task;
  697. }
  698. async UniTaskVoid RunTask(UniTask task)
  699. {
  700. try
  701. {
  702. await task;
  703. }
  704. catch (Exception ex)
  705. {
  706. if (exceptionHandler != null)
  707. {
  708. exceptionHandler(ex);
  709. }
  710. else
  711. {
  712. this.exception = ExceptionDispatchInfo.Capture(ex);
  713. }
  714. }
  715. finally
  716. {
  717. completed = true;
  718. }
  719. }
  720. public object Current => null;
  721. public bool MoveNext()
  722. {
  723. if (!isStarted)
  724. {
  725. isStarted = true;
  726. RunTask(task).Forget();
  727. }
  728. if (exception != null)
  729. {
  730. exception.Throw();
  731. return false;
  732. }
  733. return !completed;
  734. }
  735. void IEnumerator.Reset()
  736. {
  737. }
  738. }
  739. sealed class ToCoroutineEnumerator<T> : IEnumerator
  740. {
  741. bool completed;
  742. Action<T> resultHandler = null;
  743. Action<Exception> exceptionHandler = null;
  744. bool isStarted = false;
  745. UniTask<T> task;
  746. object current = null;
  747. ExceptionDispatchInfo exception;
  748. public ToCoroutineEnumerator(UniTask<T> task, Action<T> resultHandler, Action<Exception> exceptionHandler)
  749. {
  750. completed = false;
  751. this.task = task;
  752. this.resultHandler = resultHandler;
  753. this.exceptionHandler = exceptionHandler;
  754. }
  755. async UniTaskVoid RunTask(UniTask<T> task)
  756. {
  757. try
  758. {
  759. var value = await task;
  760. current = value; // boxed if T is struct...
  761. if (resultHandler != null)
  762. {
  763. resultHandler(value);
  764. }
  765. }
  766. catch (Exception ex)
  767. {
  768. if (exceptionHandler != null)
  769. {
  770. exceptionHandler(ex);
  771. }
  772. else
  773. {
  774. this.exception = ExceptionDispatchInfo.Capture(ex);
  775. }
  776. }
  777. finally
  778. {
  779. completed = true;
  780. }
  781. }
  782. public object Current => current;
  783. public bool MoveNext()
  784. {
  785. if (!isStarted)
  786. {
  787. isStarted = true;
  788. RunTask(task).Forget();
  789. }
  790. if (exception != null)
  791. {
  792. exception.Throw();
  793. return false;
  794. }
  795. return !completed;
  796. }
  797. void IEnumerator.Reset()
  798. {
  799. }
  800. }
  801. #endif
  802. }
  803. }