MotionConfiguredSourceBase.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. using System;
  2. using System.Threading;
  3. namespace LitMotion
  4. {
  5. internal abstract class MotionConfiguredSourceBase
  6. {
  7. public MotionConfiguredSourceBase()
  8. {
  9. onCancelCallbackDelegate = OnCancelCallbackDelegate;
  10. onCompleteCallbackDelegate = OnCompleteCallbackDelegate;
  11. }
  12. readonly Action onCancelCallbackDelegate;
  13. readonly Action onCompleteCallbackDelegate;
  14. MotionHandle motionHandle;
  15. CancelBehaviour cancelBehaviour;
  16. CancellationToken cancellationToken;
  17. CancellationTokenRegistration cancellationRegistration;
  18. bool canceled;
  19. Action originalCompleteAction;
  20. Action originalCancelAction;
  21. protected abstract void SetTaskCanceled(CancellationToken cancellationToken);
  22. protected abstract void SetTaskCompleted();
  23. protected void OnCancelCallbackDelegate()
  24. {
  25. if (cancellationToken.IsCancellationRequested)
  26. {
  27. if (cancelBehaviour is CancelBehaviour.CancelAndCancelAwait or CancelBehaviour.CompleteAndCancelAwait or CancelBehaviour.CancelAwait)
  28. {
  29. canceled = true;
  30. }
  31. }
  32. originalCancelAction?.Invoke();
  33. SetTaskCanceled(cancellationToken);
  34. }
  35. protected void OnCompleteCallbackDelegate()
  36. {
  37. if (cancellationToken.IsCancellationRequested)
  38. {
  39. if (cancelBehaviour is CancelBehaviour.CancelAndCancelAwait or CancelBehaviour.CompleteAndCancelAwait or CancelBehaviour.CancelAwait)
  40. {
  41. canceled = true;
  42. }
  43. }
  44. originalCompleteAction?.Invoke();
  45. if (canceled)
  46. {
  47. SetTaskCanceled(cancellationToken);
  48. }
  49. else
  50. {
  51. SetTaskCompleted();
  52. }
  53. }
  54. protected static void OnCanceledTokenReceived(MotionHandle motionHandle, CancelBehaviour cancelBehaviour)
  55. {
  56. switch (cancelBehaviour)
  57. {
  58. case CancelBehaviour.Cancel:
  59. case CancelBehaviour.CancelAndCancelAwait:
  60. motionHandle.Cancel();
  61. break;
  62. case CancelBehaviour.Complete:
  63. case CancelBehaviour.CompleteAndCancelAwait:
  64. motionHandle.Complete();
  65. break;
  66. }
  67. }
  68. protected void Initialize(MotionHandle motionHandle, CancelBehaviour cancelBehaviour, CancellationToken cancellationToken)
  69. {
  70. this.motionHandle = motionHandle;
  71. this.cancelBehaviour = cancelBehaviour;
  72. this.cancellationToken = cancellationToken;
  73. ref var callbackData = ref MotionStorageManager.GetMotionCallbackDataRef(motionHandle);
  74. originalCancelAction = callbackData.OnCancelAction;
  75. originalCompleteAction = callbackData.OnCompleteAction;
  76. callbackData.OnCancelAction = onCancelCallbackDelegate;
  77. callbackData.OnCompleteAction = onCompleteCallbackDelegate;
  78. if (originalCancelAction == onCancelCallbackDelegate)
  79. {
  80. originalCancelAction = null;
  81. }
  82. if (originalCompleteAction == onCompleteCallbackDelegate)
  83. {
  84. originalCompleteAction = null;
  85. }
  86. if (cancellationToken.CanBeCanceled)
  87. {
  88. cancellationRegistration = RegisterWithoutCaptureExecutionContext(cancellationToken, static x =>
  89. {
  90. var source = (MotionConfiguredSourceBase)x;
  91. switch (source.cancelBehaviour)
  92. {
  93. default:
  94. case CancelBehaviour.CancelAndCancelAwait:
  95. source.canceled = true;
  96. source.motionHandle.Cancel();
  97. break;
  98. case CancelBehaviour.Cancel:
  99. source.motionHandle.Cancel();
  100. break;
  101. case CancelBehaviour.CompleteAndCancelAwait:
  102. source.canceled = true;
  103. source.motionHandle.Complete();
  104. break;
  105. case CancelBehaviour.Complete:
  106. source.motionHandle.Complete();
  107. break;
  108. case CancelBehaviour.CancelAwait:
  109. source.RestoreOriginalCallback();
  110. source.SetTaskCanceled(source.cancellationToken);
  111. break;
  112. }
  113. }, this);
  114. }
  115. }
  116. protected void ResetFields()
  117. {
  118. motionHandle = default;
  119. cancelBehaviour = default;
  120. cancellationToken = default;
  121. originalCompleteAction = default;
  122. originalCancelAction = default;
  123. canceled = default;
  124. }
  125. protected void RestoreOriginalCallback()
  126. {
  127. if (!motionHandle.IsActive()) return;
  128. ref var callbackData = ref MotionStorageManager.GetMotionCallbackDataRef(motionHandle);
  129. callbackData.OnCancelAction = originalCancelAction;
  130. callbackData.OnCompleteAction = originalCompleteAction;
  131. }
  132. protected void DisposeRegistration()
  133. {
  134. cancellationRegistration.Dispose();
  135. }
  136. static CancellationTokenRegistration RegisterWithoutCaptureExecutionContext(CancellationToken cancellationToken, Action<object> callback, object state)
  137. {
  138. bool flag = false;
  139. if (!ExecutionContext.IsFlowSuppressed())
  140. {
  141. ExecutionContext.SuppressFlow();
  142. flag = true;
  143. }
  144. try
  145. {
  146. return cancellationToken.Register(callback, state, useSynchronizationContext: false);
  147. }
  148. finally
  149. {
  150. if (flag)
  151. {
  152. ExecutionContext.RestoreFlow();
  153. }
  154. }
  155. }
  156. }
  157. }