You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
182 lines
5.6 KiB
182 lines
5.6 KiB
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member |
|
|
|
using System; |
|
using System.Runtime.CompilerServices; |
|
using System.Threading; |
|
|
|
namespace Cysharp.Threading.Tasks |
|
{ |
|
public static class CancellationTokenExtensions |
|
{ |
|
static readonly Action<object> cancellationTokenCallback = Callback; |
|
static readonly Action<object> disposeCallback = DisposeCallback; |
|
|
|
public static CancellationToken ToCancellationToken(this UniTask task) |
|
{ |
|
var cts = new CancellationTokenSource(); |
|
ToCancellationTokenCore(task, cts).Forget(); |
|
return cts.Token; |
|
} |
|
|
|
public static CancellationToken ToCancellationToken(this UniTask task, CancellationToken linkToken) |
|
{ |
|
if (linkToken.IsCancellationRequested) |
|
{ |
|
return linkToken; |
|
} |
|
|
|
if (!linkToken.CanBeCanceled) |
|
{ |
|
return ToCancellationToken(task); |
|
} |
|
|
|
var cts = CancellationTokenSource.CreateLinkedTokenSource(linkToken); |
|
ToCancellationTokenCore(task, cts).Forget(); |
|
|
|
return cts.Token; |
|
} |
|
|
|
public static CancellationToken ToCancellationToken<T>(this UniTask<T> task) |
|
{ |
|
return ToCancellationToken(task.AsUniTask()); |
|
} |
|
|
|
public static CancellationToken ToCancellationToken<T>(this UniTask<T> task, CancellationToken linkToken) |
|
{ |
|
return ToCancellationToken(task.AsUniTask(), linkToken); |
|
} |
|
|
|
static async UniTaskVoid ToCancellationTokenCore(UniTask task, CancellationTokenSource cts) |
|
{ |
|
try |
|
{ |
|
await task; |
|
} |
|
catch (Exception ex) |
|
{ |
|
UniTaskScheduler.PublishUnobservedTaskException(ex); |
|
} |
|
cts.Cancel(); |
|
cts.Dispose(); |
|
} |
|
|
|
public static (UniTask, CancellationTokenRegistration) ToUniTask(this CancellationToken cancellationToken) |
|
{ |
|
if (cancellationToken.IsCancellationRequested) |
|
{ |
|
return (UniTask.FromCanceled(cancellationToken), default(CancellationTokenRegistration)); |
|
} |
|
|
|
var promise = new UniTaskCompletionSource(); |
|
return (promise.Task, cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationTokenCallback, promise)); |
|
} |
|
|
|
static void Callback(object state) |
|
{ |
|
var promise = (UniTaskCompletionSource)state; |
|
promise.TrySetResult(); |
|
} |
|
|
|
public static CancellationTokenAwaitable WaitUntilCanceled(this CancellationToken cancellationToken) |
|
{ |
|
return new CancellationTokenAwaitable(cancellationToken); |
|
} |
|
|
|
public static CancellationTokenRegistration RegisterWithoutCaptureExecutionContext(this CancellationToken cancellationToken, Action callback) |
|
{ |
|
var restoreFlow = false; |
|
if (!ExecutionContext.IsFlowSuppressed()) |
|
{ |
|
ExecutionContext.SuppressFlow(); |
|
restoreFlow = true; |
|
} |
|
|
|
try |
|
{ |
|
return cancellationToken.Register(callback, false); |
|
} |
|
finally |
|
{ |
|
if (restoreFlow) |
|
{ |
|
ExecutionContext.RestoreFlow(); |
|
} |
|
} |
|
} |
|
|
|
public static CancellationTokenRegistration RegisterWithoutCaptureExecutionContext(this CancellationToken cancellationToken, Action<object> callback, object state) |
|
{ |
|
var restoreFlow = false; |
|
if (!ExecutionContext.IsFlowSuppressed()) |
|
{ |
|
ExecutionContext.SuppressFlow(); |
|
restoreFlow = true; |
|
} |
|
|
|
try |
|
{ |
|
return cancellationToken.Register(callback, state, false); |
|
} |
|
finally |
|
{ |
|
if (restoreFlow) |
|
{ |
|
ExecutionContext.RestoreFlow(); |
|
} |
|
} |
|
} |
|
|
|
public static CancellationTokenRegistration AddTo(this IDisposable disposable, CancellationToken cancellationToken) |
|
{ |
|
return cancellationToken.RegisterWithoutCaptureExecutionContext(disposeCallback, disposable); |
|
} |
|
|
|
static void DisposeCallback(object state) |
|
{ |
|
var d = (IDisposable)state; |
|
d.Dispose(); |
|
} |
|
} |
|
|
|
public struct CancellationTokenAwaitable |
|
{ |
|
CancellationToken cancellationToken; |
|
|
|
public CancellationTokenAwaitable(CancellationToken cancellationToken) |
|
{ |
|
this.cancellationToken = cancellationToken; |
|
} |
|
|
|
public Awaiter GetAwaiter() |
|
{ |
|
return new Awaiter(cancellationToken); |
|
} |
|
|
|
public struct Awaiter : ICriticalNotifyCompletion |
|
{ |
|
CancellationToken cancellationToken; |
|
|
|
public Awaiter(CancellationToken cancellationToken) |
|
{ |
|
this.cancellationToken = cancellationToken; |
|
} |
|
|
|
public bool IsCompleted => !cancellationToken.CanBeCanceled || cancellationToken.IsCancellationRequested; |
|
|
|
public void GetResult() |
|
{ |
|
} |
|
|
|
public void OnCompleted(Action continuation) |
|
{ |
|
UnsafeOnCompleted(continuation); |
|
} |
|
|
|
public void UnsafeOnCompleted(Action continuation) |
|
{ |
|
cancellationToken.RegisterWithoutCaptureExecutionContext(continuation); |
|
} |
|
} |
|
} |
|
} |
|
|
|
|