您不能選擇超過 %s 個話題 話題必須以字母或數字為開頭,可包含連接號 ('-') 且最長為 35 個字
 
 
 

712 行
20 KiB

  1. #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
  2. #pragma warning disable CS0436
  3. #if UNITASK_NETCORE || UNITY_2022_3_OR_NEWER
  4. #define SUPPORT_VALUETASK
  5. #endif
  6. using Cysharp.Threading.Tasks.CompilerServices;
  7. using System;
  8. using System.Diagnostics;
  9. using System.Runtime.CompilerServices;
  10. using System.Runtime.ExceptionServices;
  11. using System.Runtime.InteropServices;
  12. namespace Cysharp.Threading.Tasks
  13. {
  14. internal static class AwaiterActions
  15. {
  16. internal static readonly Action<object> InvokeContinuationDelegate = Continuation;
  17. [DebuggerHidden]
  18. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  19. static void Continuation(object state)
  20. {
  21. ((Action)state).Invoke();
  22. }
  23. }
  24. /// <summary>
  25. /// Lightweight unity specified task-like object.
  26. /// </summary>
  27. [AsyncMethodBuilder(typeof(AsyncUniTaskMethodBuilder))]
  28. [StructLayout(LayoutKind.Auto)]
  29. public readonly partial struct UniTask
  30. {
  31. readonly IUniTaskSource source;
  32. readonly short token;
  33. [DebuggerHidden]
  34. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  35. public UniTask(IUniTaskSource source, short token)
  36. {
  37. this.source = source;
  38. this.token = token;
  39. }
  40. public UniTaskStatus Status
  41. {
  42. [DebuggerHidden]
  43. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  44. get
  45. {
  46. if (source == null) return UniTaskStatus.Succeeded;
  47. return source.GetStatus(token);
  48. }
  49. }
  50. [DebuggerHidden]
  51. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  52. public Awaiter GetAwaiter()
  53. {
  54. return new Awaiter(this);
  55. }
  56. /// <summary>
  57. /// returns (bool IsCanceled) instead of throws OperationCanceledException.
  58. /// </summary>
  59. public UniTask<bool> SuppressCancellationThrow()
  60. {
  61. var status = Status;
  62. if (status == UniTaskStatus.Succeeded) return CompletedTasks.False;
  63. if (status == UniTaskStatus.Canceled) return CompletedTasks.True;
  64. return new UniTask<bool>(new IsCanceledSource(source), token);
  65. }
  66. #if SUPPORT_VALUETASK
  67. public static implicit operator System.Threading.Tasks.ValueTask(in UniTask self)
  68. {
  69. if (self.source == null)
  70. {
  71. return default;
  72. }
  73. #if (UNITASK_NETCORE && NETSTANDARD2_0)
  74. return self.AsValueTask();
  75. #else
  76. return new System.Threading.Tasks.ValueTask(self.source, self.token);
  77. #endif
  78. }
  79. #endif
  80. public override string ToString()
  81. {
  82. if (source == null) return "()";
  83. return "(" + source.UnsafeGetStatus() + ")";
  84. }
  85. /// <summary>
  86. /// Memoizing inner IValueTaskSource. The result UniTask can await multiple.
  87. /// </summary>
  88. public UniTask Preserve()
  89. {
  90. if (source == null)
  91. {
  92. return this;
  93. }
  94. else
  95. {
  96. return new UniTask(new MemoizeSource(source), token);
  97. }
  98. }
  99. public UniTask<AsyncUnit> AsAsyncUnitUniTask()
  100. {
  101. if (this.source == null) return CompletedTasks.AsyncUnit;
  102. var status = this.source.GetStatus(this.token);
  103. if (status.IsCompletedSuccessfully())
  104. {
  105. this.source.GetResult(this.token);
  106. return CompletedTasks.AsyncUnit;
  107. }
  108. else if (this.source is IUniTaskSource<AsyncUnit> asyncUnitSource)
  109. {
  110. return new UniTask<AsyncUnit>(asyncUnitSource, this.token);
  111. }
  112. return new UniTask<AsyncUnit>(new AsyncUnitSource(this.source), this.token);
  113. }
  114. sealed class AsyncUnitSource : IUniTaskSource<AsyncUnit>
  115. {
  116. readonly IUniTaskSource source;
  117. public AsyncUnitSource(IUniTaskSource source)
  118. {
  119. this.source = source;
  120. }
  121. public AsyncUnit GetResult(short token)
  122. {
  123. source.GetResult(token);
  124. return AsyncUnit.Default;
  125. }
  126. public UniTaskStatus GetStatus(short token)
  127. {
  128. return source.GetStatus(token);
  129. }
  130. public void OnCompleted(Action<object> continuation, object state, short token)
  131. {
  132. source.OnCompleted(continuation, state, token);
  133. }
  134. public UniTaskStatus UnsafeGetStatus()
  135. {
  136. return source.UnsafeGetStatus();
  137. }
  138. void IUniTaskSource.GetResult(short token)
  139. {
  140. GetResult(token);
  141. }
  142. }
  143. sealed class IsCanceledSource : IUniTaskSource<bool>
  144. {
  145. readonly IUniTaskSource source;
  146. public IsCanceledSource(IUniTaskSource source)
  147. {
  148. this.source = source;
  149. }
  150. public bool GetResult(short token)
  151. {
  152. if (source.GetStatus(token) == UniTaskStatus.Canceled)
  153. {
  154. return true;
  155. }
  156. source.GetResult(token);
  157. return false;
  158. }
  159. void IUniTaskSource.GetResult(short token)
  160. {
  161. GetResult(token);
  162. }
  163. public UniTaskStatus GetStatus(short token)
  164. {
  165. return source.GetStatus(token);
  166. }
  167. public UniTaskStatus UnsafeGetStatus()
  168. {
  169. return source.UnsafeGetStatus();
  170. }
  171. public void OnCompleted(Action<object> continuation, object state, short token)
  172. {
  173. source.OnCompleted(continuation, state, token);
  174. }
  175. }
  176. sealed class MemoizeSource : IUniTaskSource
  177. {
  178. IUniTaskSource source;
  179. ExceptionDispatchInfo exception;
  180. UniTaskStatus status;
  181. public MemoizeSource(IUniTaskSource source)
  182. {
  183. this.source = source;
  184. }
  185. public void GetResult(short token)
  186. {
  187. if (source == null)
  188. {
  189. if (exception != null)
  190. {
  191. exception.Throw();
  192. }
  193. }
  194. else
  195. {
  196. try
  197. {
  198. source.GetResult(token);
  199. status = UniTaskStatus.Succeeded;
  200. }
  201. catch (Exception ex)
  202. {
  203. exception = ExceptionDispatchInfo.Capture(ex);
  204. if (ex is OperationCanceledException)
  205. {
  206. status = UniTaskStatus.Canceled;
  207. }
  208. else
  209. {
  210. status = UniTaskStatus.Faulted;
  211. }
  212. throw;
  213. }
  214. finally
  215. {
  216. source = null;
  217. }
  218. }
  219. }
  220. public UniTaskStatus GetStatus(short token)
  221. {
  222. if (source == null)
  223. {
  224. return status;
  225. }
  226. return source.GetStatus(token);
  227. }
  228. public void OnCompleted(Action<object> continuation, object state, short token)
  229. {
  230. if (source == null)
  231. {
  232. continuation(state);
  233. }
  234. else
  235. {
  236. source.OnCompleted(continuation, state, token);
  237. }
  238. }
  239. public UniTaskStatus UnsafeGetStatus()
  240. {
  241. if (source == null)
  242. {
  243. return status;
  244. }
  245. return source.UnsafeGetStatus();
  246. }
  247. }
  248. public readonly struct Awaiter : ICriticalNotifyCompletion
  249. {
  250. readonly UniTask task;
  251. [DebuggerHidden]
  252. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  253. public Awaiter(in UniTask task)
  254. {
  255. this.task = task;
  256. }
  257. public bool IsCompleted
  258. {
  259. [DebuggerHidden]
  260. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  261. get
  262. {
  263. return task.Status.IsCompleted();
  264. }
  265. }
  266. [DebuggerHidden]
  267. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  268. public void GetResult()
  269. {
  270. if (task.source == null) return;
  271. task.source.GetResult(task.token);
  272. }
  273. [DebuggerHidden]
  274. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  275. public void OnCompleted(Action continuation)
  276. {
  277. if (task.source == null)
  278. {
  279. continuation();
  280. }
  281. else
  282. {
  283. task.source.OnCompleted(AwaiterActions.InvokeContinuationDelegate, continuation, task.token);
  284. }
  285. }
  286. [DebuggerHidden]
  287. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  288. public void UnsafeOnCompleted(Action continuation)
  289. {
  290. if (task.source == null)
  291. {
  292. continuation();
  293. }
  294. else
  295. {
  296. task.source.OnCompleted(AwaiterActions.InvokeContinuationDelegate, continuation, task.token);
  297. }
  298. }
  299. /// <summary>
  300. /// If register manually continuation, you can use it instead of for compiler OnCompleted methods.
  301. /// </summary>
  302. [DebuggerHidden]
  303. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  304. public void SourceOnCompleted(Action<object> continuation, object state)
  305. {
  306. if (task.source == null)
  307. {
  308. continuation(state);
  309. }
  310. else
  311. {
  312. task.source.OnCompleted(continuation, state, task.token);
  313. }
  314. }
  315. }
  316. }
  317. /// <summary>
  318. /// Lightweight unity specified task-like object.
  319. /// </summary>
  320. [AsyncMethodBuilder(typeof(AsyncUniTaskMethodBuilder<>))]
  321. [StructLayout(LayoutKind.Auto)]
  322. public readonly struct UniTask<T>
  323. {
  324. readonly IUniTaskSource<T> source;
  325. readonly T result;
  326. readonly short token;
  327. [DebuggerHidden]
  328. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  329. public UniTask(T result)
  330. {
  331. this.source = default;
  332. this.token = default;
  333. this.result = result;
  334. }
  335. [DebuggerHidden]
  336. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  337. public UniTask(IUniTaskSource<T> source, short token)
  338. {
  339. this.source = source;
  340. this.token = token;
  341. this.result = default;
  342. }
  343. public UniTaskStatus Status
  344. {
  345. [DebuggerHidden]
  346. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  347. get
  348. {
  349. return (source == null) ? UniTaskStatus.Succeeded : source.GetStatus(token);
  350. }
  351. }
  352. [DebuggerHidden]
  353. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  354. public Awaiter GetAwaiter()
  355. {
  356. return new Awaiter(this);
  357. }
  358. /// <summary>
  359. /// Memoizing inner IValueTaskSource. The result UniTask can await multiple.
  360. /// </summary>
  361. public UniTask<T> Preserve()
  362. {
  363. if (source == null)
  364. {
  365. return this;
  366. }
  367. else
  368. {
  369. return new UniTask<T>(new MemoizeSource(source), token);
  370. }
  371. }
  372. public UniTask AsUniTask()
  373. {
  374. if (this.source == null) return UniTask.CompletedTask;
  375. var status = this.source.GetStatus(this.token);
  376. if (status.IsCompletedSuccessfully())
  377. {
  378. this.source.GetResult(this.token);
  379. return UniTask.CompletedTask;
  380. }
  381. // Converting UniTask<T> -> UniTask is zero overhead.
  382. return new UniTask(this.source, this.token);
  383. }
  384. public static implicit operator UniTask(UniTask<T> self)
  385. {
  386. return self.AsUniTask();
  387. }
  388. #if SUPPORT_VALUETASK
  389. public static implicit operator System.Threading.Tasks.ValueTask<T>(in UniTask<T> self)
  390. {
  391. if (self.source == null)
  392. {
  393. return new System.Threading.Tasks.ValueTask<T>(self.result);
  394. }
  395. #if (UNITASK_NETCORE && NETSTANDARD2_0)
  396. return self.AsValueTask();
  397. #else
  398. return new System.Threading.Tasks.ValueTask<T>(self.source, self.token);
  399. #endif
  400. }
  401. #endif
  402. /// <summary>
  403. /// returns (bool IsCanceled, T Result) instead of throws OperationCanceledException.
  404. /// </summary>
  405. public UniTask<(bool IsCanceled, T Result)> SuppressCancellationThrow()
  406. {
  407. if (source == null)
  408. {
  409. return new UniTask<(bool IsCanceled, T Result)>((false, result));
  410. }
  411. return new UniTask<(bool, T)>(new IsCanceledSource(source), token);
  412. }
  413. public override string ToString()
  414. {
  415. return (this.source == null) ? result?.ToString()
  416. : "(" + this.source.UnsafeGetStatus() + ")";
  417. }
  418. sealed class IsCanceledSource : IUniTaskSource<(bool, T)>
  419. {
  420. readonly IUniTaskSource<T> source;
  421. [DebuggerHidden]
  422. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  423. public IsCanceledSource(IUniTaskSource<T> source)
  424. {
  425. this.source = source;
  426. }
  427. [DebuggerHidden]
  428. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  429. public (bool, T) GetResult(short token)
  430. {
  431. if (source.GetStatus(token) == UniTaskStatus.Canceled)
  432. {
  433. return (true, default);
  434. }
  435. var result = source.GetResult(token);
  436. return (false, result);
  437. }
  438. [DebuggerHidden]
  439. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  440. void IUniTaskSource.GetResult(short token)
  441. {
  442. GetResult(token);
  443. }
  444. [DebuggerHidden]
  445. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  446. public UniTaskStatus GetStatus(short token)
  447. {
  448. return source.GetStatus(token);
  449. }
  450. [DebuggerHidden]
  451. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  452. public UniTaskStatus UnsafeGetStatus()
  453. {
  454. return source.UnsafeGetStatus();
  455. }
  456. [DebuggerHidden]
  457. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  458. public void OnCompleted(Action<object> continuation, object state, short token)
  459. {
  460. source.OnCompleted(continuation, state, token);
  461. }
  462. }
  463. sealed class MemoizeSource : IUniTaskSource<T>
  464. {
  465. IUniTaskSource<T> source;
  466. T result;
  467. ExceptionDispatchInfo exception;
  468. UniTaskStatus status;
  469. public MemoizeSource(IUniTaskSource<T> source)
  470. {
  471. this.source = source;
  472. }
  473. public T GetResult(short token)
  474. {
  475. if (source == null)
  476. {
  477. if (exception != null)
  478. {
  479. exception.Throw();
  480. }
  481. return result;
  482. }
  483. else
  484. {
  485. try
  486. {
  487. result = source.GetResult(token);
  488. status = UniTaskStatus.Succeeded;
  489. return result;
  490. }
  491. catch (Exception ex)
  492. {
  493. exception = ExceptionDispatchInfo.Capture(ex);
  494. if (ex is OperationCanceledException)
  495. {
  496. status = UniTaskStatus.Canceled;
  497. }
  498. else
  499. {
  500. status = UniTaskStatus.Faulted;
  501. }
  502. throw;
  503. }
  504. finally
  505. {
  506. source = null;
  507. }
  508. }
  509. }
  510. void IUniTaskSource.GetResult(short token)
  511. {
  512. GetResult(token);
  513. }
  514. public UniTaskStatus GetStatus(short token)
  515. {
  516. if (source == null)
  517. {
  518. return status;
  519. }
  520. return source.GetStatus(token);
  521. }
  522. public void OnCompleted(Action<object> continuation, object state, short token)
  523. {
  524. if (source == null)
  525. {
  526. continuation(state);
  527. }
  528. else
  529. {
  530. source.OnCompleted(continuation, state, token);
  531. }
  532. }
  533. public UniTaskStatus UnsafeGetStatus()
  534. {
  535. if (source == null)
  536. {
  537. return status;
  538. }
  539. return source.UnsafeGetStatus();
  540. }
  541. }
  542. public readonly struct Awaiter : ICriticalNotifyCompletion
  543. {
  544. readonly UniTask<T> task;
  545. [DebuggerHidden]
  546. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  547. public Awaiter(in UniTask<T> task)
  548. {
  549. this.task = task;
  550. }
  551. public bool IsCompleted
  552. {
  553. [DebuggerHidden]
  554. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  555. get
  556. {
  557. return task.Status.IsCompleted();
  558. }
  559. }
  560. [DebuggerHidden]
  561. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  562. public T GetResult()
  563. {
  564. var s = task.source;
  565. if (s == null)
  566. {
  567. return task.result;
  568. }
  569. else
  570. {
  571. return s.GetResult(task.token);
  572. }
  573. }
  574. [DebuggerHidden]
  575. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  576. public void OnCompleted(Action continuation)
  577. {
  578. var s = task.source;
  579. if (s == null)
  580. {
  581. continuation();
  582. }
  583. else
  584. {
  585. s.OnCompleted(AwaiterActions.InvokeContinuationDelegate, continuation, task.token);
  586. }
  587. }
  588. [DebuggerHidden]
  589. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  590. public void UnsafeOnCompleted(Action continuation)
  591. {
  592. var s = task.source;
  593. if (s == null)
  594. {
  595. continuation();
  596. }
  597. else
  598. {
  599. s.OnCompleted(AwaiterActions.InvokeContinuationDelegate, continuation, task.token);
  600. }
  601. }
  602. /// <summary>
  603. /// If register manually continuation, you can use it instead of for compiler OnCompleted methods.
  604. /// </summary>
  605. [DebuggerHidden]
  606. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  607. public void SourceOnCompleted(Action<object> continuation, object state)
  608. {
  609. var s = task.source;
  610. if (s == null)
  611. {
  612. continuation(state);
  613. }
  614. else
  615. {
  616. s.OnCompleted(continuation, state, task.token);
  617. }
  618. }
  619. }
  620. }
  621. }