diff --git a/README.md b/README.md
index 73911c9..da969bc 100644
--- a/README.md
+++ b/README.md
@@ -46,8 +46,14 @@ public Test : Node
var cts = new CancellationTokenSource();
WaitAndEmitMySignal(TimeSpan.FromSeconds(2)).Forget();
WaitAndCancelToken(TimeSpan.FromSeconds(1), cts).Forget();
- var signalResults = await GDTask.ToSignal(this, nameof(MySignal), cts.Token);
- // signalResults = null, since we cancelled awaiting the signal before the signal could fire.
+ try
+ {
+ var signalResults = await GDTask.ToSignal(this, nameof(MySignal), cts.Token);
+ }
+ catch (OperationCanceledException _)
+ {
+ GD.Print("Awaiting MySignal cancelled!");
+ }
// Waiting a single frame
await GDTask.Yield();
diff --git a/addons/GDTask/GDTask.ToSignal.cs b/addons/GDTask/GDTask.ToSignal.cs
index 5146aa3..edf6df3 100644
--- a/addons/GDTask/GDTask.ToSignal.cs
+++ b/addons/GDTask/GDTask.ToSignal.cs
@@ -1,89 +1,25 @@
using Godot;
-using System;
-using System.Runtime.CompilerServices;
using System.Threading;
namespace Fractural.Tasks
{
- ///
- /// A cancellable signal awaiter that wraps the Godot . Using ToSignal
- /// with an additional as parameter automatically returns this awaiter.
- /// See .
- ///
- /// Originally from GodotEx
- ///
- public class CancellableSignalAwaiter : IAwaiter, INotifyCompletion, IAwaitable
- {
- private readonly SignalAwaiter _signalAwaiter;
- private readonly CancellationToken _cancellationToken;
- private readonly CancellationTokenRegistration _cancellationTokenRegistration;
-
- private Action? _continuation;
- private bool _isCancelled;
-
- ///
- /// Creates a new that wraps the Godot .
- ///
- /// Godot .
- /// Cancellation token for cancellation request.
- public CancellableSignalAwaiter(SignalAwaiter signalAwaiter, CancellationToken cancellationToken)
- {
- _signalAwaiter = signalAwaiter;
- _cancellationToken = cancellationToken;
- _cancellationTokenRegistration = _cancellationToken.Register(() =>
- {
- _cancellationTokenRegistration.Dispose();
- _isCancelled = true;
- OnAwaiterCompleted();
- });
- }
-
- ///
- /// Completion status of the awaiter. True if canceled or if signal is emitted.
- ///
- public bool IsCompleted => _isCancelled || _signalAwaiter.IsCompleted;
-
- ///
- /// Registers action delegate upon completion.
- ///
- /// Action delegate up completion.
- public void OnCompleted(Action continuation)
- {
- _continuation = continuation;
- _signalAwaiter.OnCompleted(OnAwaiterCompleted);
- }
-
- ///
- /// Returns current awaiter as that can be used with the await keyword.
- ///
- /// Current awaiter as .
- public IAwaiter GetAwaiter() => this;
-
- ///
- /// Returns result upon completion.
- ///
- /// Result upon completion.
- public Variant[] GetResult() => _signalAwaiter.GetResult();
-
- private void OnAwaiterCompleted()
- {
- var continuation = _continuation;
- _continuation = null;
- continuation?.Invoke();
- }
- }
-
public partial struct GDTask
{
- public static async GDTask ToSignal(GodotObject self, string signal)
+ public static async GDTask ToSignal(GodotObject self, StringName signal)
{
return await self.ToSignal(self, signal);
}
- public static async GDTask ToSignal(GodotObject self, string signal, CancellationToken ct)
+ public static async GDTask ToSignal(GodotObject self, StringName signal, CancellationToken ct)
{
- var cancellableSignalAwaiter = new CancellableSignalAwaiter(self.ToSignal(self, signal), ct);
- return await cancellableSignalAwaiter;
+ var tcs = new GDTaskCompletionSource();
+ ct.Register(() => tcs.TrySetCanceled(ct));
+ Create(async () =>
+ {
+ var result = await self.ToSignal(self, signal);
+ tcs.TrySetResult(result);
+ }).Forget();
+ return await tcs.Task;
}
}
}
diff --git a/tests/manual/Test.cs b/tests/manual/Test.cs
index 29bdbe9..c2edbfb 100644
--- a/tests/manual/Test.cs
+++ b/tests/manual/Test.cs
@@ -85,15 +85,29 @@ private async GDTaskVoid Run()
GD.Print("Run: Await Cancellable MyEmptySignal");
WaitAndEmitMyEmptySignal(TimeSpan.FromSeconds(3)).Forget();
WaitAndCancelToken(TimeSpan.FromSeconds(0.5), cts).Forget();
- signalResult = await GDTask.ToSignal(this, nameof(MyEmptySignal), cts.Token);
- GD.Print("Run: Await Cancellable MyEmptySignal Cancelled, result: ", signalResult);
+ try
+ {
+ signalResult = await GDTask.ToSignal(this, nameof(MyEmptySignal), cts.Token);
+ GD.Print("Run: Await Cancellable MyEmptySignal ran with result: ", signalResult);
+ }
+ catch (OperationCanceledException _)
+ {
+ GD.Print("Run: Await Cancellable MyEmptySignal Cancelled");
+ }
cts = new CancellationTokenSource();
GD.Print("Run: Await Cancellable MyArgSignal");
WaitAndEmitMyArgSignal(TimeSpan.FromSeconds(3)).Forget();
WaitAndCancelToken(TimeSpan.FromSeconds(0.5), cts).Forget();
- signalResult = await GDTask.ToSignal(this, nameof(MyArgSignal), cts.Token);
- GD.Print("Run: Await Cancellable MyArgSignal Cancelled, result: ", signalResult);
+ try
+ {
+ signalResult = await GDTask.ToSignal(this, nameof(MyArgSignal), cts.Token);
+ GD.Print("Run: Await Cancellable MyArgSignal ran with result: ", signalResult);
+ }
+ catch (OperationCanceledException _)
+ {
+ GD.Print("Run: Await Cancellable MyArgSignal Cancelled");
+ }
GD.Print("Run: Pre RunWithResult");
string runResult = await RunWithResult();