Add cancel immediate flag

master
hadashiA 2023-10-26 18:11:25 +09:00
parent 6f5d818544
commit 3f042c8886
8 changed files with 375 additions and 110 deletions

View File

@ -4,38 +4,50 @@ namespace Cysharp.Threading.Tasks.Linq
{ {
public static partial class UniTaskAsyncEnumerable public static partial class UniTaskAsyncEnumerable
{ {
public static IUniTaskAsyncEnumerable<AsyncUnit> EveryUpdate(PlayerLoopTiming updateTiming = PlayerLoopTiming.Update) public static IUniTaskAsyncEnumerable<AsyncUnit> EveryUpdate(PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool cancelImmediately = false)
{ {
return new EveryUpdate(updateTiming); return new EveryUpdate(updateTiming, cancelImmediately);
} }
} }
internal class EveryUpdate : IUniTaskAsyncEnumerable<AsyncUnit> internal class EveryUpdate : IUniTaskAsyncEnumerable<AsyncUnit>
{ {
readonly PlayerLoopTiming updateTiming; readonly PlayerLoopTiming updateTiming;
readonly bool cancelImmediately;
public EveryUpdate(PlayerLoopTiming updateTiming) public EveryUpdate(PlayerLoopTiming updateTiming, bool cancelImmediately)
{ {
this.updateTiming = updateTiming; this.updateTiming = updateTiming;
this.cancelImmediately = cancelImmediately;
} }
public IUniTaskAsyncEnumerator<AsyncUnit> GetAsyncEnumerator(CancellationToken cancellationToken = default) public IUniTaskAsyncEnumerator<AsyncUnit> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{ {
return new _EveryUpdate(updateTiming, cancellationToken); return new _EveryUpdate(updateTiming, cancellationToken, cancelImmediately);
} }
class _EveryUpdate : MoveNextSource, IUniTaskAsyncEnumerator<AsyncUnit>, IPlayerLoopItem class _EveryUpdate : MoveNextSource, IUniTaskAsyncEnumerator<AsyncUnit>, IPlayerLoopItem
{ {
readonly PlayerLoopTiming updateTiming; readonly PlayerLoopTiming updateTiming;
CancellationToken cancellationToken; readonly CancellationToken cancellationToken;
readonly CancellationTokenRegistration cancellationTokenRegistration;
bool disposed; bool disposed;
public _EveryUpdate(PlayerLoopTiming updateTiming, CancellationToken cancellationToken) public _EveryUpdate(PlayerLoopTiming updateTiming, CancellationToken cancellationToken, bool cancelImmediately)
{ {
this.updateTiming = updateTiming; this.updateTiming = updateTiming;
this.cancellationToken = cancellationToken; this.cancellationToken = cancellationToken;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var source = (_EveryUpdate)state;
source.completionSource.TrySetCanceled(source.cancellationToken);
}, this);
}
TaskTracker.TrackActiveTask(this, 2); TaskTracker.TrackActiveTask(this, 2);
PlayerLoopHelper.AddAction(updateTiming, this); PlayerLoopHelper.AddAction(updateTiming, this);
} }
@ -55,6 +67,7 @@ namespace Cysharp.Threading.Tasks.Linq
{ {
if (!disposed) if (!disposed)
{ {
cancellationTokenRegistration.Dispose();
disposed = true; disposed = true;
TaskTracker.RemoveTracking(this); TaskTracker.RemoveTracking(this);
} }

View File

@ -7,7 +7,7 @@ namespace Cysharp.Threading.Tasks.Linq
{ {
public static partial class UniTaskAsyncEnumerable 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) public static IUniTaskAsyncEnumerable<TProperty> EveryValueChanged<TTarget, TProperty>(TTarget target, Func<TTarget, TProperty> propertySelector, PlayerLoopTiming monitorTiming = PlayerLoopTiming.Update, IEqualityComparer<TProperty> equalityComparer = null, bool cancelImmediately = false)
where TTarget : class where TTarget : class
{ {
var unityObject = target as UnityEngine.Object; var unityObject = target as UnityEngine.Object;
@ -15,11 +15,11 @@ namespace Cysharp.Threading.Tasks.Linq
if (isUnityObject) if (isUnityObject)
{ {
return new EveryValueChangedUnityObject<TTarget, TProperty>(target, propertySelector, equalityComparer ?? UnityEqualityComparer.GetDefault<TProperty>(), monitorTiming); return new EveryValueChangedUnityObject<TTarget, TProperty>(target, propertySelector, equalityComparer ?? UnityEqualityComparer.GetDefault<TProperty>(), monitorTiming, cancelImmediately);
} }
else else
{ {
return new EveryValueChangedStandardObject<TTarget, TProperty>(target, propertySelector, equalityComparer ?? UnityEqualityComparer.GetDefault<TProperty>(), monitorTiming); return new EveryValueChangedStandardObject<TTarget, TProperty>(target, propertySelector, equalityComparer ?? UnityEqualityComparer.GetDefault<TProperty>(), monitorTiming, cancelImmediately);
} }
} }
} }
@ -30,18 +30,20 @@ namespace Cysharp.Threading.Tasks.Linq
readonly Func<TTarget, TProperty> propertySelector; readonly Func<TTarget, TProperty> propertySelector;
readonly IEqualityComparer<TProperty> equalityComparer; readonly IEqualityComparer<TProperty> equalityComparer;
readonly PlayerLoopTiming monitorTiming; readonly PlayerLoopTiming monitorTiming;
readonly bool cancelImmediately;
public EveryValueChangedUnityObject(TTarget target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming) public EveryValueChangedUnityObject(TTarget target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming, bool cancelImmediately)
{ {
this.target = target; this.target = target;
this.propertySelector = propertySelector; this.propertySelector = propertySelector;
this.equalityComparer = equalityComparer; this.equalityComparer = equalityComparer;
this.monitorTiming = monitorTiming; this.monitorTiming = monitorTiming;
this.cancelImmediately = cancelImmediately;
} }
public IUniTaskAsyncEnumerator<TProperty> GetAsyncEnumerator(CancellationToken cancellationToken = default) public IUniTaskAsyncEnumerator<TProperty> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{ {
return new _EveryValueChanged(target, propertySelector, equalityComparer, monitorTiming, cancellationToken); return new _EveryValueChanged(target, propertySelector, equalityComparer, monitorTiming, cancellationToken, cancelImmediately);
} }
sealed class _EveryValueChanged : MoveNextSource, IUniTaskAsyncEnumerator<TProperty>, IPlayerLoopItem sealed class _EveryValueChanged : MoveNextSource, IUniTaskAsyncEnumerator<TProperty>, IPlayerLoopItem
@ -50,13 +52,14 @@ namespace Cysharp.Threading.Tasks.Linq
readonly UnityEngine.Object targetAsUnityObject; readonly UnityEngine.Object targetAsUnityObject;
readonly IEqualityComparer<TProperty> equalityComparer; readonly IEqualityComparer<TProperty> equalityComparer;
readonly Func<TTarget, TProperty> propertySelector; readonly Func<TTarget, TProperty> propertySelector;
CancellationToken cancellationToken; readonly CancellationToken cancellationToken;
readonly CancellationTokenRegistration cancellationTokenRegistration;
bool first; bool first;
TProperty currentValue; TProperty currentValue;
bool disposed; bool disposed;
public _EveryValueChanged(TTarget target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming, CancellationToken cancellationToken) public _EveryValueChanged(TTarget target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming, CancellationToken cancellationToken, bool cancelImmediately)
{ {
this.target = target; this.target = target;
this.targetAsUnityObject = target as UnityEngine.Object; this.targetAsUnityObject = target as UnityEngine.Object;
@ -64,6 +67,16 @@ namespace Cysharp.Threading.Tasks.Linq
this.equalityComparer = equalityComparer; this.equalityComparer = equalityComparer;
this.cancellationToken = cancellationToken; this.cancellationToken = cancellationToken;
this.first = true; this.first = true;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var source = (_EveryValueChanged)state;
source.completionSource.TrySetCanceled(source.cancellationToken);
}, this);
}
TaskTracker.TrackActiveTask(this, 2); TaskTracker.TrackActiveTask(this, 2);
PlayerLoopHelper.AddAction(monitorTiming, this); PlayerLoopHelper.AddAction(monitorTiming, this);
} }
@ -139,18 +152,20 @@ namespace Cysharp.Threading.Tasks.Linq
readonly Func<TTarget, TProperty> propertySelector; readonly Func<TTarget, TProperty> propertySelector;
readonly IEqualityComparer<TProperty> equalityComparer; readonly IEqualityComparer<TProperty> equalityComparer;
readonly PlayerLoopTiming monitorTiming; readonly PlayerLoopTiming monitorTiming;
readonly bool cancelImmediately;
public EveryValueChangedStandardObject(TTarget target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming) public EveryValueChangedStandardObject(TTarget target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming, bool cancelImmediately)
{ {
this.target = new WeakReference<TTarget>(target, false); this.target = new WeakReference<TTarget>(target, false);
this.propertySelector = propertySelector; this.propertySelector = propertySelector;
this.equalityComparer = equalityComparer; this.equalityComparer = equalityComparer;
this.monitorTiming = monitorTiming; this.monitorTiming = monitorTiming;
this.cancelImmediately = cancelImmediately;
} }
public IUniTaskAsyncEnumerator<TProperty> GetAsyncEnumerator(CancellationToken cancellationToken = default) public IUniTaskAsyncEnumerator<TProperty> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{ {
return new _EveryValueChanged(target, propertySelector, equalityComparer, monitorTiming, cancellationToken); return new _EveryValueChanged(target, propertySelector, equalityComparer, monitorTiming, cancellationToken, cancelImmediately);
} }
sealed class _EveryValueChanged : MoveNextSource, IUniTaskAsyncEnumerator<TProperty>, IPlayerLoopItem sealed class _EveryValueChanged : MoveNextSource, IUniTaskAsyncEnumerator<TProperty>, IPlayerLoopItem
@ -158,19 +173,30 @@ namespace Cysharp.Threading.Tasks.Linq
readonly WeakReference<TTarget> target; readonly WeakReference<TTarget> target;
readonly IEqualityComparer<TProperty> equalityComparer; readonly IEqualityComparer<TProperty> equalityComparer;
readonly Func<TTarget, TProperty> propertySelector; readonly Func<TTarget, TProperty> propertySelector;
CancellationToken cancellationToken; readonly CancellationToken cancellationToken;
readonly CancellationTokenRegistration cancellationTokenRegistration;
bool first; bool first;
TProperty currentValue; TProperty currentValue;
bool disposed; bool disposed;
public _EveryValueChanged(WeakReference<TTarget> target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming, CancellationToken cancellationToken) public _EveryValueChanged(WeakReference<TTarget> target, Func<TTarget, TProperty> propertySelector, IEqualityComparer<TProperty> equalityComparer, PlayerLoopTiming monitorTiming, CancellationToken cancellationToken, bool cancelImmediately)
{ {
this.target = target; this.target = target;
this.propertySelector = propertySelector; this.propertySelector = propertySelector;
this.equalityComparer = equalityComparer; this.equalityComparer = equalityComparer;
this.cancellationToken = cancellationToken; this.cancellationToken = cancellationToken;
this.first = true; this.first = true;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var source = (_EveryValueChanged)state;
source.completionSource.TrySetCanceled(source.cancellationToken);
}, this);
}
TaskTracker.TrackActiveTask(this, 2); TaskTracker.TrackActiveTask(this, 2);
PlayerLoopHelper.AddAction(monitorTiming, this); PlayerLoopHelper.AddAction(monitorTiming, this);
} }
@ -200,6 +226,7 @@ namespace Cysharp.Threading.Tasks.Linq
{ {
if (!disposed) if (!disposed)
{ {
cancellationTokenRegistration.Dispose();
disposed = true; disposed = true;
TaskTracker.RemoveTracking(this); TaskTracker.RemoveTracking(this);
} }

View File

@ -6,32 +6,32 @@ namespace Cysharp.Threading.Tasks.Linq
{ {
public static partial class UniTaskAsyncEnumerable public static partial class UniTaskAsyncEnumerable
{ {
public static IUniTaskAsyncEnumerable<AsyncUnit> Timer(TimeSpan dueTime, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool ignoreTimeScale = false) public static IUniTaskAsyncEnumerable<AsyncUnit> Timer(TimeSpan dueTime, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool ignoreTimeScale = false, bool cancelImmediately = false)
{ {
return new Timer(dueTime, null, updateTiming, ignoreTimeScale); return new Timer(dueTime, null, updateTiming, ignoreTimeScale, cancelImmediately);
} }
public static IUniTaskAsyncEnumerable<AsyncUnit> Timer(TimeSpan dueTime, TimeSpan period, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool ignoreTimeScale = false) public static IUniTaskAsyncEnumerable<AsyncUnit> Timer(TimeSpan dueTime, TimeSpan period, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool ignoreTimeScale = false, bool cancelImmediately = false)
{ {
return new Timer(dueTime, period, updateTiming, ignoreTimeScale); return new Timer(dueTime, period, updateTiming, ignoreTimeScale, cancelImmediately);
} }
public static IUniTaskAsyncEnumerable<AsyncUnit> Interval(TimeSpan period, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool ignoreTimeScale = false) public static IUniTaskAsyncEnumerable<AsyncUnit> Interval(TimeSpan period, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool ignoreTimeScale = false, bool cancelImmediately = false)
{ {
return new Timer(period, period, updateTiming, ignoreTimeScale); return new Timer(period, period, updateTiming, ignoreTimeScale, cancelImmediately);
} }
public static IUniTaskAsyncEnumerable<AsyncUnit> TimerFrame(int dueTimeFrameCount, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update) public static IUniTaskAsyncEnumerable<AsyncUnit> TimerFrame(int dueTimeFrameCount, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool cancelImmediately = false)
{ {
if (dueTimeFrameCount < 0) if (dueTimeFrameCount < 0)
{ {
throw new ArgumentOutOfRangeException("Delay does not allow minus delayFrameCount. dueTimeFrameCount:" + dueTimeFrameCount); throw new ArgumentOutOfRangeException("Delay does not allow minus delayFrameCount. dueTimeFrameCount:" + dueTimeFrameCount);
} }
return new TimerFrame(dueTimeFrameCount, null, updateTiming); return new TimerFrame(dueTimeFrameCount, null, updateTiming, cancelImmediately);
} }
public static IUniTaskAsyncEnumerable<AsyncUnit> TimerFrame(int dueTimeFrameCount, int periodFrameCount, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update) public static IUniTaskAsyncEnumerable<AsyncUnit> TimerFrame(int dueTimeFrameCount, int periodFrameCount, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool cancelImmediately = false)
{ {
if (dueTimeFrameCount < 0) if (dueTimeFrameCount < 0)
{ {
@ -42,16 +42,16 @@ namespace Cysharp.Threading.Tasks.Linq
throw new ArgumentOutOfRangeException("Delay does not allow minus periodFrameCount. periodFrameCount:" + dueTimeFrameCount); throw new ArgumentOutOfRangeException("Delay does not allow minus periodFrameCount. periodFrameCount:" + dueTimeFrameCount);
} }
return new TimerFrame(dueTimeFrameCount, periodFrameCount, updateTiming); return new TimerFrame(dueTimeFrameCount, periodFrameCount, updateTiming, cancelImmediately);
} }
public static IUniTaskAsyncEnumerable<AsyncUnit> IntervalFrame(int intervalFrameCount, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update) public static IUniTaskAsyncEnumerable<AsyncUnit> IntervalFrame(int intervalFrameCount, PlayerLoopTiming updateTiming = PlayerLoopTiming.Update, bool cancelImmediately = false)
{ {
if (intervalFrameCount < 0) if (intervalFrameCount < 0)
{ {
throw new ArgumentOutOfRangeException("Delay does not allow minus intervalFrameCount. intervalFrameCount:" + intervalFrameCount); throw new ArgumentOutOfRangeException("Delay does not allow minus intervalFrameCount. intervalFrameCount:" + intervalFrameCount);
} }
return new TimerFrame(intervalFrameCount, intervalFrameCount, updateTiming); return new TimerFrame(intervalFrameCount, intervalFrameCount, updateTiming, cancelImmediately);
} }
} }
@ -61,18 +61,20 @@ namespace Cysharp.Threading.Tasks.Linq
readonly TimeSpan dueTime; readonly TimeSpan dueTime;
readonly TimeSpan? period; readonly TimeSpan? period;
readonly bool ignoreTimeScale; readonly bool ignoreTimeScale;
readonly bool cancelImmediately;
public Timer(TimeSpan dueTime, TimeSpan? period, PlayerLoopTiming updateTiming, bool ignoreTimeScale) public Timer(TimeSpan dueTime, TimeSpan? period, PlayerLoopTiming updateTiming, bool ignoreTimeScale, bool cancelImmediately)
{ {
this.updateTiming = updateTiming; this.updateTiming = updateTiming;
this.dueTime = dueTime; this.dueTime = dueTime;
this.period = period; this.period = period;
this.ignoreTimeScale = ignoreTimeScale; this.ignoreTimeScale = ignoreTimeScale;
this.cancelImmediately = cancelImmediately;
} }
public IUniTaskAsyncEnumerator<AsyncUnit> GetAsyncEnumerator(CancellationToken cancellationToken = default) public IUniTaskAsyncEnumerator<AsyncUnit> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{ {
return new _Timer(dueTime, period, updateTiming, ignoreTimeScale, cancellationToken); return new _Timer(dueTime, period, updateTiming, ignoreTimeScale, cancellationToken, cancelImmediately);
} }
class _Timer : MoveNextSource, IUniTaskAsyncEnumerator<AsyncUnit>, IPlayerLoopItem class _Timer : MoveNextSource, IUniTaskAsyncEnumerator<AsyncUnit>, IPlayerLoopItem
@ -81,7 +83,8 @@ namespace Cysharp.Threading.Tasks.Linq
readonly float? period; readonly float? period;
readonly PlayerLoopTiming updateTiming; readonly PlayerLoopTiming updateTiming;
readonly bool ignoreTimeScale; readonly bool ignoreTimeScale;
CancellationToken cancellationToken; readonly CancellationToken cancellationToken;
readonly CancellationTokenRegistration cancellationTokenRegistration;
int initialFrame; int initialFrame;
float elapsed; float elapsed;
@ -89,7 +92,7 @@ namespace Cysharp.Threading.Tasks.Linq
bool completed; bool completed;
bool disposed; bool disposed;
public _Timer(TimeSpan dueTime, TimeSpan? period, PlayerLoopTiming updateTiming, bool ignoreTimeScale, CancellationToken cancellationToken) public _Timer(TimeSpan dueTime, TimeSpan? period, PlayerLoopTiming updateTiming, bool ignoreTimeScale, CancellationToken cancellationToken, bool cancelImmediately)
{ {
this.dueTime = (float)dueTime.TotalSeconds; this.dueTime = (float)dueTime.TotalSeconds;
this.period = (period == null) ? null : (float?)period.Value.TotalSeconds; this.period = (period == null) ? null : (float?)period.Value.TotalSeconds;
@ -105,6 +108,17 @@ namespace Cysharp.Threading.Tasks.Linq
this.updateTiming = updateTiming; this.updateTiming = updateTiming;
this.ignoreTimeScale = ignoreTimeScale; this.ignoreTimeScale = ignoreTimeScale;
this.cancellationToken = cancellationToken; this.cancellationToken = cancellationToken;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var source = (_Timer)state;
source.completionSource.TrySetCanceled(source.cancellationToken);
}, this);
}
TaskTracker.TrackActiveTask(this, 2); TaskTracker.TrackActiveTask(this, 2);
PlayerLoopHelper.AddAction(updateTiming, this); PlayerLoopHelper.AddAction(updateTiming, this);
} }
@ -127,6 +141,7 @@ namespace Cysharp.Threading.Tasks.Linq
{ {
if (!disposed) if (!disposed)
{ {
cancellationTokenRegistration.Dispose();
disposed = true; disposed = true;
TaskTracker.RemoveTracking(this); TaskTracker.RemoveTracking(this);
} }
@ -187,24 +202,27 @@ namespace Cysharp.Threading.Tasks.Linq
readonly PlayerLoopTiming updateTiming; readonly PlayerLoopTiming updateTiming;
readonly int dueTimeFrameCount; readonly int dueTimeFrameCount;
readonly int? periodFrameCount; readonly int? periodFrameCount;
readonly bool cancelImmediately;
public TimerFrame(int dueTimeFrameCount, int? periodFrameCount, PlayerLoopTiming updateTiming) public TimerFrame(int dueTimeFrameCount, int? periodFrameCount, PlayerLoopTiming updateTiming, bool cancelImmediately)
{ {
this.updateTiming = updateTiming; this.updateTiming = updateTiming;
this.dueTimeFrameCount = dueTimeFrameCount; this.dueTimeFrameCount = dueTimeFrameCount;
this.periodFrameCount = periodFrameCount; this.periodFrameCount = periodFrameCount;
this.cancelImmediately = cancelImmediately;
} }
public IUniTaskAsyncEnumerator<AsyncUnit> GetAsyncEnumerator(CancellationToken cancellationToken = default) public IUniTaskAsyncEnumerator<AsyncUnit> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{ {
return new _TimerFrame(dueTimeFrameCount, periodFrameCount, updateTiming, cancellationToken); return new _TimerFrame(dueTimeFrameCount, periodFrameCount, updateTiming, cancellationToken, cancelImmediately);
} }
class _TimerFrame : MoveNextSource, IUniTaskAsyncEnumerator<AsyncUnit>, IPlayerLoopItem class _TimerFrame : MoveNextSource, IUniTaskAsyncEnumerator<AsyncUnit>, IPlayerLoopItem
{ {
readonly int dueTimeFrameCount; readonly int dueTimeFrameCount;
readonly int? periodFrameCount; readonly int? periodFrameCount;
CancellationToken cancellationToken; readonly CancellationToken cancellationToken;
readonly CancellationTokenRegistration cancellationTokenRegistration;
int initialFrame; int initialFrame;
int currentFrame; int currentFrame;
@ -212,7 +230,7 @@ namespace Cysharp.Threading.Tasks.Linq
bool completed; bool completed;
bool disposed; bool disposed;
public _TimerFrame(int dueTimeFrameCount, int? periodFrameCount, PlayerLoopTiming updateTiming, CancellationToken cancellationToken) public _TimerFrame(int dueTimeFrameCount, int? periodFrameCount, PlayerLoopTiming updateTiming, CancellationToken cancellationToken, bool cancelImmediately)
{ {
if (dueTimeFrameCount <= 0) dueTimeFrameCount = 0; if (dueTimeFrameCount <= 0) dueTimeFrameCount = 0;
if (periodFrameCount != null) if (periodFrameCount != null)
@ -225,6 +243,15 @@ namespace Cysharp.Threading.Tasks.Linq
this.dueTimeFrameCount = dueTimeFrameCount; this.dueTimeFrameCount = dueTimeFrameCount;
this.periodFrameCount = periodFrameCount; this.periodFrameCount = periodFrameCount;
this.cancellationToken = cancellationToken; this.cancellationToken = cancellationToken;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var source = (_TimerFrame)state;
source.completionSource.TrySetCanceled(source.cancellationToken);
}, this);
}
TaskTracker.TrackActiveTask(this, 2); TaskTracker.TrackActiveTask(this, 2);
PlayerLoopHelper.AddAction(updateTiming, this); PlayerLoopHelper.AddAction(updateTiming, this);
@ -249,6 +276,7 @@ namespace Cysharp.Threading.Tasks.Linq
{ {
if (!disposed) if (!disposed)
{ {
cancellationTokenRegistration.Dispose();
disposed = true; disposed = true;
TaskTracker.RemoveTracking(this); TaskTracker.RemoveTracking(this);
} }

View File

@ -33,14 +33,14 @@ namespace Cysharp.Threading.Tasks
return new YieldAwaitable(timing); return new YieldAwaitable(timing);
} }
public static UniTask Yield(CancellationToken cancellationToken) public static UniTask Yield(CancellationToken cancellationToken, bool cancelImmediately = false)
{ {
return new UniTask(YieldPromise.Create(PlayerLoopTiming.Update, cancellationToken, out var token), token); return new UniTask(YieldPromise.Create(PlayerLoopTiming.Update, cancellationToken, cancelImmediately, out var token), token);
} }
public static UniTask Yield(PlayerLoopTiming timing, CancellationToken cancellationToken) public static UniTask Yield(PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately = false)
{ {
return new UniTask(YieldPromise.Create(timing, cancellationToken, out var token), token); return new UniTask(YieldPromise.Create(timing, cancellationToken, cancelImmediately, out var token), token);
} }
/// <summary> /// <summary>
@ -48,7 +48,7 @@ namespace Cysharp.Threading.Tasks
/// </summary> /// </summary>
public static UniTask NextFrame() public static UniTask NextFrame()
{ {
return new UniTask(NextFramePromise.Create(PlayerLoopTiming.Update, CancellationToken.None, out var token), token); return new UniTask(NextFramePromise.Create(PlayerLoopTiming.Update, CancellationToken.None, false, out var token), token);
} }
/// <summary> /// <summary>
@ -56,23 +56,23 @@ namespace Cysharp.Threading.Tasks
/// </summary> /// </summary>
public static UniTask NextFrame(PlayerLoopTiming timing) public static UniTask NextFrame(PlayerLoopTiming timing)
{ {
return new UniTask(NextFramePromise.Create(timing, CancellationToken.None, out var token), token); return new UniTask(NextFramePromise.Create(timing, CancellationToken.None, false, out var token), token);
} }
/// <summary> /// <summary>
/// Similar as UniTask.Yield but guaranteed run on next frame. /// Similar as UniTask.Yield but guaranteed run on next frame.
/// </summary> /// </summary>
public static UniTask NextFrame(CancellationToken cancellationToken) public static UniTask NextFrame(CancellationToken cancellationToken, bool cancelImmediately = false)
{ {
return new UniTask(NextFramePromise.Create(PlayerLoopTiming.Update, cancellationToken, out var token), token); return new UniTask(NextFramePromise.Create(PlayerLoopTiming.Update, cancellationToken, cancelImmediately, out var token), token);
} }
/// <summary> /// <summary>
/// Similar as UniTask.Yield but guaranteed run on next frame. /// Similar as UniTask.Yield but guaranteed run on next frame.
/// </summary> /// </summary>
public static UniTask NextFrame(PlayerLoopTiming timing, CancellationToken cancellationToken) public static UniTask NextFrame(PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately = false)
{ {
return new UniTask(NextFramePromise.Create(timing, cancellationToken, out var token), token); return new UniTask(NextFramePromise.Create(timing, cancellationToken, cancelImmediately, out var token), token);
} }
#if UNITY_2023_1_OR_NEWER #if UNITY_2023_1_OR_NEWER
@ -88,15 +88,21 @@ namespace Cysharp.Threading.Tasks
} }
[Obsolete("Use WaitForEndOfFrame(MonoBehaviour) instead or UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate). Equivalent for coroutine's WaitForEndOfFrame requires MonoBehaviour(runner of Coroutine).")] [Obsolete("Use WaitForEndOfFrame(MonoBehaviour) instead or UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate). Equivalent for coroutine's WaitForEndOfFrame requires MonoBehaviour(runner of Coroutine).")]
public static UniTask WaitForEndOfFrame(CancellationToken cancellationToken) public static UniTask WaitForEndOfFrame(CancellationToken cancellationToken, bool cancelImmediately = false)
{ {
return UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate, cancellationToken); return UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate, cancellationToken, cancelImmediately);
} }
#endif #endif
public static UniTask WaitForEndOfFrame(MonoBehaviour coroutineRunner, CancellationToken cancellationToken = default) public static UniTask WaitForEndOfFrame(MonoBehaviour coroutineRunner)
{ {
var source = WaitForEndOfFramePromise.Create(coroutineRunner, cancellationToken, out var token); var source = WaitForEndOfFramePromise.Create(coroutineRunner, CancellationToken.None, false, out var token);
return new UniTask(source, token);
}
public static UniTask WaitForEndOfFrame(MonoBehaviour coroutineRunner, CancellationToken cancellationToken, bool cancelImmediately = false)
{
var source = WaitForEndOfFramePromise.Create(coroutineRunner, cancellationToken, cancelImmediately, out var token);
return new UniTask(source, token); return new UniTask(source, token);
} }
@ -113,50 +119,50 @@ namespace Cysharp.Threading.Tasks
/// <summary> /// <summary>
/// Same as UniTask.Yield(PlayerLoopTiming.LastFixedUpdate, cancellationToken). /// Same as UniTask.Yield(PlayerLoopTiming.LastFixedUpdate, cancellationToken).
/// </summary> /// </summary>
public static UniTask WaitForFixedUpdate(CancellationToken cancellationToken) public static UniTask WaitForFixedUpdate(CancellationToken cancellationToken, bool cancelImmediately = false)
{ {
return UniTask.Yield(PlayerLoopTiming.LastFixedUpdate, cancellationToken); return UniTask.Yield(PlayerLoopTiming.LastFixedUpdate, cancellationToken, cancelImmediately);
} }
public static UniTask WaitForSeconds(float duration, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken)) public static UniTask WaitForSeconds(float duration, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{ {
return Delay(Mathf.RoundToInt(1000 * duration), ignoreTimeScale, delayTiming, cancellationToken); return Delay(Mathf.RoundToInt(1000 * duration), ignoreTimeScale, delayTiming, cancellationToken, cancelImmediately);
} }
public static UniTask WaitForSeconds(int duration, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken)) public static UniTask WaitForSeconds(int duration, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{ {
return Delay(1000 * duration, ignoreTimeScale, delayTiming, cancellationToken); return Delay(1000 * duration, ignoreTimeScale, delayTiming, cancellationToken, cancelImmediately);
} }
public static UniTask DelayFrame(int delayFrameCount, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken)) public static UniTask DelayFrame(int delayFrameCount, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{ {
if (delayFrameCount < 0) if (delayFrameCount < 0)
{ {
throw new ArgumentOutOfRangeException("Delay does not allow minus delayFrameCount. delayFrameCount:" + delayFrameCount); throw new ArgumentOutOfRangeException("Delay does not allow minus delayFrameCount. delayFrameCount:" + delayFrameCount);
} }
return new UniTask(DelayFramePromise.Create(delayFrameCount, delayTiming, cancellationToken, out var token), token); return new UniTask(DelayFramePromise.Create(delayFrameCount, delayTiming, cancellationToken, cancelImmediately, out var token), token);
} }
public static UniTask Delay(int millisecondsDelay, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken)) public static UniTask Delay(int millisecondsDelay, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{ {
var delayTimeSpan = TimeSpan.FromMilliseconds(millisecondsDelay); var delayTimeSpan = TimeSpan.FromMilliseconds(millisecondsDelay);
return Delay(delayTimeSpan, ignoreTimeScale, delayTiming, cancellationToken); return Delay(delayTimeSpan, ignoreTimeScale, delayTiming, cancellationToken, cancelImmediately);
} }
public static UniTask Delay(TimeSpan delayTimeSpan, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken)) public static UniTask Delay(TimeSpan delayTimeSpan, bool ignoreTimeScale = false, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{ {
var delayType = ignoreTimeScale ? DelayType.UnscaledDeltaTime : DelayType.DeltaTime; var delayType = ignoreTimeScale ? DelayType.UnscaledDeltaTime : DelayType.DeltaTime;
return Delay(delayTimeSpan, delayType, delayTiming, cancellationToken); return Delay(delayTimeSpan, delayType, delayTiming, cancellationToken, cancelImmediately);
} }
public static UniTask Delay(int millisecondsDelay, DelayType delayType, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken)) public static UniTask Delay(int millisecondsDelay, DelayType delayType, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{ {
var delayTimeSpan = TimeSpan.FromMilliseconds(millisecondsDelay); var delayTimeSpan = TimeSpan.FromMilliseconds(millisecondsDelay);
return Delay(delayTimeSpan, delayType, delayTiming, cancellationToken); return Delay(delayTimeSpan, delayType, delayTiming, cancellationToken, cancelImmediately);
} }
public static UniTask Delay(TimeSpan delayTimeSpan, DelayType delayType, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken)) public static UniTask Delay(TimeSpan delayTimeSpan, DelayType delayType, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{ {
if (delayTimeSpan < TimeSpan.Zero) if (delayTimeSpan < TimeSpan.Zero)
{ {
@ -175,16 +181,16 @@ namespace Cysharp.Threading.Tasks
{ {
case DelayType.UnscaledDeltaTime: case DelayType.UnscaledDeltaTime:
{ {
return new UniTask(DelayIgnoreTimeScalePromise.Create(delayTimeSpan, delayTiming, cancellationToken, out var token), token); return new UniTask(DelayIgnoreTimeScalePromise.Create(delayTimeSpan, delayTiming, cancellationToken, cancelImmediately, out var token), token);
} }
case DelayType.Realtime: case DelayType.Realtime:
{ {
return new UniTask(DelayRealtimePromise.Create(delayTimeSpan, delayTiming, cancellationToken, out var token), token); return new UniTask(DelayRealtimePromise.Create(delayTimeSpan, delayTiming, cancellationToken, cancelImmediately, out var token), token);
} }
case DelayType.DeltaTime: case DelayType.DeltaTime:
default: default:
{ {
return new UniTask(DelayPromise.Create(delayTimeSpan, delayTiming, cancellationToken, out var token), token); return new UniTask(DelayPromise.Create(delayTimeSpan, delayTiming, cancellationToken, cancelImmediately, out var token), token);
} }
} }
} }
@ -201,13 +207,14 @@ namespace Cysharp.Threading.Tasks
} }
CancellationToken cancellationToken; CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
UniTaskCompletionSourceCore<object> core; UniTaskCompletionSourceCore<object> core;
YieldPromise() YieldPromise()
{ {
} }
public static IUniTaskSource Create(PlayerLoopTiming timing, CancellationToken cancellationToken, out short token) public static IUniTaskSource Create(PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{ {
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
@ -219,8 +226,16 @@ namespace Cysharp.Threading.Tasks
result = new YieldPromise(); result = new YieldPromise();
} }
result.cancellationToken = cancellationToken; result.cancellationToken = cancellationToken;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (YieldPromise)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3); TaskTracker.TrackActiveTask(result, 3);
@ -274,6 +289,7 @@ namespace Cysharp.Threading.Tasks
TaskTracker.RemoveTracking(this); TaskTracker.RemoveTracking(this);
core.Reset(); core.Reset();
cancellationToken = default; cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this); return pool.TryPush(this);
} }
} }
@ -290,14 +306,15 @@ namespace Cysharp.Threading.Tasks
} }
int frameCount; int frameCount;
CancellationToken cancellationToken;
UniTaskCompletionSourceCore<AsyncUnit> core; UniTaskCompletionSourceCore<AsyncUnit> core;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
NextFramePromise() NextFramePromise()
{ {
} }
public static IUniTaskSource Create(PlayerLoopTiming timing, CancellationToken cancellationToken, out short token) public static IUniTaskSource Create(PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{ {
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
@ -312,6 +329,15 @@ namespace Cysharp.Threading.Tasks
result.frameCount = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1; result.frameCount = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
result.cancellationToken = cancellationToken; result.cancellationToken = cancellationToken;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (NextFramePromise)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3); TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(timing, result); PlayerLoopHelper.AddAction(timing, result);
@ -369,6 +395,7 @@ namespace Cysharp.Threading.Tasks
TaskTracker.RemoveTracking(this); TaskTracker.RemoveTracking(this);
core.Reset(); core.Reset();
cancellationToken = default; cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this); return pool.TryPush(this);
} }
} }
@ -384,14 +411,15 @@ namespace Cysharp.Threading.Tasks
TaskPool.RegisterSizeGetter(typeof(WaitForEndOfFramePromise), () => pool.Size); TaskPool.RegisterSizeGetter(typeof(WaitForEndOfFramePromise), () => pool.Size);
} }
CancellationToken cancellationToken;
UniTaskCompletionSourceCore<object> core; UniTaskCompletionSourceCore<object> core;
CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
WaitForEndOfFramePromise() WaitForEndOfFramePromise()
{ {
} }
public static IUniTaskSource Create(MonoBehaviour coroutineRunner, CancellationToken cancellationToken, out short token) public static IUniTaskSource Create(MonoBehaviour coroutineRunner, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{ {
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
@ -405,6 +433,15 @@ namespace Cysharp.Threading.Tasks
result.cancellationToken = cancellationToken; result.cancellationToken = cancellationToken;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (WaitForEndOfFramePromise)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3); TaskTracker.TrackActiveTask(result, 3);
coroutineRunner.StartCoroutine(result); coroutineRunner.StartCoroutine(result);
@ -446,6 +483,7 @@ namespace Cysharp.Threading.Tasks
core.Reset(); core.Reset();
Reset(); // Reset Enumerator Reset(); // Reset Enumerator
cancellationToken = default; cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this); return pool.TryPush(this);
} }
@ -494,6 +532,7 @@ namespace Cysharp.Threading.Tasks
int initialFrame; int initialFrame;
int delayFrameCount; int delayFrameCount;
CancellationToken cancellationToken; CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
int currentFrameCount; int currentFrameCount;
UniTaskCompletionSourceCore<AsyncUnit> core; UniTaskCompletionSourceCore<AsyncUnit> core;
@ -502,7 +541,7 @@ namespace Cysharp.Threading.Tasks
{ {
} }
public static IUniTaskSource Create(int delayFrameCount, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token) public static IUniTaskSource Create(int delayFrameCount, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{ {
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
@ -518,6 +557,15 @@ namespace Cysharp.Threading.Tasks
result.cancellationToken = cancellationToken; result.cancellationToken = cancellationToken;
result.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1; result.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (DelayFramePromise)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3); TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(timing, result); PlayerLoopHelper.AddAction(timing, result);
@ -604,6 +652,7 @@ namespace Cysharp.Threading.Tasks
currentFrameCount = default; currentFrameCount = default;
delayFrameCount = default; delayFrameCount = default;
cancellationToken = default; cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this); return pool.TryPush(this);
} }
} }
@ -623,6 +672,7 @@ namespace Cysharp.Threading.Tasks
float delayTimeSpan; float delayTimeSpan;
float elapsed; float elapsed;
CancellationToken cancellationToken; CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
UniTaskCompletionSourceCore<object> core; UniTaskCompletionSourceCore<object> core;
@ -630,7 +680,7 @@ namespace Cysharp.Threading.Tasks
{ {
} }
public static IUniTaskSource Create(TimeSpan delayTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token) public static IUniTaskSource Create(TimeSpan delayTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{ {
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
@ -647,6 +697,15 @@ namespace Cysharp.Threading.Tasks
result.cancellationToken = cancellationToken; result.cancellationToken = cancellationToken;
result.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1; result.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (DelayPromise)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3); TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(timing, result); PlayerLoopHelper.AddAction(timing, result);
@ -715,6 +774,7 @@ namespace Cysharp.Threading.Tasks
delayTimeSpan = default; delayTimeSpan = default;
elapsed = default; elapsed = default;
cancellationToken = default; cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this); return pool.TryPush(this);
} }
} }
@ -734,6 +794,7 @@ namespace Cysharp.Threading.Tasks
float elapsed; float elapsed;
int initialFrame; int initialFrame;
CancellationToken cancellationToken; CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
UniTaskCompletionSourceCore<object> core; UniTaskCompletionSourceCore<object> core;
@ -741,7 +802,7 @@ namespace Cysharp.Threading.Tasks
{ {
} }
public static IUniTaskSource Create(TimeSpan delayFrameTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token) public static IUniTaskSource Create(TimeSpan delayFrameTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{ {
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
@ -758,6 +819,15 @@ namespace Cysharp.Threading.Tasks
result.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1; result.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
result.cancellationToken = cancellationToken; result.cancellationToken = cancellationToken;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (DelayIgnoreTimeScalePromise)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3); TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(timing, result); PlayerLoopHelper.AddAction(timing, result);
@ -826,6 +896,7 @@ namespace Cysharp.Threading.Tasks
delayFrameTimeSpan = default; delayFrameTimeSpan = default;
elapsed = default; elapsed = default;
cancellationToken = default; cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this); return pool.TryPush(this);
} }
} }
@ -844,6 +915,7 @@ namespace Cysharp.Threading.Tasks
long delayTimeSpanTicks; long delayTimeSpanTicks;
ValueStopwatch stopwatch; ValueStopwatch stopwatch;
CancellationToken cancellationToken; CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
UniTaskCompletionSourceCore<AsyncUnit> core; UniTaskCompletionSourceCore<AsyncUnit> core;
@ -851,7 +923,7 @@ namespace Cysharp.Threading.Tasks
{ {
} }
public static IUniTaskSource Create(TimeSpan delayTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token) public static IUniTaskSource Create(TimeSpan delayTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{ {
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
@ -867,6 +939,15 @@ namespace Cysharp.Threading.Tasks
result.delayTimeSpanTicks = delayTimeSpan.Ticks; result.delayTimeSpanTicks = delayTimeSpan.Ticks;
result.cancellationToken = cancellationToken; result.cancellationToken = cancellationToken;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (DelayRealtimePromise)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3); TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(timing, result); PlayerLoopHelper.AddAction(timing, result);
@ -931,6 +1012,7 @@ namespace Cysharp.Threading.Tasks
core.Reset(); core.Reset();
stopwatch = default; stopwatch = default;
cancellationToken = default; cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this); return pool.TryPush(this);
} }
} }

