-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix ToSignal to throw OperationCanceledException
- Loading branch information
Showing
3 changed files
with
36 additions
and
80 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,89 +1,25 @@ | ||
using Godot; | ||
using System; | ||
using System.Runtime.CompilerServices; | ||
using System.Threading; | ||
|
||
namespace Fractural.Tasks | ||
{ | ||
/// <summary> | ||
/// A cancellable signal awaiter that wraps the Godot <see cref="SignalAwaiter"/>. Using ToSignal | ||
/// with an additional <see cref="CancellationToken"/> as parameter automatically returns this awaiter. | ||
/// See <see cref="GodotObjectExtensions.ToSignal(GodotObject, GodotObject, StringName, CancellationToken)"/>. | ||
/// | ||
/// Originally from <see href="https://github.com/altamkp/GodotEx/blob/master/src/GodotEx.Async/src/Core/CancellableSignalAwaiter.cs">GodotEx</see> | ||
/// </summary> | ||
public class CancellableSignalAwaiter : IAwaiter<Variant[]>, INotifyCompletion, IAwaitable<Variant[]> | ||
{ | ||
private readonly SignalAwaiter _signalAwaiter; | ||
private readonly CancellationToken _cancellationToken; | ||
private readonly CancellationTokenRegistration _cancellationTokenRegistration; | ||
|
||
private Action? _continuation; | ||
private bool _isCancelled; | ||
|
||
/// <summary> | ||
/// Creates a new <see cref="CancellableSignalAwaiter"/> that wraps the Godot <see cref="SignalAwaiter"/>. | ||
/// </summary> | ||
/// <param name="signalAwaiter">Godot <see cref="SignalAwaiter"/>.</param> | ||
/// <param name="cancellationToken">Cancellation token for cancellation request.</param> | ||
public CancellableSignalAwaiter(SignalAwaiter signalAwaiter, CancellationToken cancellationToken) | ||
{ | ||
_signalAwaiter = signalAwaiter; | ||
_cancellationToken = cancellationToken; | ||
_cancellationTokenRegistration = _cancellationToken.Register(() => | ||
{ | ||
_cancellationTokenRegistration.Dispose(); | ||
_isCancelled = true; | ||
OnAwaiterCompleted(); | ||
}); | ||
} | ||
|
||
/// <summary> | ||
/// Completion status of the awaiter. True if canceled or if signal is emitted. | ||
/// </summary> | ||
public bool IsCompleted => _isCancelled || _signalAwaiter.IsCompleted; | ||
|
||
/// <summary> | ||
/// Registers action delegate upon completion. | ||
/// </summary> | ||
/// <param name="continuation">Action delegate up completion.</param> | ||
public void OnCompleted(Action continuation) | ||
{ | ||
_continuation = continuation; | ||
_signalAwaiter.OnCompleted(OnAwaiterCompleted); | ||
} | ||
|
||
/// <summary> | ||
/// Returns current awaiter as <see cref="IAwaiter"/> that can be used with the await keyword. | ||
/// </summary> | ||
/// <returns>Current awaiter as <see cref="IAwaiter"/>.</returns> | ||
public IAwaiter<Variant[]> GetAwaiter() => this; | ||
|
||
/// <summary> | ||
/// Returns result upon completion. | ||
/// </summary> | ||
/// <returns>Result upon completion.</returns> | ||
public Variant[] GetResult() => _signalAwaiter.GetResult(); | ||
|
||
private void OnAwaiterCompleted() | ||
{ | ||
var continuation = _continuation; | ||
_continuation = null; | ||
continuation?.Invoke(); | ||
} | ||
} | ||
|
||
public partial struct GDTask | ||
{ | ||
public static async GDTask<Variant[]> ToSignal(GodotObject self, string signal) | ||
public static async GDTask<Variant[]> ToSignal(GodotObject self, StringName signal) | ||
{ | ||
return await self.ToSignal(self, signal); | ||
} | ||
|
||
public static async GDTask<Variant[]> ToSignal(GodotObject self, string signal, CancellationToken ct) | ||
public static async GDTask<Variant[]> ToSignal(GodotObject self, StringName signal, CancellationToken ct) | ||
{ | ||
var cancellableSignalAwaiter = new CancellableSignalAwaiter(self.ToSignal(self, signal), ct); | ||
return await cancellableSignalAwaiter; | ||
var tcs = new GDTaskCompletionSource<Variant[]>(); | ||
ct.Register(() => tcs.TrySetCanceled(ct)); | ||
Create(async () => | ||
{ | ||
var result = await self.ToSignal(self, signal); | ||
tcs.TrySetResult(result); | ||
}).Forget(); | ||
return await tcs.Task; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters