123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
- using System;
- using System.Threading;
- using UnityEngine;
- namespace Cysharp.Threading.Tasks.Triggers
- {
- public abstract class AsyncTriggerBase<T> : MonoBehaviour, IUniTaskAsyncEnumerable<T>
- {
- TriggerEvent<T> triggerEvent;
- internal protected bool calledAwake;
- internal protected bool calledDestroy;
- void Awake()
- {
- calledAwake = true;
- }
- void OnDestroy()
- {
- if (calledDestroy) return;
- calledDestroy = true;
- triggerEvent.SetCompleted();
- }
- internal void AddHandler(ITriggerHandler<T> handler)
- {
- if (!calledAwake)
- {
- PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, new AwakeMonitor(this));
- }
- triggerEvent.Add(handler);
- }
- internal void RemoveHandler(ITriggerHandler<T> handler)
- {
- if (!calledAwake)
- {
- PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, new AwakeMonitor(this));
- }
- triggerEvent.Remove(handler);
- }
- protected void RaiseEvent(T value)
- {
- triggerEvent.SetResult(value);
- }
- public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
- {
- return new AsyncTriggerEnumerator(this, cancellationToken);
- }
- sealed class AsyncTriggerEnumerator : MoveNextSource, IUniTaskAsyncEnumerator<T>, ITriggerHandler<T>
- {
- static Action<object> cancellationCallback = CancellationCallback;
- readonly AsyncTriggerBase<T> parent;
- CancellationToken cancellationToken;
- CancellationTokenRegistration registration;
- bool called;
- bool isDisposed;
- public AsyncTriggerEnumerator(AsyncTriggerBase<T> parent, CancellationToken cancellationToken)
- {
- this.parent = parent;
- this.cancellationToken = cancellationToken;
- }
- public void OnCanceled(CancellationToken cancellationToken = default)
- {
- completionSource.TrySetCanceled(cancellationToken);
- }
- public void OnNext(T value)
- {
- Current = value;
- completionSource.TrySetResult(true);
- }
- public void OnCompleted()
- {
- completionSource.TrySetResult(false);
- }
- public void OnError(Exception ex)
- {
- completionSource.TrySetException(ex);
- }
- static void CancellationCallback(object state)
- {
- var self = (AsyncTriggerEnumerator)state;
- self.DisposeAsync().Forget(); // sync
- self.completionSource.TrySetCanceled(self.cancellationToken);
- }
- public T Current { get; private set; }
- ITriggerHandler<T> ITriggerHandler<T>.Prev { get; set; }
- ITriggerHandler<T> ITriggerHandler<T>.Next { get; set; }
- public UniTask<bool> MoveNextAsync()
- {
- cancellationToken.ThrowIfCancellationRequested();
- completionSource.Reset();
- if (!called)
- {
- called = true;
- TaskTracker.TrackActiveTask(this, 3);
- parent.AddHandler(this);
- if (cancellationToken.CanBeCanceled)
- {
- registration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, this);
- }
- }
- return new UniTask<bool>(this, completionSource.Version);
- }
- public UniTask DisposeAsync()
- {
- if (!isDisposed)
- {
- isDisposed = true;
- TaskTracker.RemoveTracking(this);
- registration.Dispose();
- parent.RemoveHandler(this);
- }
- return default;
- }
- }
- class AwakeMonitor : IPlayerLoopItem
- {
- readonly AsyncTriggerBase<T> trigger;
- public AwakeMonitor(AsyncTriggerBase<T> trigger)
- {
- this.trigger = trigger;
- }
- public bool MoveNext()
- {
- if (trigger.calledAwake) return false;
- if (trigger == null)
- {
- trigger.OnDestroy();
- return false;
- }
- return true;
- }
- }
- }
- public interface IAsyncOneShotTrigger
- {
- UniTask OneShotAsync();
- }
- public partial class AsyncTriggerHandler<T> : IAsyncOneShotTrigger
- {
- UniTask IAsyncOneShotTrigger.OneShotAsync()
- {
- core.Reset();
- return new UniTask((IUniTaskSource)this, core.Version);
- }
- }
- public sealed partial class AsyncTriggerHandler<T> : IUniTaskSource<T>, ITriggerHandler<T>, IDisposable
- {
- static Action<object> cancellationCallback = CancellationCallback;
- readonly AsyncTriggerBase<T> trigger;
- CancellationToken cancellationToken;
- CancellationTokenRegistration registration;
- bool isDisposed;
- bool callOnce;
- UniTaskCompletionSourceCore<T> core;
- internal CancellationToken CancellationToken => cancellationToken;
- ITriggerHandler<T> ITriggerHandler<T>.Prev { get; set; }
- ITriggerHandler<T> ITriggerHandler<T>.Next { get; set; }
- internal AsyncTriggerHandler(AsyncTriggerBase<T> trigger, bool callOnce)
- {
- if (cancellationToken.IsCancellationRequested)
- {
- isDisposed = true;
- return;
- }
- this.trigger = trigger;
- this.cancellationToken = default;
- this.registration = default;
- this.callOnce = callOnce;
- trigger.AddHandler(this);
- TaskTracker.TrackActiveTask(this, 3);
- }
- internal AsyncTriggerHandler(AsyncTriggerBase<T> trigger, CancellationToken cancellationToken, bool callOnce)
- {
- if (cancellationToken.IsCancellationRequested)
- {
- isDisposed = true;
- return;
- }
- this.trigger = trigger;
- this.cancellationToken = cancellationToken;
- this.callOnce = callOnce;
- trigger.AddHandler(this);
- if (cancellationToken.CanBeCanceled)
- {
- registration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, this);
- }
- TaskTracker.TrackActiveTask(this, 3);
- }
- static void CancellationCallback(object state)
- {
- var self = (AsyncTriggerHandler<T>)state;
- self.Dispose();
- self.core.TrySetCanceled(self.cancellationToken);
- }
- public void Dispose()
- {
- if (!isDisposed)
- {
- isDisposed = true;
- TaskTracker.RemoveTracking(this);
- registration.Dispose();
- trigger.RemoveHandler(this);
- }
- }
- T IUniTaskSource<T>.GetResult(short token)
- {
- try
- {
- return core.GetResult(token);
- }
- finally
- {
- if (callOnce)
- {
- Dispose();
- }
- }
- }
- void ITriggerHandler<T>.OnNext(T value)
- {
- core.TrySetResult(value);
- }
- void ITriggerHandler<T>.OnCanceled(CancellationToken cancellationToken)
- {
- core.TrySetCanceled(cancellationToken);
- }
- void ITriggerHandler<T>.OnCompleted()
- {
- core.TrySetCanceled(CancellationToken.None);
- }
- void ITriggerHandler<T>.OnError(Exception ex)
- {
- core.TrySetException(ex);
- }
- void IUniTaskSource.GetResult(short token)
- {
- ((IUniTaskSource<T>)this).GetResult(token);
- }
- UniTaskStatus IUniTaskSource.GetStatus(short token)
- {
- return core.GetStatus(token);
- }
- UniTaskStatus IUniTaskSource.UnsafeGetStatus()
- {
- return core.UnsafeGetStatus();
- }
- void IUniTaskSource.OnCompleted(Action<object> continuation, object state, short token)
- {
- core.OnCompleted(continuation, state, token);
- }
- }
- }
|