View File

@ -9,30 +9,30 @@ namespace Cysharp.Threading.Tasks
{ {
public partial struct UniTask public partial struct UniTask
{ {
public static UniTask WaitUntil(Func<bool> predicate, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken)) public static UniTask WaitUntil(Func<bool> predicate, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{ {
return new UniTask(WaitUntilPromise.Create(predicate, timing, cancellationToken, out var token), token); return new UniTask(WaitUntilPromise.Create(predicate, timing, cancellationToken, cancelImmediately, out var token), token);
} }
public static UniTask WaitWhile(Func<bool> predicate, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken)) public static UniTask WaitWhile(Func<bool> predicate, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{ {
return new UniTask(WaitWhilePromise.Create(predicate, timing, cancellationToken, out var token), token); return new UniTask(WaitWhilePromise.Create(predicate, timing, cancellationToken, cancelImmediately, out var token), token);
} }
public static UniTask WaitUntilCanceled(CancellationToken cancellationToken, PlayerLoopTiming timing = PlayerLoopTiming.Update) public static UniTask WaitUntilCanceled(CancellationToken cancellationToken, PlayerLoopTiming timing = PlayerLoopTiming.Update, bool completeImmediately = false)
{ {
return new UniTask(WaitUntilCanceledPromise.Create(cancellationToken, timing, out var token), token); return new UniTask(WaitUntilCanceledPromise.Create(cancellationToken, timing, completeImmediately, out var token), token);
} }
public static UniTask<U> WaitUntilValueChanged<T, U>(T target, Func<T, U> monitorFunction, PlayerLoopTiming monitorTiming = PlayerLoopTiming.Update, IEqualityComparer<U> equalityComparer = null, CancellationToken cancellationToken = default(CancellationToken)) public static UniTask<U> WaitUntilValueChanged<T, U>(T target, Func<T, U> monitorFunction, PlayerLoopTiming monitorTiming = PlayerLoopTiming.Update, IEqualityComparer<U> equalityComparer = null, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
where T : class where T : class
{ {
var unityObject = target as UnityEngine.Object; var unityObject = target as UnityEngine.Object;
var isUnityObject = target is UnityEngine.Object; // don't use (unityObject == null) var isUnityObject = target is UnityEngine.Object; // don't use (unityObject == null)
return new UniTask<U>(isUnityObject return new UniTask<U>(isUnityObject
? WaitUntilValueChangedUnityObjectPromise<T, U>.Create(target, monitorFunction, equalityComparer, monitorTiming, cancellationToken, out var token) ? WaitUntilValueChangedUnityObjectPromise<T, U>.Create(target, monitorFunction, equalityComparer, monitorTiming, cancellationToken, cancelImmediately, out var token)
: WaitUntilValueChangedStandardObjectPromise<T, U>.Create(target, monitorFunction, equalityComparer, monitorTiming, cancellationToken, out token), token); : WaitUntilValueChangedStandardObjectPromise<T, U>.Create(target, monitorFunction, equalityComparer, monitorTiming, cancellationToken, cancelImmediately, out token), token);
} }
sealed class WaitUntilPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitUntilPromise> sealed class WaitUntilPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitUntilPromise>
@ -48,6 +48,7 @@ namespace Cysharp.Threading.Tasks
Func<bool> predicate; Func<bool> predicate;
CancellationToken cancellationToken; CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
UniTaskCompletionSourceCore<object> core; UniTaskCompletionSourceCore<object> core;
@ -55,7 +56,7 @@ namespace Cysharp.Threading.Tasks
{ {
} }
public static IUniTaskSource Create(Func<bool> predicate, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token) public static IUniTaskSource Create(Func<bool> predicate, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{ {
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
@ -70,6 +71,15 @@ namespace Cysharp.Threading.Tasks
result.predicate = predicate; result.predicate = predicate;
result.cancellationToken = cancellationToken; result.cancellationToken = cancellationToken;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (WaitUntilPromise)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3); TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(timing, result); PlayerLoopHelper.AddAction(timing, result);
@ -136,6 +146,7 @@ namespace Cysharp.Threading.Tasks
core.Reset(); core.Reset();
predicate = default; predicate = default;
cancellationToken = default; cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this); return pool.TryPush(this);
} }
} }
@ -153,6 +164,7 @@ namespace Cysharp.Threading.Tasks
Func<bool> predicate; Func<bool> predicate;
CancellationToken cancellationToken; CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
UniTaskCompletionSourceCore<object> core; UniTaskCompletionSourceCore<object> core;
@ -160,7 +172,7 @@ namespace Cysharp.Threading.Tasks
{ {
} }
public static IUniTaskSource Create(Func<bool> predicate, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token) public static IUniTaskSource Create(Func<bool> predicate, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{ {
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
@ -174,6 +186,15 @@ namespace Cysharp.Threading.Tasks
result.predicate = predicate; result.predicate = predicate;
result.cancellationToken = cancellationToken; result.cancellationToken = cancellationToken;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (WaitWhilePromise)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3); TaskTracker.TrackActiveTask(result, 3);
@ -241,6 +262,7 @@ namespace Cysharp.Threading.Tasks
core.Reset(); core.Reset();
predicate = default; predicate = default;
cancellationToken = default; cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this); return pool.TryPush(this);
} }
} }
@ -257,6 +279,7 @@ namespace Cysharp.Threading.Tasks
} }
CancellationToken cancellationToken; CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
UniTaskCompletionSourceCore<object> core; UniTaskCompletionSourceCore<object> core;
@ -264,7 +287,7 @@ namespace Cysharp.Threading.Tasks
{ {
} }
public static IUniTaskSource Create(CancellationToken cancellationToken, PlayerLoopTiming timing, out short token) public static IUniTaskSource Create(CancellationToken cancellationToken, PlayerLoopTiming timing, bool completeImmediately, out short token)
{ {
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
@ -278,6 +301,15 @@ namespace Cysharp.Threading.Tasks
result.cancellationToken = cancellationToken; result.cancellationToken = cancellationToken;
if (completeImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (WaitUntilCanceledPromise)state;
promise.core.TrySetResult(null);
}, result);
}
TaskTracker.TrackActiveTask(result, 3); TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(timing, result); PlayerLoopHelper.AddAction(timing, result);
@ -329,6 +361,7 @@ namespace Cysharp.Threading.Tasks
TaskTracker.RemoveTracking(this); TaskTracker.RemoveTracking(this);
core.Reset(); core.Reset();
cancellationToken = default; cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this); return pool.TryPush(this);
} }
} }
@ -351,6 +384,7 @@ namespace Cysharp.Threading.Tasks
Func<T, U> monitorFunction; Func<T, U> monitorFunction;
IEqualityComparer<U> equalityComparer; IEqualityComparer<U> equalityComparer;
CancellationToken cancellationToken; CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
UniTaskCompletionSourceCore<U> core; UniTaskCompletionSourceCore<U> core;
@ -358,7 +392,7 @@ namespace Cysharp.Threading.Tasks
{ {
} }
public static IUniTaskSource<U> Create(T target, Func<T, U> monitorFunction, IEqualityComparer<U> equalityComparer, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token) public static IUniTaskSource<U> Create(T target, Func<T, U> monitorFunction, IEqualityComparer<U> equalityComparer, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{ {
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
@ -376,6 +410,15 @@ namespace Cysharp.Threading.Tasks
result.currentValue = monitorFunction(target); result.currentValue = monitorFunction(target);
result.equalityComparer = equalityComparer ?? UnityEqualityComparer.GetDefault<U>(); result.equalityComparer = equalityComparer ?? UnityEqualityComparer.GetDefault<U>();
result.cancellationToken = cancellationToken; result.cancellationToken = cancellationToken;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (WaitUntilValueChangedUnityObjectPromise<T, U>)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3); TaskTracker.TrackActiveTask(result, 3);
@ -453,6 +496,7 @@ namespace Cysharp.Threading.Tasks
monitorFunction = default; monitorFunction = default;
equalityComparer = default; equalityComparer = default;
cancellationToken = default; cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this); return pool.TryPush(this);
} }
} }
@ -474,6 +518,7 @@ namespace Cysharp.Threading.Tasks
Func<T, U> monitorFunction; Func<T, U> monitorFunction;
IEqualityComparer<U> equalityComparer; IEqualityComparer<U> equalityComparer;
CancellationToken cancellationToken; CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
UniTaskCompletionSourceCore<U> core; UniTaskCompletionSourceCore<U> core;
@ -481,7 +526,7 @@ namespace Cysharp.Threading.Tasks
{ {
} }
public static IUniTaskSource<U> Create(T target, Func<T, U> monitorFunction, IEqualityComparer<U> equalityComparer, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token) public static IUniTaskSource<U> Create(T target, Func<T, U> monitorFunction, IEqualityComparer<U> equalityComparer, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{ {
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
@ -498,6 +543,15 @@ namespace Cysharp.Threading.Tasks
result.currentValue = monitorFunction(target); result.currentValue = monitorFunction(target);
result.equalityComparer = equalityComparer ?? UnityEqualityComparer.GetDefault<U>(); result.equalityComparer = equalityComparer ?? UnityEqualityComparer.GetDefault<U>();
result.cancellationToken = cancellationToken; result.cancellationToken = cancellationToken;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (WaitUntilValueChangedStandardObjectPromise<T, U>)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3); TaskTracker.TrackActiveTask(result, 3);
@ -575,6 +629,7 @@ namespace Cysharp.Threading.Tasks
monitorFunction = default; monitorFunction = default;
equalityComparer = default; equalityComparer = default;
cancellationToken = default; cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this); return pool.TryPush(this);
} }
} }

