123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- using Cysharp.Threading.Tasks.Internal;
- using System;
- using System.Collections.Generic;
- using System.Threading;
- namespace Cysharp.Threading.Tasks.Linq
- {
- public static partial class UniTaskAsyncEnumerable
- {
- public static IUniTaskAsyncEnumerable<TProperty> EveryValueChanged<TTarget, TProperty>(TTarget target, Func<TTarget, TProperty> propertySelector, PlayerLoopTiming monitorTiming = PlayerLoopTiming.Update, IEqualityComparer<TProperty> equalityComparer = null)
- where TTarget : class
- {
- var unityObject = target as UnityEngine.Object;
- var isUnityObject = target is UnityEngine.Object; // don't use (unityObject == null)
- if (isUnityObject)
- {
- return new EveryValueChangedUnityObject<TTarget, TProperty>(target, propertySelector, equalityComparer ?? UnityEqualityComparer.GetDefault<TProperty>(), monitorTiming);
- }
- else
- {
- return new EveryValueChangedStandardObject<TTarget, TProperty>(target, propertySelector, equalityComparer ?? UnityEqualityComparer.GetDefault<TProperty>(), monitorTiming);
- }
- }
- }
- internal sealed class EveryValueChangedUnityObject<TTarget, TProperty> : IUniTaskAsyncEnumerable<TProperty>
- {
- readonly TTarget target;
- readonly Func<TTarget, TProperty> propertySelector;
- readonly IEqualityComparer<TProperty> equalityComparer;
- readonly PlayerLoopTiming monitorTiming;
- public EveryValueChangedUnityObject(TTarget target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming)
- {
- this.target = target;
- this.propertySelector = propertySelector;
- this.equalityComparer = equalityComparer;
- this.monitorTiming = monitorTiming;
- }
- public IUniTaskAsyncEnumerator<TProperty> GetAsyncEnumerator(CancellationToken cancellationToken = default)
- {
- return new _EveryValueChanged(target, propertySelector, equalityComparer, monitorTiming, cancellationToken);
- }
- sealed class _EveryValueChanged : MoveNextSource, IUniTaskAsyncEnumerator<TProperty>, IPlayerLoopItem
- {
- readonly TTarget target;
- readonly UnityEngine.Object targetAsUnityObject;
- readonly IEqualityComparer<TProperty> equalityComparer;
- readonly Func<TTarget, TProperty> propertySelector;
- CancellationToken cancellationToken;
- bool first;
- TProperty currentValue;
- bool disposed;
- public _EveryValueChanged(TTarget target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming, CancellationToken cancellationToken)
- {
- this.target = target;
- this.targetAsUnityObject = target as UnityEngine.Object;
- this.propertySelector = propertySelector;
- this.equalityComparer = equalityComparer;
- this.cancellationToken = cancellationToken;
- this.first = true;
- TaskTracker.TrackActiveTask(this, 2);
- PlayerLoopHelper.AddAction(monitorTiming, this);
- }
- public TProperty Current => currentValue;
- public UniTask<bool> MoveNextAsync()
- {
- // return false instead of throw
- if (disposed || cancellationToken.IsCancellationRequested) return CompletedTasks.False;
- if (first)
- {
- first = false;
- if (targetAsUnityObject == null)
- {
- return CompletedTasks.False;
- }
- this.currentValue = propertySelector(target);
- return CompletedTasks.True;
- }
- completionSource.Reset();
- return new UniTask<bool>(this, completionSource.Version);
- }
- public UniTask DisposeAsync()
- {
- if (!disposed)
- {
- disposed = true;
- TaskTracker.RemoveTracking(this);
- }
- return default;
- }
- public bool MoveNext()
- {
- if (disposed || cancellationToken.IsCancellationRequested || targetAsUnityObject == null) // destroyed = cancel.
- {
- completionSource.TrySetResult(false);
- DisposeAsync().Forget();
- return false;
- }
- TProperty nextValue = default(TProperty);
- try
- {
- nextValue = propertySelector(target);
- if (equalityComparer.Equals(currentValue, nextValue))
- {
- return true;
- }
- }
- catch (Exception ex)
- {
- completionSource.TrySetException(ex);
- DisposeAsync().Forget();
- return false;
- }
- currentValue = nextValue;
- completionSource.TrySetResult(true);
- return true;
- }
- }
- }
- internal sealed class EveryValueChangedStandardObject<TTarget, TProperty> : IUniTaskAsyncEnumerable<TProperty>
- where TTarget : class
- {
- readonly WeakReference<TTarget> target;
- readonly Func<TTarget, TProperty> propertySelector;
- readonly IEqualityComparer<TProperty> equalityComparer;
- readonly PlayerLoopTiming monitorTiming;
- public EveryValueChangedStandardObject(TTarget target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming)
- {
- this.target = new WeakReference<TTarget>(target, false);
- this.propertySelector = propertySelector;
- this.equalityComparer = equalityComparer;
- this.monitorTiming = monitorTiming;
- }
- public IUniTaskAsyncEnumerator<TProperty> GetAsyncEnumerator(CancellationToken cancellationToken = default)
- {
- return new _EveryValueChanged(target, propertySelector, equalityComparer, monitorTiming, cancellationToken);
- }
- sealed class _EveryValueChanged : MoveNextSource, IUniTaskAsyncEnumerator<TProperty>, IPlayerLoopItem
- {
- readonly WeakReference<TTarget> target;
- readonly IEqualityComparer<TProperty> equalityComparer;
- readonly Func<TTarget, TProperty> propertySelector;
- CancellationToken cancellationToken;
- bool first;
- TProperty currentValue;
- bool disposed;
- public _EveryValueChanged(WeakReference<TTarget> target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming, CancellationToken cancellationToken)
- {
- this.target = target;
- this.propertySelector = propertySelector;
- this.equalityComparer = equalityComparer;
- this.cancellationToken = cancellationToken;
- this.first = true;
- TaskTracker.TrackActiveTask(this, 2);
- PlayerLoopHelper.AddAction(monitorTiming, this);
- }
- public TProperty Current => currentValue;
- public UniTask<bool> MoveNextAsync()
- {
- if (disposed || cancellationToken.IsCancellationRequested) return CompletedTasks.False;
- if (first)
- {
- first = false;
- if (!target.TryGetTarget(out var t))
- {
- return CompletedTasks.False;
- }
- this.currentValue = propertySelector(t);
- return CompletedTasks.True;
- }
- completionSource.Reset();
- return new UniTask<bool>(this, completionSource.Version);
- }
- public UniTask DisposeAsync()
- {
- if (!disposed)
- {
- disposed = true;
- TaskTracker.RemoveTracking(this);
- }
- return default;
- }
- public bool MoveNext()
- {
- if (disposed || cancellationToken.IsCancellationRequested || !target.TryGetTarget(out var t))
- {
- completionSource.TrySetResult(false);
- DisposeAsync().Forget();
- return false;
- }
- TProperty nextValue = default(TProperty);
- try
- {
- nextValue = propertySelector(t);
- if (equalityComparer.Equals(currentValue, nextValue))
- {
- return true;
- }
- }
- catch (Exception ex)
- {
- completionSource.TrySetException(ex);
- DisposeAsync().Forget();
- return false;
- }
- currentValue = nextValue;
- completionSource.TrySetResult(true);
- return true;
- }
- }
- }
- }
|