Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 

924 lignes
29 KiB

  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.InnerException ?? 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.InnerException ?? 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. task.Forget();
  182. return UniTask.FromCanceled(cancellationToken);
  183. }
  184. if (task.Status.IsCompleted())
  185. {
  186. return task;
  187. }
  188. return new UniTask(new AttachExternalCancellationSource(task, cancellationToken), 0);
  189. }
  190. /// <summary>
  191. /// Ignore task result when cancel raised first.
  192. /// </summary>
  193. public static UniTask<T> AttachExternalCancellation<T>(this UniTask<T> task, CancellationToken cancellationToken)
  194. {
  195. if (!cancellationToken.CanBeCanceled)
  196. {
  197. return task;
  198. }
  199. if (cancellationToken.IsCancellationRequested)
  200. {
  201. task.Forget();
  202. return UniTask.FromCanceled<T>(cancellationToken);
  203. }
  204. if (task.Status.IsCompleted())
  205. {
  206. return task;
  207. }
  208. return new UniTask<T>(new AttachExternalCancellationSource<T>(task, cancellationToken), 0);
  209. }
  210. sealed class AttachExternalCancellationSource : IUniTaskSource
  211. {
  212. static readonly Action<object> cancellationCallbackDelegate = CancellationCallback;
  213. CancellationToken cancellationToken;
  214. CancellationTokenRegistration tokenRegistration;
  215. UniTaskCompletionSourceCore<AsyncUnit> core;
  216. public AttachExternalCancellationSource(UniTask task, CancellationToken cancellationToken)
  217. {
  218. this.cancellationToken = cancellationToken;
  219. this.tokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallbackDelegate, this);
  220. RunTask(task).Forget();
  221. }
  222. async UniTaskVoid RunTask(UniTask task)
  223. {
  224. try
  225. {
  226. await task;
  227. core.TrySetResult(AsyncUnit.Default);
  228. }
  229. catch (Exception ex)
  230. {
  231. core.TrySetException(ex);
  232. }
  233. finally
  234. {
  235. tokenRegistration.Dispose();
  236. }
  237. }
  238. static void CancellationCallback(object state)
  239. {
  240. var self = (AttachExternalCancellationSource)state;
  241. self.core.TrySetCanceled(self.cancellationToken);
  242. }
  243. public void GetResult(short token)
  244. {
  245. core.GetResult(token);
  246. }
  247. public UniTaskStatus GetStatus(short token)
  248. {
  249. return core.GetStatus(token);
  250. }
  251. public void OnCompleted(Action<object> continuation, object state, short token)
  252. {
  253. core.OnCompleted(continuation, state, token);
  254. }
  255. public UniTaskStatus UnsafeGetStatus()
  256. {
  257. return core.UnsafeGetStatus();
  258. }
  259. }
  260. sealed class AttachExternalCancellationSource<T> : IUniTaskSource<T>
  261. {
  262. static readonly Action<object> cancellationCallbackDelegate = CancellationCallback;
  263. CancellationToken cancellationToken;
  264. CancellationTokenRegistration tokenRegistration;
  265. UniTaskCompletionSourceCore<T> core;
  266. public AttachExternalCancellationSource(UniTask<T> task, CancellationToken cancellationToken)
  267. {
  268. this.cancellationToken = cancellationToken;
  269. this.tokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallbackDelegate, this);
  270. RunTask(task).Forget();
  271. }
  272. async UniTaskVoid RunTask(UniTask<T> task)
  273. {
  274. try
  275. {
  276. core.TrySetResult(await task);
  277. }
  278. catch (Exception ex)
  279. {
  280. core.TrySetException(ex);
  281. }
  282. finally
  283. {
  284. tokenRegistration.Dispose();
  285. }
  286. }
  287. static void CancellationCallback(object state)
  288. {
  289. var self = (AttachExternalCancellationSource<T>)state;
  290. self.core.TrySetCanceled(self.cancellationToken);
  291. }
  292. void IUniTaskSource.GetResult(short token)
  293. {
  294. core.GetResult(token);
  295. }
  296. public T GetResult(short token)
  297. {
  298. return core.GetResult(token);
  299. }
  300. public UniTaskStatus GetStatus(short token)
  301. {
  302. return core.GetStatus(token);
  303. }
  304. public void OnCompleted(Action<object> continuation, object state, short token)
  305. {
  306. core.OnCompleted(continuation, state, token);
  307. }
  308. public UniTaskStatus UnsafeGetStatus()
  309. {
  310. return core.UnsafeGetStatus();
  311. }
  312. }
  313. #if UNITY_2018_3_OR_NEWER
  314. public static IEnumerator ToCoroutine<T>(this UniTask<T> task, Action<T> resultHandler = null, Action<Exception> exceptionHandler = null)
  315. {
  316. return new ToCoroutineEnumerator<T>(task, resultHandler, exceptionHandler);
  317. }
  318. public static IEnumerator ToCoroutine(this UniTask task, Action<Exception> exceptionHandler = null)
  319. {
  320. return new ToCoroutineEnumerator(task, exceptionHandler);
  321. }
  322. public static async UniTask Timeout(this UniTask task, TimeSpan timeout, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming timeoutCheckTiming = PlayerLoopTiming.Update, CancellationTokenSource taskCancellationTokenSource = null)
  323. {
  324. var delayCancellationTokenSource = new CancellationTokenSource();
  325. var timeoutTask = UniTask.Delay(timeout, delayType, timeoutCheckTiming, delayCancellationTokenSource.Token).SuppressCancellationThrow();
  326. int winArgIndex;
  327. bool taskResultIsCanceled;
  328. try
  329. {
  330. (winArgIndex, taskResultIsCanceled, _) = await UniTask.WhenAny(task.SuppressCancellationThrow(), timeoutTask);
  331. }
  332. catch
  333. {
  334. delayCancellationTokenSource.Cancel();
  335. delayCancellationTokenSource.Dispose();
  336. throw;
  337. }
  338. // timeout
  339. if (winArgIndex == 1)
  340. {
  341. if (taskCancellationTokenSource != null)
  342. {
  343. taskCancellationTokenSource.Cancel();
  344. taskCancellationTokenSource.Dispose();
  345. }
  346. throw new TimeoutException("Exceed Timeout:" + timeout);
  347. }
  348. else
  349. {
  350. delayCancellationTokenSource.Cancel();
  351. delayCancellationTokenSource.Dispose();
  352. }
  353. if (taskResultIsCanceled)
  354. {
  355. Error.ThrowOperationCanceledException();
  356. }
  357. }
  358. public static async UniTask<T> Timeout<T>(this UniTask<T> task, TimeSpan timeout, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming timeoutCheckTiming = PlayerLoopTiming.Update, CancellationTokenSource taskCancellationTokenSource = null)
  359. {
  360. var delayCancellationTokenSource = new CancellationTokenSource();
  361. var timeoutTask = UniTask.Delay(timeout, delayType, timeoutCheckTiming, delayCancellationTokenSource.Token).SuppressCancellationThrow();
  362. int winArgIndex;
  363. (bool IsCanceled, T Result) taskResult;
  364. try
  365. {
  366. (winArgIndex, taskResult, _) = await UniTask.WhenAny(task.SuppressCancellationThrow(), timeoutTask);
  367. }
  368. catch
  369. {
  370. delayCancellationTokenSource.Cancel();
  371. delayCancellationTokenSource.Dispose();
  372. throw;
  373. }
  374. // timeout
  375. if (winArgIndex == 1)
  376. {
  377. if (taskCancellationTokenSource != null)
  378. {
  379. taskCancellationTokenSource.Cancel();
  380. taskCancellationTokenSource.Dispose();
  381. }
  382. throw new TimeoutException("Exceed Timeout:" + timeout);
  383. }
  384. else
  385. {
  386. delayCancellationTokenSource.Cancel();
  387. delayCancellationTokenSource.Dispose();
  388. }
  389. if (taskResult.IsCanceled)
  390. {
  391. Error.ThrowOperationCanceledException();
  392. }
  393. return taskResult.Result;
  394. }
  395. /// <summary>
  396. /// Timeout with suppress OperationCanceledException. Returns (bool, IsCanceled).
  397. /// </summary>
  398. public static async UniTask<bool> TimeoutWithoutException(this UniTask task, TimeSpan timeout, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming timeoutCheckTiming = PlayerLoopTiming.Update, CancellationTokenSource taskCancellationTokenSource = null)
  399. {
  400. var delayCancellationTokenSource = new CancellationTokenSource();
  401. var timeoutTask = UniTask.Delay(timeout, delayType, timeoutCheckTiming, delayCancellationTokenSource.Token).SuppressCancellationThrow();
  402. int winArgIndex;
  403. bool taskResultIsCanceled;
  404. try
  405. {
  406. (winArgIndex, taskResultIsCanceled, _) = await UniTask.WhenAny(task.SuppressCancellationThrow(), timeoutTask);
  407. }
  408. catch
  409. {
  410. delayCancellationTokenSource.Cancel();
  411. delayCancellationTokenSource.Dispose();
  412. return true;
  413. }
  414. // timeout
  415. if (winArgIndex == 1)
  416. {
  417. if (taskCancellationTokenSource != null)
  418. {
  419. taskCancellationTokenSource.Cancel();
  420. taskCancellationTokenSource.Dispose();
  421. }
  422. return true;
  423. }
  424. else
  425. {
  426. delayCancellationTokenSource.Cancel();
  427. delayCancellationTokenSource.Dispose();
  428. }
  429. if (taskResultIsCanceled)
  430. {
  431. return true;
  432. }
  433. return false;
  434. }
  435. /// <summary>
  436. /// Timeout with suppress OperationCanceledException. Returns (bool IsTimeout, T Result).
  437. /// </summary>
  438. 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)
  439. {
  440. var delayCancellationTokenSource = new CancellationTokenSource();
  441. var timeoutTask = UniTask.Delay(timeout, delayType, timeoutCheckTiming, delayCancellationTokenSource.Token).SuppressCancellationThrow();
  442. int winArgIndex;
  443. (bool IsCanceled, T Result) taskResult;
  444. try
  445. {
  446. (winArgIndex, taskResult, _) = await UniTask.WhenAny(task.SuppressCancellationThrow(), timeoutTask);
  447. }
  448. catch
  449. {
  450. delayCancellationTokenSource.Cancel();
  451. delayCancellationTokenSource.Dispose();
  452. return (true, default);
  453. }
  454. // timeout
  455. if (winArgIndex == 1)
  456. {
  457. if (taskCancellationTokenSource != null)
  458. {
  459. taskCancellationTokenSource.Cancel();
  460. taskCancellationTokenSource.Dispose();
  461. }
  462. return (true, default);
  463. }
  464. else
  465. {
  466. delayCancellationTokenSource.Cancel();
  467. delayCancellationTokenSource.Dispose();
  468. }
  469. if (taskResult.IsCanceled)
  470. {
  471. return (true, default);
  472. }
  473. return (false, taskResult.Result);
  474. }
  475. #endif
  476. public static void Forget(this UniTask task)
  477. {
  478. var awaiter = task.GetAwaiter();
  479. if (awaiter.IsCompleted)
  480. {
  481. try
  482. {
  483. awaiter.GetResult();
  484. }
  485. catch (Exception ex)
  486. {
  487. UniTaskScheduler.PublishUnobservedTaskException(ex);
  488. }
  489. }
  490. else
  491. {
  492. awaiter.SourceOnCompleted(state =>
  493. {
  494. using (var t = (StateTuple<UniTask.Awaiter>)state)
  495. {
  496. try
  497. {
  498. t.Item1.GetResult();
  499. }
  500. catch (Exception ex)
  501. {
  502. UniTaskScheduler.PublishUnobservedTaskException(ex);
  503. }
  504. }
  505. }, StateTuple.Create(awaiter));
  506. }
  507. }
  508. public static void Forget(this UniTask task, Action<Exception> exceptionHandler, bool handleExceptionOnMainThread = true)
  509. {
  510. if (exceptionHandler == null)
  511. {
  512. Forget(task);
  513. }
  514. else
  515. {
  516. ForgetCoreWithCatch(task, exceptionHandler, handleExceptionOnMainThread).Forget();
  517. }
  518. }
  519. static async UniTaskVoid ForgetCoreWithCatch(UniTask task, Action<Exception> exceptionHandler, bool handleExceptionOnMainThread)
  520. {
  521. try
  522. {
  523. await task;
  524. }
  525. catch (Exception ex)
  526. {
  527. try
  528. {
  529. if (handleExceptionOnMainThread)
  530. {
  531. #if UNITY_2018_3_OR_NEWER
  532. await UniTask.SwitchToMainThread();
  533. #endif
  534. }
  535. exceptionHandler(ex);
  536. }
  537. catch (Exception ex2)
  538. {
  539. UniTaskScheduler.PublishUnobservedTaskException(ex2);
  540. }
  541. }
  542. }
  543. public static void Forget<T>(this UniTask<T> task)
  544. {
  545. var awaiter = task.GetAwaiter();
  546. if (awaiter.IsCompleted)
  547. {
  548. try
  549. {
  550. awaiter.GetResult();
  551. }
  552. catch (Exception ex)
  553. {
  554. UniTaskScheduler.PublishUnobservedTaskException(ex);
  555. }
  556. }
  557. else
  558. {
  559. awaiter.SourceOnCompleted(state =>
  560. {
  561. using (var t = (StateTuple<UniTask<T>.Awaiter>)state)
  562. {
  563. try
  564. {
  565. t.Item1.GetResult();
  566. }
  567. catch (Exception ex)
  568. {
  569. UniTaskScheduler.PublishUnobservedTaskException(ex);
  570. }
  571. }
  572. }, StateTuple.Create(awaiter));
  573. }
  574. }
  575. public static void Forget<T>(this UniTask<T> task, Action<Exception> exceptionHandler, bool handleExceptionOnMainThread = true)
  576. {
  577. if (exceptionHandler == null)
  578. {
  579. task.Forget();
  580. }
  581. else
  582. {
  583. ForgetCoreWithCatch(task, exceptionHandler, handleExceptionOnMainThread).Forget();
  584. }
  585. }
  586. static async UniTaskVoid ForgetCoreWithCatch<T>(UniTask<T> task, Action<Exception> exceptionHandler, bool handleExceptionOnMainThread)
  587. {
  588. try
  589. {
  590. await task;
  591. }
  592. catch (Exception ex)
  593. {
  594. try
  595. {
  596. if (handleExceptionOnMainThread)
  597. {
  598. #if UNITY_2018_3_OR_NEWER
  599. await UniTask.SwitchToMainThread();
  600. #endif
  601. }
  602. exceptionHandler(ex);
  603. }
  604. catch (Exception ex2)
  605. {
  606. UniTaskScheduler.PublishUnobservedTaskException(ex2);
  607. }
  608. }
  609. }
  610. public static async UniTask ContinueWith<T>(this UniTask<T> task, Action<T> continuationFunction)
  611. {
  612. continuationFunction(await task);
  613. }
  614. public static async UniTask ContinueWith<T>(this UniTask<T> task, Func<T, UniTask> continuationFunction)
  615. {
  616. await continuationFunction(await task);
  617. }
  618. public static async UniTask<TR> ContinueWith<T, TR>(this UniTask<T> task, Func<T, TR> continuationFunction)
  619. {
  620. return continuationFunction(await task);
  621. }
  622. public static async UniTask<TR> ContinueWith<T, TR>(this UniTask<T> task, Func<T, UniTask<TR>> continuationFunction)
  623. {
  624. return await continuationFunction(await task);
  625. }
  626. public static async UniTask ContinueWith(this UniTask task, Action continuationFunction)
  627. {
  628. await task;
  629. continuationFunction();
  630. }
  631. public static async UniTask ContinueWith(this UniTask task, Func<UniTask> continuationFunction)
  632. {
  633. await task;
  634. await continuationFunction();
  635. }
  636. public static async UniTask<T> ContinueWith<T>(this UniTask task, Func<T> continuationFunction)
  637. {
  638. await task;
  639. return continuationFunction();
  640. }
  641. public static async UniTask<T> ContinueWith<T>(this UniTask task, Func<UniTask<T>> continuationFunction)
  642. {
  643. await task;
  644. return await continuationFunction();
  645. }
  646. public static async UniTask<T> Unwrap<T>(this UniTask<UniTask<T>> task)
  647. {
  648. return await await task;
  649. }
  650. public static async UniTask Unwrap(this UniTask<UniTask> task)
  651. {
  652. await await task;
  653. }
  654. public static async UniTask<T> Unwrap<T>(this Task<UniTask<T>> task)
  655. {
  656. return await await task;
  657. }
  658. public static async UniTask<T> Unwrap<T>(this Task<UniTask<T>> task, bool continueOnCapturedContext)
  659. {
  660. return await await task.ConfigureAwait(continueOnCapturedContext);
  661. }
  662. public static async UniTask Unwrap(this Task<UniTask> task)
  663. {
  664. await await task;
  665. }
  666. public static async UniTask Unwrap(this Task<UniTask> task, bool continueOnCapturedContext)
  667. {
  668. await await task.ConfigureAwait(continueOnCapturedContext);
  669. }
  670. public static async UniTask<T> Unwrap<T>(this UniTask<Task<T>> task)
  671. {
  672. return await await task;
  673. }
  674. public static async UniTask<T> Unwrap<T>(this UniTask<Task<T>> task, bool continueOnCapturedContext)
  675. {
  676. return await (await task).ConfigureAwait(continueOnCapturedContext);
  677. }
  678. public static async UniTask Unwrap(this UniTask<Task> task)
  679. {
  680. await await task;
  681. }
  682. public static async UniTask Unwrap(this UniTask<Task> task, bool continueOnCapturedContext)
  683. {
  684. await (await task).ConfigureAwait(continueOnCapturedContext);
  685. }
  686. #if UNITY_2018_3_OR_NEWER
  687. sealed class ToCoroutineEnumerator : IEnumerator
  688. {
  689. bool completed;
  690. UniTask task;
  691. Action<Exception> exceptionHandler = null;
  692. bool isStarted = false;
  693. ExceptionDispatchInfo exception;
  694. public ToCoroutineEnumerator(UniTask task, Action<Exception> exceptionHandler)
  695. {
  696. completed = false;
  697. this.exceptionHandler = exceptionHandler;
  698. this.task = task;
  699. }
  700. async UniTaskVoid RunTask(UniTask task)
  701. {
  702. try
  703. {
  704. await task;
  705. }
  706. catch (Exception ex)
  707. {
  708. if (exceptionHandler != null)
  709. {
  710. exceptionHandler(ex);
  711. }
  712. else
  713. {
  714. this.exception = ExceptionDispatchInfo.Capture(ex);
  715. }
  716. }
  717. finally
  718. {
  719. completed = true;
  720. }
  721. }
  722. public object Current => null;
  723. public bool MoveNext()
  724. {
  725. if (!isStarted)
  726. {
  727. isStarted = true;
  728. RunTask(task).Forget();
  729. }
  730. if (exception != null)
  731. {
  732. exception.Throw();
  733. return false;
  734. }
  735. return !completed;
  736. }
  737. void IEnumerator.Reset()
  738. {
  739. }
  740. }
  741. sealed class ToCoroutineEnumerator<T> : IEnumerator
  742. {
  743. bool completed;
  744. Action<T> resultHandler = null;
  745. Action<Exception> exceptionHandler = null;
  746. bool isStarted = false;
  747. UniTask<T> task;
  748. object current = null;
  749. ExceptionDispatchInfo exception;
  750. public ToCoroutineEnumerator(UniTask<T> task, Action<T> resultHandler, Action<Exception> exceptionHandler)
  751. {
  752. completed = false;
  753. this.task = task;
  754. this.resultHandler = resultHandler;
  755. this.exceptionHandler = exceptionHandler;
  756. }
  757. async UniTaskVoid RunTask(UniTask<T> task)
  758. {
  759. try
  760. {
  761. var value = await task;
  762. current = value; // boxed if T is struct...
  763. if (resultHandler != null)
  764. {
  765. resultHandler(value);
  766. }
  767. }
  768. catch (Exception ex)
  769. {
  770. if (exceptionHandler != null)
  771. {
  772. exceptionHandler(ex);
  773. }
  774. else
  775. {
  776. this.exception = ExceptionDispatchInfo.Capture(ex);
  777. }
  778. }
  779. finally
  780. {
  781. completed = true;
  782. }
  783. }
  784. public object Current => current;
  785. public bool MoveNext()
  786. {
  787. if (!isStarted)
  788. {
  789. isStarted = true;
  790. RunTask(task).Forget();
  791. }
  792. if (exception != null)
  793. {
  794. exception.Throw();
  795. return false;
  796. }
  797. return !completed;
  798. }
  799. void IEnumerator.Reset()
  800. {
  801. }
  802. }
  803. #endif
  804. }
  805. }