View File

@ -24,12 +24,17 @@ namespace Cysharp.Threading.Tasks
return AwaitForAllAssets(asyncOperation, null, PlayerLoopTiming.Update, cancellationToken: cancellationToken); return AwaitForAllAssets(asyncOperation, null, PlayerLoopTiming.Update, cancellationToken: cancellationToken);
} }
public static UniTask<UnityEngine.Object[]> AwaitForAllAssets(this AssetBundleRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken)) public static UniTask<UnityEngine.Object[]> AwaitForAllAssets(this AssetBundleRequest asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
{
return AwaitForAllAssets(asyncOperation, null, PlayerLoopTiming.Update, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
}
public static UniTask<UnityEngine.Object[]> AwaitForAllAssets(this AssetBundleRequest asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{ {
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation)); Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityEngine.Object[]>(cancellationToken); if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityEngine.Object[]>(cancellationToken);
if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.allAssets); if (asyncOperation.isDone) return UniTask.FromResult(asyncOperation.allAssets);
return new UniTask<UnityEngine.Object[]>(AssetBundleRequestAllAssetsConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token); return new UniTask<UnityEngine.Object[]>(AssetBundleRequestAllAssetsConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
} }
public struct AssetBundleRequestAllAssetsAwaiter : ICriticalNotifyCompletion public struct AssetBundleRequestAllAssetsAwaiter : ICriticalNotifyCompletion
@ -95,15 +100,15 @@ namespace Cysharp.Threading.Tasks
AssetBundleRequest asyncOperation; AssetBundleRequest asyncOperation;
IProgress<float> progress; IProgress<float> progress;
CancellationToken cancellationToken; CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
UniTaskCompletionSourceCore<UnityEngine.Object[]> core; UniTaskCompletionSourceCore<UnityEngine.Object[]> core;
AssetBundleRequestAllAssetsConfiguredSource() AssetBundleRequestAllAssetsConfiguredSource()
{ {
} }
public static IUniTaskSource<UnityEngine.Object[]> Create(AssetBundleRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token) public static IUniTaskSource<UnityEngine.Object[]> Create(AssetBundleRequest asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{ {
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
@ -118,6 +123,15 @@ namespace Cysharp.Threading.Tasks
result.asyncOperation = asyncOperation; result.asyncOperation = asyncOperation;
result.progress = progress; result.progress = progress;
result.cancellationToken = cancellationToken; result.cancellationToken = cancellationToken;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (AssetBundleRequestAllAssetsConfiguredSource)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3); TaskTracker.TrackActiveTask(result, 3);
@ -188,6 +202,7 @@ namespace Cysharp.Threading.Tasks
asyncOperation = default; asyncOperation = default;
progress = default; progress = default;
cancellationToken = default; cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this); return pool.TryPush(this);
} }
} }

