AsyncOperationBaseExtensions.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. using System;
  2. using YooAsset;
  3. using static Cysharp.Threading.Tasks.Internal.Error;
  4. namespace Cysharp.Threading.Tasks
  5. {
  6. public static class AsyncOperationBaseExtensions
  7. {
  8. public static UniTask.Awaiter GetAwaiter(this AsyncOperationBase handle)
  9. {
  10. return ToUniTask(handle).GetAwaiter();
  11. }
  12. public static UniTask ToUniTask(this AsyncOperationBase handle,
  13. IProgress<float> progress = null,
  14. PlayerLoopTiming timing = PlayerLoopTiming.Update)
  15. {
  16. ThrowArgumentNullException(handle, nameof(handle));
  17. if(handle.IsDone)
  18. {
  19. return UniTask.CompletedTask;
  20. }
  21. return new UniTask(
  22. AsyncOperationBaserConfiguredSource.Create(
  23. handle,
  24. timing,
  25. progress,
  26. out var token
  27. ),
  28. token
  29. );
  30. }
  31. sealed class AsyncOperationBaserConfiguredSource : IUniTaskSource,
  32. IPlayerLoopItem,
  33. ITaskPoolNode<AsyncOperationBaserConfiguredSource>
  34. {
  35. private static TaskPool<AsyncOperationBaserConfiguredSource> pool;
  36. private AsyncOperationBaserConfiguredSource nextNode;
  37. public ref AsyncOperationBaserConfiguredSource NextNode => ref nextNode;
  38. static AsyncOperationBaserConfiguredSource()
  39. {
  40. TaskPool.RegisterSizeGetter(typeof(AsyncOperationBaserConfiguredSource), () => pool.Size);
  41. }
  42. private readonly Action<AsyncOperationBase> continuationAction;
  43. private AsyncOperationBase handle;
  44. private IProgress<float> progress;
  45. private bool completed;
  46. private UniTaskCompletionSourceCore<AsyncUnit> core;
  47. AsyncOperationBaserConfiguredSource() { continuationAction = Continuation; }
  48. public static IUniTaskSource Create(AsyncOperationBase handle,
  49. PlayerLoopTiming timing,
  50. IProgress<float> progress,
  51. out short token)
  52. {
  53. if(!pool.TryPop(out var result))
  54. {
  55. result = new AsyncOperationBaserConfiguredSource();
  56. }
  57. result.handle = handle;
  58. result.progress = progress;
  59. result.completed = false;
  60. TaskTracker.TrackActiveTask(result, 3);
  61. if(progress != null)
  62. {
  63. PlayerLoopHelper.AddAction(timing, result);
  64. }
  65. handle.Completed += result.continuationAction;
  66. token = result.core.Version;
  67. return result;
  68. }
  69. private void Continuation(AsyncOperationBase _)
  70. {
  71. handle.Completed -= continuationAction;
  72. if(completed)
  73. {
  74. TryReturn();
  75. }
  76. else
  77. {
  78. completed = true;
  79. if(handle.Status == EOperationStatus.Failed)
  80. {
  81. core.TrySetException(new Exception(handle.Error));
  82. }
  83. else
  84. {
  85. core.TrySetResult(AsyncUnit.Default);
  86. }
  87. }
  88. }
  89. bool TryReturn()
  90. {
  91. TaskTracker.RemoveTracking(this);
  92. core.Reset();
  93. handle = default;
  94. progress = default;
  95. return pool.TryPush(this);
  96. }
  97. public UniTaskStatus GetStatus(short token) => core.GetStatus(token);
  98. public void OnCompleted(Action<object> continuation, object state, short token)
  99. {
  100. core.OnCompleted(continuation, state, token);
  101. }
  102. public void GetResult(short token) { core.GetResult(token); }
  103. public UniTaskStatus UnsafeGetStatus() => core.UnsafeGetStatus();
  104. public bool MoveNext()
  105. {
  106. if(completed)
  107. {
  108. TryReturn();
  109. return false;
  110. }
  111. if(!handle.IsDone)
  112. {
  113. progress?.Report(handle.Progress);
  114. }
  115. return true;
  116. }
  117. }
  118. }
  119. }