View File

@ -20,10 +20,15 @@ namespace Cysharp.Threading.Tasks
return ToUniTask(asyncOperation, cancellationToken: cancellationToken); return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
} }
public static UniTask<AsyncGPUReadbackRequest> ToUniTask(this AsyncGPUReadbackRequest asyncOperation, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken)) public static UniTask<AsyncGPUReadbackRequest> WithCancellation(this AsyncGPUReadbackRequest asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
{
return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
}
public static UniTask<AsyncGPUReadbackRequest> ToUniTask(this AsyncGPUReadbackRequest asyncOperation, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{ {
if (asyncOperation.done) return UniTask.FromResult(asyncOperation); if (asyncOperation.done) return UniTask.FromResult(asyncOperation);
return new UniTask<AsyncGPUReadbackRequest>(AsyncGPUReadbackRequestAwaiterConfiguredSource.Create(asyncOperation, timing, cancellationToken, out var token), token); return new UniTask<AsyncGPUReadbackRequest>(AsyncGPUReadbackRequestAwaiterConfiguredSource.Create(asyncOperation, timing, cancellationToken, cancelImmediately, out var token), token);
} }
sealed class AsyncGPUReadbackRequestAwaiterConfiguredSource : IUniTaskSource<AsyncGPUReadbackRequest>, IPlayerLoopItem, ITaskPoolNode<AsyncGPUReadbackRequestAwaiterConfiguredSource> sealed class AsyncGPUReadbackRequestAwaiterConfiguredSource : IUniTaskSource<AsyncGPUReadbackRequest>, IPlayerLoopItem, ITaskPoolNode<AsyncGPUReadbackRequestAwaiterConfiguredSource>
@ -39,15 +44,15 @@ namespace Cysharp.Threading.Tasks
AsyncGPUReadbackRequest asyncOperation; AsyncGPUReadbackRequest asyncOperation;
CancellationToken cancellationToken; CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
UniTaskCompletionSourceCore<AsyncGPUReadbackRequest> core; UniTaskCompletionSourceCore<AsyncGPUReadbackRequest> core;
AsyncGPUReadbackRequestAwaiterConfiguredSource() AsyncGPUReadbackRequestAwaiterConfiguredSource()
{ {
} }
public static IUniTaskSource<AsyncGPUReadbackRequest> Create(AsyncGPUReadbackRequest asyncOperation, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token) public static IUniTaskSource<AsyncGPUReadbackRequest> Create(AsyncGPUReadbackRequest asyncOperation, PlayerLoopTiming timing, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{ {
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
@ -61,6 +66,15 @@ namespace Cysharp.Threading.Tasks
result.asyncOperation = asyncOperation; result.asyncOperation = asyncOperation;
result.cancellationToken = cancellationToken; result.cancellationToken = cancellationToken;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (AsyncGPUReadbackRequestAwaiterConfiguredSource)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3); TaskTracker.TrackActiveTask(result, 3);
@ -131,6 +145,7 @@ namespace Cysharp.Threading.Tasks
core.Reset(); core.Reset();
asyncOperation = default; asyncOperation = default;
cancellationToken = default; cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this); return pool.TryPush(this);
} }
} }

View File

@ -29,13 +29,18 @@ namespace Cysharp.Threading.Tasks
{ {
return ToUniTask(asyncOperation, cancellationToken: cancellationToken); return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
} }
public static UniTask WithCancellation(this AsyncOperation asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
{
return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
}
public static UniTask ToUniTask(this AsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken)) public static UniTask ToUniTask(this AsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{ {
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation)); Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled(cancellationToken); if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled(cancellationToken);
if (asyncOperation.isDone) return UniTask.CompletedTask; if (asyncOperation.isDone) return UniTask.CompletedTask;
return new UniTask(AsyncOperationConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token); return new UniTask(AsyncOperationConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
} }
public struct AsyncOperationAwaiter : ICriticalNotifyCompletion public struct AsyncOperationAwaiter : ICriticalNotifyCompletion
@ -92,15 +97,15 @@ namespace Cysharp.Threading.Tasks
AsyncOperation asyncOperation; AsyncOperation asyncOperation;
IProgress<float> progress; IProgress<float> progress;
CancellationToken cancellationToken; CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
UniTaskCompletionSourceCore<AsyncUnit> core; UniTaskCompletionSourceCore<AsyncUnit> core;
AsyncOperationConfiguredSource() AsyncOperationConfiguredSource()
{ {
} }
public static IUniTaskSource Create(AsyncOperation asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token) public static IUniTaskSource Create(AsyncOperation asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{ {
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
@ -111,6 +116,16 @@ namespace Cysharp.Threading.Tasks
{ {
result = new AsyncOperationConfiguredSource(); result = new AsyncOperationConfiguredSource();
} }
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (AsyncOperationConfiguredSource)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
result.asyncOperation = asyncOperation; result.asyncOperation = asyncOperation;
result.progress = progress; result.progress = progress;
@ -136,7 +151,6 @@ namespace Cysharp.Threading.Tasks
} }
} }
public UniTaskStatus GetStatus(short token) public UniTaskStatus GetStatus(short token)
{ {
return core.GetStatus(token); return core.GetStatus(token);
@ -181,6 +195,7 @@ namespace Cysharp.Threading.Tasks
asyncOperation = default; asyncOperation = default;
progress = default; progress = default;
cancellationToken = default; cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this); return pool.TryPush(this);
} }
} }
@ -739,7 +754,12 @@ namespace Cysharp.Threading.Tasks
return ToUniTask(asyncOperation, cancellationToken: cancellationToken); return ToUniTask(asyncOperation, cancellationToken: cancellationToken);
} }
public static UniTask<UnityWebRequest> ToUniTask(this UnityWebRequestAsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken)) public static UniTask<UnityWebRequest> WithCancellation(this UnityWebRequestAsyncOperation asyncOperation, CancellationToken cancellationToken, bool cancelImmediately)
{
return ToUniTask(asyncOperation, cancellationToken: cancellationToken, cancelImmediately: cancelImmediately);
}
public static UniTask<UnityWebRequest> ToUniTask(this UnityWebRequestAsyncOperation asyncOperation, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken), bool cancelImmediately = false)
{ {
Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation)); Error.ThrowArgumentNullException(asyncOperation, nameof(asyncOperation));
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityWebRequest>(cancellationToken); if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled<UnityWebRequest>(cancellationToken);
@ -751,7 +771,7 @@ namespace Cysharp.Threading.Tasks
} }
return UniTask.FromResult(asyncOperation.webRequest); return UniTask.FromResult(asyncOperation.webRequest);
} }
return new UniTask<UnityWebRequest>(UnityWebRequestAsyncOperationConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, out var token), token); return new UniTask<UnityWebRequest>(UnityWebRequestAsyncOperationConfiguredSource.Create(asyncOperation, timing, progress, cancellationToken, cancelImmediately, out var token), token);
} }
public struct UnityWebRequestAsyncOperationAwaiter : ICriticalNotifyCompletion public struct UnityWebRequestAsyncOperationAwaiter : ICriticalNotifyCompletion
@ -820,15 +840,15 @@ namespace Cysharp.Threading.Tasks
UnityWebRequestAsyncOperation asyncOperation; UnityWebRequestAsyncOperation asyncOperation;
IProgress<float> progress; IProgress<float> progress;
CancellationToken cancellationToken; CancellationToken cancellationToken;
CancellationTokenRegistration cancellationTokenRegistration;
UniTaskCompletionSourceCore<UnityWebRequest> core; UniTaskCompletionSourceCore<UnityWebRequest> core;
UnityWebRequestAsyncOperationConfiguredSource() UnityWebRequestAsyncOperationConfiguredSource()
{ {
} }
public static IUniTaskSource<UnityWebRequest> Create(UnityWebRequestAsyncOperation asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, out short token) public static IUniTaskSource<UnityWebRequest> Create(UnityWebRequestAsyncOperation asyncOperation, PlayerLoopTiming timing, IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
{ {
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
@ -843,6 +863,15 @@ namespace Cysharp.Threading.Tasks
result.asyncOperation = asyncOperation; result.asyncOperation = asyncOperation;
result.progress = progress; result.progress = progress;
result.cancellationToken = cancellationToken; result.cancellationToken = cancellationToken;
if (cancelImmediately && cancellationToken.CanBeCanceled)
{
result.cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(state =>
{
var promise = (UnityWebRequestAsyncOperationConfiguredSource)state;
promise.core.TrySetCanceled(promise.cancellationToken);
}, result);
}
TaskTracker.TrackActiveTask(result, 3); TaskTracker.TrackActiveTask(result, 3);
@ -925,6 +954,7 @@ namespace Cysharp.Threading.Tasks
asyncOperation = default; asyncOperation = default;
progress = default; progress = default;
cancellationToken = default; cancellationToken = default;
cancellationTokenRegistration.Dispose();
return pool.TryPush(this); return pool.TryPush(this);
} }
} }