Repository: Fractural/GDTask Branch: main Commit: 7e0c911b16cc Files: 127 Total size: 781.4 KB Directory structure: gitextract_fw_63qmu/ ├── .github/ │ └── workflows/ │ └── deploy.yml ├── .gitignore ├── .gitmodules ├── GDTask.csproj ├── GDTask.sln ├── LICENSE.md ├── README.md ├── addons/ │ └── GDTask/ │ ├── AsyncLazy.cs │ ├── AsyncLazy.cs.uid │ ├── AsyncUnit.cs │ ├── AsyncUnit.cs.uid │ ├── Autoload/ │ │ ├── GDTaskPlayerLoopAutoload.cs │ │ ├── GDTaskPlayerLoopAutoload.cs.uid │ │ ├── ProcessListener.cs │ │ └── ProcessListener.cs.uid │ ├── CancellationTokenEqualityComparer.cs │ ├── CancellationTokenEqualityComparer.cs.uid │ ├── CancellationTokenExtensions.cs │ ├── CancellationTokenExtensions.cs.uid │ ├── CancellationTokenSourceExtensions.cs │ ├── CancellationTokenSourceExtensions.cs.uid │ ├── CompilerServices/ │ │ ├── AsyncGDTaskMethodBuilder.cs │ │ ├── AsyncGDTaskMethodBuilder.cs.uid │ │ ├── AsyncGDTaskVoidMethodBuilder.cs │ │ ├── AsyncGDTaskVoidMethodBuilder.cs.uid │ │ ├── StateMachineRunner.cs │ │ └── StateMachineRunner.cs.uid │ ├── GDTask.Delay.cs │ ├── GDTask.Delay.cs.uid │ ├── GDTask.Factory.cs │ ├── GDTask.Factory.cs.uid │ ├── GDTask.Run.cs │ ├── GDTask.Run.cs.uid │ ├── GDTask.Threading.cs │ ├── GDTask.Threading.cs.uid │ ├── GDTask.ToSignal.cs │ ├── GDTask.ToSignal.cs.uid │ ├── GDTask.WaitUntil.cs │ ├── GDTask.WaitUntil.cs.uid │ ├── GDTask.WhenAll.Generated.cs │ ├── GDTask.WhenAll.Generated.cs.uid │ ├── GDTask.WhenAll.cs │ ├── GDTask.WhenAll.cs.uid │ ├── GDTask.WhenAny.Generated.cs │ ├── GDTask.WhenAny.Generated.cs.uid │ ├── GDTask.WhenAny.cs │ ├── GDTask.WhenAny.cs.uid │ ├── GDTask.cs │ ├── GDTask.cs.uid │ ├── GDTaskCompletionSource.cs │ ├── GDTaskCompletionSource.cs.uid │ ├── GDTaskExtensions.Shorthand.cs │ ├── GDTaskExtensions.Shorthand.cs.uid │ ├── GDTaskExtensions.cs │ ├── GDTaskExtensions.cs.uid │ ├── GDTaskObservableExtensions.cs │ ├── GDTaskObservableExtensions.cs.uid │ ├── GDTaskScheduler.cs │ ├── GDTaskScheduler.cs.uid │ ├── GDTaskSynchronizationContext.cs │ ├── GDTaskSynchronizationContext.cs.uid │ ├── GDTaskVoid.cs │ ├── GDTaskVoid.cs.uid │ ├── IGDTaskSource.cs │ ├── IGDTaskSource.cs.uid │ ├── Internal/ │ │ ├── ArrayPool.cs │ │ ├── ArrayPool.cs.uid │ │ ├── ArrayPoolUtil.cs │ │ ├── ArrayPoolUtil.cs.uid │ │ ├── ArrayUtil.cs │ │ ├── ArrayUtil.cs.uid │ │ ├── ContinuationQueue.cs │ │ ├── ContinuationQueue.cs.uid │ │ ├── DiagnosticsExtensions.cs │ │ ├── DiagnosticsExtensions.cs.uid │ │ ├── Error.cs │ │ ├── Error.cs.uid │ │ ├── GodotEqualityComparer.cs │ │ ├── GodotEqualityComparer.cs.uid │ │ ├── MinimumQueue.cs │ │ ├── MinimumQueue.cs.uid │ │ ├── PlayerLoopRunner.cs │ │ ├── PlayerLoopRunner.cs.uid │ │ ├── PooledDelegate.cs │ │ ├── PooledDelegate.cs.uid │ │ ├── RuntimeHelpersAbstraction.cs │ │ ├── RuntimeHelpersAbstraction.cs.uid │ │ ├── StatePool.cs │ │ ├── StatePool.cs.uid │ │ ├── TaskTracker.cs │ │ ├── TaskTracker.cs.uid │ │ ├── ValueStopwatch.cs │ │ ├── ValueStopwatch.cs.uid │ │ ├── WeakDictionary.cs │ │ └── WeakDictionary.cs.uid │ ├── MoveNextSource.cs │ ├── MoveNextSource.cs.uid │ ├── PlayerLoopTimer.cs │ ├── PlayerLoopTimer.cs.uid │ ├── Progress.cs │ ├── Progress.cs.uid │ ├── TaskPool.cs │ ├── TaskPool.cs.uid │ ├── TimeoutController.cs │ ├── TimeoutController.cs.uid │ ├── TriggerEvent.cs │ ├── TriggerEvent.cs.uid │ └── Triggers/ │ ├── AsyncDestroyTrigger.cs │ ├── AsyncDestroyTrigger.cs.uid │ ├── AsyncEnterTreeTrigger.cs │ ├── AsyncEnterTreeTrigger.cs.uid │ ├── AsyncReadyTrigger.cs │ ├── AsyncReadyTrigger.cs.uid │ ├── AsyncTriggerBase.cs │ ├── AsyncTriggerBase.cs.uid │ ├── AsyncTriggerExtensions.cs │ ├── AsyncTriggerExtensions.cs.uid │ ├── NodeMessagesTriggers.cs │ └── NodeMessagesTriggers.cs.uid ├── bootsplash.png.import ├── default_env.tres ├── icon.import ├── icon.png.import ├── project.godot └── tests/ └── manual/ ├── Test.cs ├── Test.cs.uid └── Test.tscn ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/workflows/deploy.yml ================================================ name: 🚀 Deploy Release on: push: branches: - main tags: - "v*.*.*" jobs: deploy: name: Deploy runs-on: ubuntu-latest steps: - name: Checkout Repository uses: actions/checkout@v3 with: submodules: recursive # Deploy to local repo - name: Deploy to Release Branch uses: s0/git-publish-subdir-action@develop env: REPO: self BRANCH: release FOLDER: addons/GDTask GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Create Release run: | mkdir release mv addons/GDTask release pushd release zip -r ../Release.zip * popd - name: Upload Release uses: actions/upload-artifact@v4 with: name: Release path: release - name: Tagged Release uses: softprops/action-gh-release@v1 if: startsWith(github.ref, 'refs/tags/') with: files: Release.zip ================================================ FILE: .gitignore ================================================ # Godot 4+ specific ignores .godot/ # Godot-specific ignores .import/ export.cfg export_presets.cfg # Mono-specific ignores .mono/ data_*/ # IntelliJ .idea/ # VSCode Settings .vscode/ # Visual studio .vs/ Builds/ # Ignore stub bin and obj folders bin/ obj/ # Tests tests/results.xml tests/metadata.json # MacOS .DS_Store ================================================ FILE: .gitmodules ================================================ ================================================ FILE: GDTask.csproj ================================================ net8.0 true ================================================ FILE: GDTask.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.10.35027.167 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GDTask", "GDTask.csproj", "{CEF6A453-1034-46B7-9617-C94E19891B46}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU ExportDebug|Any CPU = ExportDebug|Any CPU ExportRelease|Any CPU = ExportRelease|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {CEF6A453-1034-46B7-9617-C94E19891B46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CEF6A453-1034-46B7-9617-C94E19891B46}.Debug|Any CPU.Build.0 = Debug|Any CPU {CEF6A453-1034-46B7-9617-C94E19891B46}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU {CEF6A453-1034-46B7-9617-C94E19891B46}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU {CEF6A453-1034-46B7-9617-C94E19891B46}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU {CEF6A453-1034-46B7-9617-C94E19891B46}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {688C3662-0D40-4D17-8576-4FA4A992B65A} EndGlobalSection EndGlobal ================================================ FILE: LICENSE.md ================================================ The MIT License (MIT) Copyright (c) 2019 Atlinx, Yoshifumi Kawai / Cysharp, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # ⚠️ Superceded by [GDTask.Nuget](https://github.com/Delsin-Yu/GDTask.Nuget) This addon has been superceded by [Delsin-Yu's GDTask.Nuget](https://github.com/Delsin-Yu/GDTask.Nuget) package, which is accessible from the Nuget package manager. Their package also contains useful profiling tools for debugging GDTasks. # GDTask ✅ ![Deploy](https://github.com/Fractural/GDTask/actions/workflows/deploy.yml/badge.svg) > [!Note] > > This branch is for the Godot 4.4 version of the addon. > You can download the Godot 3.x version from the 3.x branch. Adds async/await features in Godot for easier async coding. Based on code from [Cysharp's UniTask library for Unity](https://github.com/Cysharp/UniTask). ```CSharp using Fractural.Tasks; public Test : Node { [Signal] public delegate void MySignalHandler(int number, bool boolean); public override _Ready() { // Running a task from a non-async method. Run().Forget(); } public async GDTaskVoid Run() { await GDTask.DelayFrame(100); // Waiting some amount of time // Note that these delays are paused when the game is paused await GDTask.Delay(TimeSpan.FromSeconds(10)); await GDTask.Delay(TimeSpan.FromSeconds(10), PlayerLoopTiming.Process); await GDTask.Delay(TimeSpan.FromSeconds(10), PlayerLoopTiming.PhysicsProcess); // Waiting some amount of milliseconds await GDTask.Delay(1000); // Waiting some amount of milliseconds, regardless of whether the game is paused await GDTask.Delay(TimeSpan.FromSeconds(10), PlayerLoopTiming.PauseProcess); await GDTask.Delay(TimeSpan.FromSeconds(10), PlayerLoopTiming.PausePhysicsProcess); // Awaiting for a signal WaitAndEmitMySignal(TimeSpan.FromSeconds(2)).Forget(); var signalResults = await GDTask.ToSignal(this, nameof(MySignal)); // signalResults = [10, true] // Cancellable awaiting a signal var cts = new CancellationTokenSource(); WaitAndEmitMySignal(TimeSpan.FromSeconds(2)).Forget(); WaitAndCancelToken(TimeSpan.FromSeconds(1), cts).Forget(); 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(); await GDTask.NextFrame(); await GDTask.WaitForEndOfFrame(); // Waiting for specific lifetime call await GDTask.WaitForPhysicsProcess(); // Cancellation of a GDTask var cts = new CancellationTokenSource(); CancellableReallyLongTask(cts.Token).Forget(); await GDTask.Delay(TimeSpan.FromSeconds(3)); cts.Cancel(); // Returning a value from a GDTask string result = await RunWithResult(); return result + " with additional text"; } public async GDTask RunWithResult() { await GDTask.Delay(TimeSpan.FromSeconds(3)); return "A result string"; } public async GDTaskVoid ReallyLongTask(CancellationToken cancellationToken) { GD.Print("Starting long task."); await GDTask.Delay(TimeSpan.FromSeconds(1000000), cancellationToken: cancellationToken); GD.Print("Finished long task."); } public async GDTaskVoid WaitAndEmitMySignal(TimeSpan delay) { await GDTask.Delay(delay); EmitSignal(nameof(MySignal), 10, true); } public async GDTaskVoid WaitAndCancelToken(TimeSpan delay, CancellationTokenSource cts) { await GDTask.Delay(delay); cts.Cancel(); } } ``` ## Installation Manual 1. Download the repository 2. Move the `addons/GDTask` folder into `addons/GDTask` Git Submodules 1. Make sure your project has a git repo initialized 2. Run ``` bash git submodule add -b release https://github.com/fractural/GDTask.git addons/GDTask ``` 3. Add `addons/GDTask/Autoload/GDTaskPlayerLoopAutoload` as an autoload ================================================ FILE: addons/GDTask/AsyncLazy.cs ================================================ using System; using System.Threading; namespace Fractural.Tasks { public partial class AsyncLazy { static Action continuation = SetCompletionSource; Func taskFactory; GDTaskCompletionSource completionSource; GDTask.Awaiter awaiter; object syncLock; bool initialized; public AsyncLazy(Func taskFactory) { this.taskFactory = taskFactory; this.completionSource = new GDTaskCompletionSource(); this.syncLock = new object(); this.initialized = false; } internal AsyncLazy(GDTask task) { this.taskFactory = null; this.completionSource = new GDTaskCompletionSource(); this.syncLock = null; this.initialized = true; var awaiter = task.GetAwaiter(); if (awaiter.IsCompleted) { SetCompletionSource(awaiter); } else { this.awaiter = awaiter; awaiter.SourceOnCompleted(continuation, this); } } public GDTask Task { get { EnsureInitialized(); return completionSource.Task; } } public GDTask.Awaiter GetAwaiter() => Task.GetAwaiter(); void EnsureInitialized() { if (Volatile.Read(ref initialized)) { return; } EnsureInitializedCore(); } void EnsureInitializedCore() { lock (syncLock) { if (!Volatile.Read(ref initialized)) { var f = Interlocked.Exchange(ref taskFactory, null); if (f != null) { var task = f(); var awaiter = task.GetAwaiter(); if (awaiter.IsCompleted) { SetCompletionSource(awaiter); } else { this.awaiter = awaiter; awaiter.SourceOnCompleted(continuation, this); } Volatile.Write(ref initialized, true); } } } } void SetCompletionSource(in GDTask.Awaiter awaiter) { try { awaiter.GetResult(); completionSource.TrySetResult(); } catch (Exception ex) { completionSource.TrySetException(ex); } } static void SetCompletionSource(object state) { var self = (AsyncLazy)state; try { self.awaiter.GetResult(); self.completionSource.TrySetResult(); } catch (Exception ex) { self.completionSource.TrySetException(ex); } finally { self.awaiter = default; } } } public partial class AsyncLazy { static Action continuation = SetCompletionSource; Func> taskFactory; GDTaskCompletionSource completionSource; GDTask.Awaiter awaiter; object syncLock; bool initialized; public AsyncLazy(Func> taskFactory) { this.taskFactory = taskFactory; this.completionSource = new GDTaskCompletionSource(); this.syncLock = new object(); this.initialized = false; } internal AsyncLazy(GDTask task) { this.taskFactory = null; this.completionSource = new GDTaskCompletionSource(); this.syncLock = null; this.initialized = true; var awaiter = task.GetAwaiter(); if (awaiter.IsCompleted) { SetCompletionSource(awaiter); } else { this.awaiter = awaiter; awaiter.SourceOnCompleted(continuation, this); } } public GDTask Task { get { EnsureInitialized(); return completionSource.Task; } } public GDTask.Awaiter GetAwaiter() => Task.GetAwaiter(); void EnsureInitialized() { if (Volatile.Read(ref initialized)) { return; } EnsureInitializedCore(); } void EnsureInitializedCore() { lock (syncLock) { if (!Volatile.Read(ref initialized)) { var f = Interlocked.Exchange(ref taskFactory, null); if (f != null) { var task = f(); var awaiter = task.GetAwaiter(); if (awaiter.IsCompleted) { SetCompletionSource(awaiter); } else { this.awaiter = awaiter; awaiter.SourceOnCompleted(continuation, this); } Volatile.Write(ref initialized, true); } } } } void SetCompletionSource(in GDTask.Awaiter awaiter) { try { var result = awaiter.GetResult(); completionSource.TrySetResult(result); } catch (Exception ex) { completionSource.TrySetException(ex); } } static void SetCompletionSource(object state) { var self = (AsyncLazy)state; try { var result = self.awaiter.GetResult(); self.completionSource.TrySetResult(result); } catch (Exception ex) { self.completionSource.TrySetException(ex); } finally { self.awaiter = default; } } } } ================================================ FILE: addons/GDTask/AsyncLazy.cs.uid ================================================ uid://cnn3liy4tgvma ================================================ FILE: addons/GDTask/AsyncUnit.cs ================================================ #pragma warning disable CS1591 // Missing XML comment for publicly visible type or using System; namespace Fractural.Tasks { public readonly struct AsyncUnit : IEquatable { public static readonly AsyncUnit Default = new AsyncUnit(); public override int GetHashCode() { return 0; } public bool Equals(AsyncUnit other) { return true; } public override string ToString() { return "()"; } } } ================================================ FILE: addons/GDTask/AsyncUnit.cs.uid ================================================ uid://bjl72gsi0q5ty ================================================ FILE: addons/GDTask/Autoload/GDTaskPlayerLoopAutoload.cs ================================================ using Fractural.Tasks.Internal; using Godot; using System; namespace Fractural.Tasks { public static class GDTaskLoopRunners { public struct GDTaskLoopRunnerProcess { }; public struct GDTaskLoopRunnerPhysicsProcess { }; } public enum PlayerLoopTiming { Process = 0, PhysicsProcess = 1, PauseProcess = 2, PausePhysicsProcess = 3, } public interface IPlayerLoopItem { bool MoveNext(); } /// /// Singleton that forwards Godot calls and values to GDTasks. /// public partial class GDTaskPlayerLoopAutoload : Node { public static int MainThreadId => Global.mainThreadId; public static bool IsMainThread => System.Threading.Thread.CurrentThread.ManagedThreadId == Global.mainThreadId; public static void AddAction(PlayerLoopTiming timing, IPlayerLoopItem action) => Global.LocalAddAction(timing, action); public static void ThrowInvalidLoopTiming(PlayerLoopTiming playerLoopTiming) => throw new InvalidOperationException("Target playerLoopTiming is not injected. Please check PlayerLoopHelper.Initialize. PlayerLoopTiming:" + playerLoopTiming); public static void AddContinuation(PlayerLoopTiming timing, Action continuation) => Global.LocalAddContinuation(timing, continuation); public void LocalAddAction(PlayerLoopTiming timing, IPlayerLoopItem action) { var runner = runners[(int)timing]; if (runner == null) { ThrowInvalidLoopTiming(timing); } runner.AddAction(action); } // NOTE: Continuation means a asynchronous task invoked by another task after the other task finishes. public void LocalAddContinuation(PlayerLoopTiming timing, Action continuation) { var q = yielders[(int)timing]; if (q == null) { ThrowInvalidLoopTiming(timing); } q.Enqueue(continuation); } public static GDTaskPlayerLoopAutoload Global { get { if (s_Global != null) return s_Global; var newInstance = new GDTaskPlayerLoopAutoload(); newInstance.Initialize(); var currentScene = ((SceneTree)Engine.GetMainLoop()).CurrentScene; currentScene.AddChild(newInstance); currentScene.MoveChild(newInstance, 0); newInstance.Name = "GDTaskPlayerLoopAutoload"; s_Global = newInstance; return s_Global; } } public double DeltaTime => GetProcessDeltaTime(); public double PhysicsDeltaTime => GetPhysicsProcessDeltaTime(); private static GDTaskPlayerLoopAutoload s_Global; private int mainThreadId; private ContinuationQueue[] yielders; private PlayerLoopRunner[] runners; private ProcessListener processListener; public override void _EnterTree() { if (s_Global == null) { Initialize(); s_Global = this; return; } QueueFree(); } private void Initialize() { ProcessMode = ProcessModeEnum.Pausable; mainThreadId = System.Threading.Thread.CurrentThread.ManagedThreadId; yielders = new[] { new ContinuationQueue(PlayerLoopTiming.Process), new ContinuationQueue(PlayerLoopTiming.PhysicsProcess), new ContinuationQueue(PlayerLoopTiming.PauseProcess), new ContinuationQueue(PlayerLoopTiming.PausePhysicsProcess), }; runners = new[] { new PlayerLoopRunner(PlayerLoopTiming.Process), new PlayerLoopRunner(PlayerLoopTiming.PhysicsProcess), new PlayerLoopRunner(PlayerLoopTiming.PauseProcess), new PlayerLoopRunner(PlayerLoopTiming.PausePhysicsProcess), }; processListener = new ProcessListener(); AddChild(processListener); processListener.ProcessMode = ProcessModeEnum.Always; processListener.OnProcess += PauseProcess; processListener.OnPhysicsProcess += PausePhysicsProcess; } public override void _Notification(int what) { if (what == NotificationPredelete) { if (Global == this) s_Global = null; if (yielders != null) { foreach (var yielder in yielders) yielder.Clear(); foreach (var runner in runners) runner.Clear(); } } } public override void _Process(double delta) { yielders[(int)PlayerLoopTiming.Process].Run(); runners[(int)PlayerLoopTiming.Process].Run(); } public override void _PhysicsProcess(double delta) { yielders[(int)PlayerLoopTiming.PhysicsProcess].Run(); runners[(int)PlayerLoopTiming.PhysicsProcess].Run(); } private void PauseProcess(double delta) { yielders[(int)PlayerLoopTiming.PauseProcess].Run(); runners[(int)PlayerLoopTiming.PauseProcess].Run(); } private void PausePhysicsProcess(double delta) { yielders[(int)PlayerLoopTiming.PausePhysicsProcess].Run(); runners[(int)PlayerLoopTiming.PausePhysicsProcess].Run(); } } } ================================================ FILE: addons/GDTask/Autoload/GDTaskPlayerLoopAutoload.cs.uid ================================================ uid://b34v2b358nj4p ================================================ FILE: addons/GDTask/Autoload/ProcessListener.cs ================================================ using Godot; using System; namespace Fractural.Tasks { public partial class ProcessListener : Node { public event Action OnProcess; public event Action OnPhysicsProcess; public override void _Process(double delta) { OnProcess?.Invoke(delta); } public override void _PhysicsProcess(double delta) { OnPhysicsProcess?.Invoke(delta); } } } ================================================ FILE: addons/GDTask/Autoload/ProcessListener.cs.uid ================================================ uid://3h6xpadx1svw ================================================ FILE: addons/GDTask/CancellationTokenEqualityComparer.cs ================================================ using System.Collections.Generic; using System.Threading; namespace Fractural.Tasks { public partial class CancellationTokenEqualityComparer : IEqualityComparer { public static readonly IEqualityComparer Default = new CancellationTokenEqualityComparer(); public bool Equals(CancellationToken x, CancellationToken y) { return x.Equals(y); } public int GetHashCode(CancellationToken obj) { return obj.GetHashCode(); } } } ================================================ FILE: addons/GDTask/CancellationTokenEqualityComparer.cs.uid ================================================ uid://dkqkuimd6xnj6 ================================================ FILE: addons/GDTask/CancellationTokenExtensions.cs ================================================ using System; using System.Runtime.CompilerServices; using System.Threading; namespace Fractural.Tasks { public static class CancellationTokenExtensions { static readonly Action cancellationTokenCallback = Callback; static readonly Action disposeCallback = DisposeCallback; public static CancellationToken ToCancellationToken(this GDTask task) { var cts = new CancellationTokenSource(); ToCancellationTokenCore(task, cts).Forget(); return cts.Token; } public static CancellationToken ToCancellationToken(this GDTask 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(this GDTask task) { return ToCancellationToken(task.AsGDTask()); } public static CancellationToken ToCancellationToken(this GDTask task, CancellationToken linkToken) { return ToCancellationToken(task.AsGDTask(), linkToken); } static async GDTaskVoid ToCancellationTokenCore(GDTask task, CancellationTokenSource cts) { try { await task; } catch (Exception ex) { GDTaskScheduler.PublishUnobservedTaskException(ex); } cts.Cancel(); cts.Dispose(); } public static (GDTask, CancellationTokenRegistration) ToGDTask(this CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return (GDTask.FromCanceled(cancellationToken), default(CancellationTokenRegistration)); } var promise = new GDTaskCompletionSource(); return (promise.Task, cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationTokenCallback, promise)); } static void Callback(object state) { var promise = (GDTaskCompletionSource)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 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); } } } } ================================================ FILE: addons/GDTask/CancellationTokenExtensions.cs.uid ================================================ uid://bvmag4mxjvgn4 ================================================ FILE: addons/GDTask/CancellationTokenSourceExtensions.cs ================================================ using System.Threading; using Fractural.Tasks.Triggers; using System; using Fractural.Tasks.Internal; using Godot; namespace Fractural.Tasks { public static partial class CancellationTokenSourceExtensions { readonly static Action CancelCancellationTokenSourceStateDelegate = new Action(CancelCancellationTokenSourceState); static void CancelCancellationTokenSourceState(object state) { var cts = (CancellationTokenSource)state; cts.Cancel(); } public static IDisposable CancelAfterSlim(this CancellationTokenSource cts, int millisecondsDelay, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming delayTiming = PlayerLoopTiming.Process) { return CancelAfterSlim(cts, TimeSpan.FromMilliseconds(millisecondsDelay), delayType, delayTiming); } public static IDisposable CancelAfterSlim(this CancellationTokenSource cts, TimeSpan delayTimeSpan, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming delayTiming = PlayerLoopTiming.Process) { return PlayerLoopTimer.StartNew(delayTimeSpan, false, delayType, delayTiming, cts.Token, CancelCancellationTokenSourceStateDelegate, cts); } public static void RegisterRaiseCancelOnDestroy(this CancellationTokenSource cts, Node node) { var trigger = node.GetAsyncDestroyTrigger(); trigger.CancellationToken.RegisterWithoutCaptureExecutionContext(CancelCancellationTokenSourceStateDelegate, cts); } } } ================================================ FILE: addons/GDTask/CancellationTokenSourceExtensions.cs.uid ================================================ uid://u8ib13lqamfi ================================================ FILE: addons/GDTask/CompilerServices/AsyncGDTaskMethodBuilder.cs ================================================ using System; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security; namespace Fractural.Tasks.CompilerServices { [StructLayout(LayoutKind.Auto)] public struct AsyncGDTaskMethodBuilder { IStateMachineRunnerPromise runnerPromise; Exception ex; // 1. Static Create method. [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static AsyncGDTaskMethodBuilder Create() { return default; } // 2. TaskLike Task property. public GDTask Task { [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] get { if (runnerPromise != null) { return runnerPromise.Task; } else if (ex != null) { return GDTask.FromException(ex); } else { return GDTask.CompletedTask; } } } // 3. SetException [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public void SetException(Exception exception) { if (runnerPromise == null) { ex = exception; } else { runnerPromise.SetException(exception); } } // 4. SetResult [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public void SetResult() { if (runnerPromise != null) { runnerPromise.SetResult(); } } // 5. AwaitOnCompleted [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine { if (runnerPromise == null) { AsyncGDTask.SetStateMachine(ref stateMachine, ref runnerPromise); } awaiter.OnCompleted(runnerPromise.MoveNext); } // 6. AwaitUnsafeOnCompleted [DebuggerHidden] [SecuritySafeCritical] [MethodImpl(MethodImplOptions.AggressiveInlining)] public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine { if (runnerPromise == null) { AsyncGDTask.SetStateMachine(ref stateMachine, ref runnerPromise); } awaiter.UnsafeOnCompleted(runnerPromise.MoveNext); } // 7. Start [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine { stateMachine.MoveNext(); } // 8. SetStateMachine [DebuggerHidden] public void SetStateMachine(IAsyncStateMachine stateMachine) { // don't use boxed stateMachine. } #if DEBUG // Important for IDE debugger. object debuggingId; private object ObjectIdForDebugger { get { if (debuggingId == null) { debuggingId = new object(); } return debuggingId; } } #endif } [StructLayout(LayoutKind.Auto)] public struct AsyncGDTaskMethodBuilder { IStateMachineRunnerPromise runnerPromise; Exception ex; T result; // 1. Static Create method. [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static AsyncGDTaskMethodBuilder Create() { return default; } // 2. TaskLike Task property. public GDTask Task { [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] get { if (runnerPromise != null) { return runnerPromise.Task; } else if (ex != null) { return GDTask.FromException(ex); } else { return GDTask.FromResult(result); } } } // 3. SetException [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public void SetException(Exception exception) { if (runnerPromise == null) { ex = exception; } else { runnerPromise.SetException(exception); } } // 4. SetResult [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public void SetResult(T result) { if (runnerPromise == null) { this.result = result; } else { runnerPromise.SetResult(result); } } // 5. AwaitOnCompleted [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine { if (runnerPromise == null) { AsyncGDTask.SetStateMachine(ref stateMachine, ref runnerPromise); } awaiter.OnCompleted(runnerPromise.MoveNext); } // 6. AwaitUnsafeOnCompleted [DebuggerHidden] [SecuritySafeCritical] [MethodImpl(MethodImplOptions.AggressiveInlining)] public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine { if (runnerPromise == null) { AsyncGDTask.SetStateMachine(ref stateMachine, ref runnerPromise); } awaiter.UnsafeOnCompleted(runnerPromise.MoveNext); } // 7. Start [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine { stateMachine.MoveNext(); } // 8. SetStateMachine [DebuggerHidden] public void SetStateMachine(IAsyncStateMachine stateMachine) { // don't use boxed stateMachine. } #if DEBUG // Important for IDE debugger. object debuggingId; private object ObjectIdForDebugger { get { if (debuggingId == null) { debuggingId = new object(); } return debuggingId; } } #endif } } ================================================ FILE: addons/GDTask/CompilerServices/AsyncGDTaskMethodBuilder.cs.uid ================================================ uid://6mv8w57jlsg3 ================================================ FILE: addons/GDTask/CompilerServices/AsyncGDTaskVoidMethodBuilder.cs ================================================  using System; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security; namespace Fractural.Tasks.CompilerServices { [StructLayout(LayoutKind.Auto)] public struct AsyncGDTaskVoidMethodBuilder { IStateMachineRunner runner; // 1. Static Create method. [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static AsyncGDTaskVoidMethodBuilder Create() { return default; } // 2. TaskLike Task property(void) public GDTaskVoid Task { [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return default; } } // 3. SetException [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public void SetException(Exception exception) { // runner is finished, return first. if (runner != null) { runner.Return(); runner = null; } GDTaskScheduler.PublishUnobservedTaskException(exception); } // 4. SetResult [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public void SetResult() { // runner is finished, return. if (runner != null) { runner.Return(); runner = null; } } // 5. AwaitOnCompleted [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine { if (runner == null) { AsyncGDTaskVoid.SetStateMachine(ref stateMachine, ref runner); } awaiter.OnCompleted(runner.MoveNext); } // 6. AwaitUnsafeOnCompleted [DebuggerHidden] [SecuritySafeCritical] [MethodImpl(MethodImplOptions.AggressiveInlining)] public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine { if (runner == null) { AsyncGDTaskVoid.SetStateMachine(ref stateMachine, ref runner); } awaiter.UnsafeOnCompleted(runner.MoveNext); } // 7. Start [DebuggerHidden] public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine { stateMachine.MoveNext(); } // 8. SetStateMachine [DebuggerHidden] public void SetStateMachine(IAsyncStateMachine stateMachine) { // don't use boxed stateMachine. } #if DEBUG // Important for IDE debugger. object debuggingId; private object ObjectIdForDebugger { get { if (debuggingId == null) { debuggingId = new object(); } return debuggingId; } } #endif } } ================================================ FILE: addons/GDTask/CompilerServices/AsyncGDTaskVoidMethodBuilder.cs.uid ================================================ uid://di85mfhei8bs7 ================================================ FILE: addons/GDTask/CompilerServices/StateMachineRunner.cs ================================================ #pragma warning disable CS1591 using System; using System.Diagnostics; using System.Linq; using System.Runtime.CompilerServices; namespace Fractural.Tasks.CompilerServices { internal interface IStateMachineRunner { Action MoveNext { get; } void Return(); Action ReturnAction { get; } } internal interface IStateMachineRunnerPromise : IGDTaskSource { Action MoveNext { get; } GDTask Task { get; } void SetResult(); void SetException(Exception exception); } internal interface IStateMachineRunnerPromise : IGDTaskSource { Action MoveNext { get; } GDTask Task { get; } void SetResult(T result); void SetException(Exception exception); } internal static class StateMachineUtility { // Get AsyncStateMachine internal state to check IL2CPP bug public static int GetState(IAsyncStateMachine stateMachine) { var info = stateMachine.GetType().GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance) .First(x => x.Name.EndsWith("__state")); return (int)info.GetValue(stateMachine); } } internal sealed class AsyncGDTaskVoid : IStateMachineRunner, ITaskPoolNode>, IGDTaskSource where TStateMachine : IAsyncStateMachine { static TaskPool> pool; public Action ReturnAction { get; } TStateMachine stateMachine; public Action MoveNext { get; } public AsyncGDTaskVoid() { MoveNext = Run; } public static void SetStateMachine(ref TStateMachine stateMachine, ref IStateMachineRunner runnerFieldRef) { if (!pool.TryPop(out var result)) { result = new AsyncGDTaskVoid(); } TaskTracker.TrackActiveTask(result, 3); runnerFieldRef = result; // set runner before copied. result.stateMachine = stateMachine; // copy struct StateMachine(in release build). } static AsyncGDTaskVoid() { TaskPool.RegisterSizeGetter(typeof(AsyncGDTaskVoid), () => pool.Size); } AsyncGDTaskVoid nextNode; public ref AsyncGDTaskVoid NextNode => ref nextNode; public void Return() { TaskTracker.RemoveTracking(this); stateMachine = default; pool.TryPush(this); } [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] void Run() { stateMachine.MoveNext(); } // dummy interface implementation for TaskTracker. GDTaskStatus IGDTaskSource.GetStatus(short token) { return GDTaskStatus.Pending; } GDTaskStatus IGDTaskSource.UnsafeGetStatus() { return GDTaskStatus.Pending; } void IGDTaskSource.OnCompleted(Action continuation, object state, short token) { } void IGDTaskSource.GetResult(short token) { } } internal sealed class AsyncGDTask : IStateMachineRunnerPromise, IGDTaskSource, ITaskPoolNode> where TStateMachine : IAsyncStateMachine { static TaskPool> pool; public Action MoveNext { get; } TStateMachine stateMachine; GDTaskCompletionSourceCore core; AsyncGDTask() { MoveNext = Run; } public static void SetStateMachine(ref TStateMachine stateMachine, ref IStateMachineRunnerPromise runnerPromiseFieldRef) { if (!pool.TryPop(out var result)) { result = new AsyncGDTask(); } TaskTracker.TrackActiveTask(result, 3); runnerPromiseFieldRef = result; // set runner before copied. result.stateMachine = stateMachine; // copy struct StateMachine(in release build). } AsyncGDTask nextNode; public ref AsyncGDTask NextNode => ref nextNode; static AsyncGDTask() { TaskPool.RegisterSizeGetter(typeof(AsyncGDTask), () => pool.Size); } void Return() { TaskTracker.RemoveTracking(this); core.Reset(); stateMachine = default; pool.TryPush(this); } bool TryReturn() { TaskTracker.RemoveTracking(this); core.Reset(); stateMachine = default; return pool.TryPush(this); } [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] void Run() { stateMachine.MoveNext(); } public GDTask Task { [DebuggerHidden] get { return new GDTask(this, core.Version); } } [DebuggerHidden] public void SetResult() { core.TrySetResult(AsyncUnit.Default); } [DebuggerHidden] public void SetException(Exception exception) { core.TrySetException(exception); } [DebuggerHidden] public void GetResult(short token) { try { core.GetResult(token); } finally { TryReturn(); } } [DebuggerHidden] public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } [DebuggerHidden] public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } [DebuggerHidden] public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } } internal sealed class AsyncGDTask : IStateMachineRunnerPromise, IGDTaskSource, ITaskPoolNode> where TStateMachine : IAsyncStateMachine { static TaskPool> pool; public Action MoveNext { get; } TStateMachine stateMachine; GDTaskCompletionSourceCore core; AsyncGDTask() { MoveNext = Run; } public static void SetStateMachine(ref TStateMachine stateMachine, ref IStateMachineRunnerPromise runnerPromiseFieldRef) { if (!pool.TryPop(out var result)) { result = new AsyncGDTask(); } TaskTracker.TrackActiveTask(result, 3); runnerPromiseFieldRef = result; // set runner before copied. result.stateMachine = stateMachine; // copy struct StateMachine(in release build). } AsyncGDTask nextNode; public ref AsyncGDTask NextNode => ref nextNode; static AsyncGDTask() { TaskPool.RegisterSizeGetter(typeof(AsyncGDTask), () => pool.Size); } void Return() { TaskTracker.RemoveTracking(this); core.Reset(); stateMachine = default; pool.TryPush(this); } bool TryReturn() { TaskTracker.RemoveTracking(this); core.Reset(); stateMachine = default; return pool.TryPush(this); } [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] void Run() { stateMachine.MoveNext(); } public GDTask Task { [DebuggerHidden] get { return new GDTask(this, core.Version); } } [DebuggerHidden] public void SetResult(T result) { core.TrySetResult(result); } [DebuggerHidden] public void SetException(Exception exception) { core.TrySetException(exception); } [DebuggerHidden] public T GetResult(short token) { try { return core.GetResult(token); } finally { TryReturn(); } } [DebuggerHidden] void IGDTaskSource.GetResult(short token) { GetResult(token); } [DebuggerHidden] public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } [DebuggerHidden] public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } [DebuggerHidden] public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } } } ================================================ FILE: addons/GDTask/CompilerServices/StateMachineRunner.cs.uid ================================================ uid://civq0j70x833j ================================================ FILE: addons/GDTask/GDTask.Delay.cs ================================================ using Fractural.Tasks.Internal; using Godot; using System; using System.Runtime.CompilerServices; using System.Threading; namespace Fractural.Tasks { public enum DelayType { /// use Time.deltaTime. DeltaTime, /// use Stopwatch.GetTimestamp(). Realtime } public partial struct GDTask { public static YieldAwaitable Yield() { // optimized for single continuation return new YieldAwaitable(PlayerLoopTiming.Process); } public static YieldAwaitable Yield(PlayerLoopTiming timing) { // optimized for single continuation return new YieldAwaitable(timing); } public static GDTask Yield(CancellationToken cancellationToken) { return new GDTask(YieldPromise.Create(PlayerLoopTiming.Process, cancellationToken, out var token), token); } public static GDTask Yield(PlayerLoopTiming timing, CancellationToken cancellationToken) { return new GDTask(YieldPromise.Create(timing, cancellationToken, out var token), token); } /// /// Similar as GDTask.Yield but guaranteed run on next frame. /// public static GDTask NextFrame() { return new GDTask(NextFramePromise.Create(PlayerLoopTiming.Process, CancellationToken.None, out var token), token); } /// /// Similar as GDTask.Yield but guaranteed run on next frame. /// public static GDTask NextFrame(PlayerLoopTiming timing) { return new GDTask(NextFramePromise.Create(timing, CancellationToken.None, out var token), token); } /// /// Similar as GDTask.Yield but guaranteed run on next frame. /// public static GDTask NextFrame(CancellationToken cancellationToken) { return new GDTask(NextFramePromise.Create(PlayerLoopTiming.Process, cancellationToken, out var token), token); } /// /// Similar as GDTask.Yield but guaranteed run on next frame. /// public static GDTask NextFrame(PlayerLoopTiming timing, CancellationToken cancellationToken) { return new GDTask(NextFramePromise.Create(timing, cancellationToken, out var token), token); } public static YieldAwaitable WaitForEndOfFrame() { return GDTask.Yield(PlayerLoopTiming.Process); } public static GDTask WaitForEndOfFrame(CancellationToken cancellationToken) { return GDTask.Yield(PlayerLoopTiming.Process, cancellationToken); } /// /// Same as GDTask.Yield(PlayerLoopTiming.PhysicsProcess). /// public static YieldAwaitable WaitForPhysicsProcess() { return GDTask.Yield(PlayerLoopTiming.PhysicsProcess); } /// /// Same as GDTask.Yield(PlayerLoopTiming.PhysicsProcess, cancellationToken). /// public static GDTask WaitForPhysicsProcess(CancellationToken cancellationToken) { return GDTask.Yield(PlayerLoopTiming.PhysicsProcess, cancellationToken); } public static GDTask DelayFrame(int delayFrameCount, PlayerLoopTiming delayTiming = PlayerLoopTiming.Process, CancellationToken cancellationToken = default(CancellationToken)) { if (delayFrameCount < 0) { throw new ArgumentOutOfRangeException("Delay does not allow minus delayFrameCount. delayFrameCount:" + delayFrameCount); } return new GDTask(DelayFramePromise.Create(delayFrameCount, delayTiming, cancellationToken, out var token), token); } public static GDTask Delay(int millisecondsDelay, PlayerLoopTiming delayTiming = PlayerLoopTiming.Process, CancellationToken cancellationToken = default(CancellationToken)) { var delayTimeSpan = TimeSpan.FromMilliseconds(millisecondsDelay); return Delay(delayTimeSpan, delayTiming, cancellationToken); } public static GDTask Delay(TimeSpan delayTimeSpan, PlayerLoopTiming delayTiming = PlayerLoopTiming.Process, CancellationToken cancellationToken = default(CancellationToken)) { return Delay(delayTimeSpan, DelayType.DeltaTime, delayTiming, cancellationToken); } public static GDTask Delay(int millisecondsDelay, DelayType delayType, PlayerLoopTiming delayTiming = PlayerLoopTiming.Process, CancellationToken cancellationToken = default(CancellationToken)) { var delayTimeSpan = TimeSpan.FromMilliseconds(millisecondsDelay); return Delay(delayTimeSpan, delayType, delayTiming, cancellationToken); } public static GDTask Delay(TimeSpan delayTimeSpan, DelayType delayType, PlayerLoopTiming delayTiming = PlayerLoopTiming.Process, CancellationToken cancellationToken = default(CancellationToken)) { if (delayTimeSpan < TimeSpan.Zero) { throw new ArgumentOutOfRangeException("Delay does not allow minus delayTimeSpan. delayTimeSpan:" + delayTimeSpan); } #if DEBUG // force use Realtime. if (GDTaskPlayerLoopAutoload.IsMainThread && Engine.IsEditorHint()) { delayType = DelayType.Realtime; } #endif switch (delayType) { case DelayType.Realtime: { return new GDTask(DelayRealtimePromise.Create(delayTimeSpan, delayTiming, cancellationToken, out var token), token); } case DelayType.DeltaTime: default: { return new GDTask(DelayPromise.Create(delayTimeSpan, delayTiming, cancellationToken, out var token), token); } } } sealed class YieldPromise : IGDTaskSource, IPlayerLoopItem, ITaskPoolNode { static TaskPool pool; YieldPromise nextNode; public ref YieldPromise NextNode => ref nextNode; static YieldPromise() { TaskPool.RegisterSizeGetter(typeof(YieldPromise), () => pool.Size); } CancellationToken cancellationToken; GDTaskCompletionSourceCore core; YieldPromise() { } public static IGDTaskSource Create(PlayerLoopTiming timing, CancellationToken cancellationToken, out short token) { if (cancellationToken.IsCancellationRequested) { return AutoResetGDTaskCompletionSource.CreateFromCanceled(cancellationToken, out token); } if (!pool.TryPop(out var result)) { result = new YieldPromise(); } result.cancellationToken = cancellationToken; TaskTracker.TrackActiveTask(result, 3); GDTaskPlayerLoopAutoload.AddAction(timing, result); token = result.core.Version; return result; } public void GetResult(short token) { try { core.GetResult(token); } finally { TryReturn(); } } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public bool MoveNext() { if (cancellationToken.IsCancellationRequested) { core.TrySetCanceled(cancellationToken); return false; } core.TrySetResult(null); return false; } bool TryReturn() { TaskTracker.RemoveTracking(this); core.Reset(); cancellationToken = default; return pool.TryPush(this); } } sealed class NextFramePromise : IGDTaskSource, IPlayerLoopItem, ITaskPoolNode { static TaskPool pool; NextFramePromise nextNode; public ref NextFramePromise NextNode => ref nextNode; static NextFramePromise() { TaskPool.RegisterSizeGetter(typeof(NextFramePromise), () => pool.Size); } bool isMainThread; ulong frameCount; CancellationToken cancellationToken; GDTaskCompletionSourceCore core; NextFramePromise() { } public static IGDTaskSource Create(PlayerLoopTiming timing, CancellationToken cancellationToken, out short token) { if (cancellationToken.IsCancellationRequested) { return AutoResetGDTaskCompletionSource.CreateFromCanceled(cancellationToken, out token); } if (!pool.TryPop(out var result)) { result = new NextFramePromise(); } result.isMainThread = GDTaskPlayerLoopAutoload.IsMainThread; if (result.isMainThread) result.frameCount = Engine.GetProcessFrames(); result.cancellationToken = cancellationToken; TaskTracker.TrackActiveTask(result, 3); GDTaskPlayerLoopAutoload.AddAction(timing, result); token = result.core.Version; return result; } public void GetResult(short token) { try { core.GetResult(token); } finally { TryReturn(); } } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public bool MoveNext() { if (cancellationToken.IsCancellationRequested) { core.TrySetCanceled(cancellationToken); return false; } if (isMainThread && frameCount == Engine.GetProcessFrames()) { return true; } core.TrySetResult(AsyncUnit.Default); return false; } bool TryReturn() { TaskTracker.RemoveTracking(this); core.Reset(); cancellationToken = default; return pool.TryPush(this); } } sealed class DelayFramePromise : IGDTaskSource, IPlayerLoopItem, ITaskPoolNode { static TaskPool pool; DelayFramePromise nextNode; public ref DelayFramePromise NextNode => ref nextNode; static DelayFramePromise() { TaskPool.RegisterSizeGetter(typeof(DelayFramePromise), () => pool.Size); } bool isMainThread; ulong initialFrame; int delayFrameCount; CancellationToken cancellationToken; int currentFrameCount; GDTaskCompletionSourceCore core; DelayFramePromise() { } public static IGDTaskSource Create(int delayFrameCount, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token) { if (cancellationToken.IsCancellationRequested) { return AutoResetGDTaskCompletionSource.CreateFromCanceled(cancellationToken, out token); } if (!pool.TryPop(out var result)) { result = new DelayFramePromise(); } result.delayFrameCount = delayFrameCount; result.cancellationToken = cancellationToken; result.isMainThread = GDTaskPlayerLoopAutoload.IsMainThread; if (result.isMainThread) result.initialFrame = Engine.GetProcessFrames(); TaskTracker.TrackActiveTask(result, 3); GDTaskPlayerLoopAutoload.AddAction(timing, result); token = result.core.Version; return result; } public void GetResult(short token) { try { core.GetResult(token); } finally { TryReturn(); } } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public bool MoveNext() { if (cancellationToken.IsCancellationRequested) { core.TrySetCanceled(cancellationToken); return false; } if (currentFrameCount == 0) { if (delayFrameCount == 0) // same as Yield { core.TrySetResult(AsyncUnit.Default); return false; } // skip in initial frame. if (isMainThread && initialFrame == Engine.GetProcessFrames()) { #if DEBUG // force use Realtime. if (GDTaskPlayerLoopAutoload.IsMainThread && Engine.IsEditorHint()) { //goto ++currentFrameCount } else { return true; } #else return true; #endif } } if (++currentFrameCount >= delayFrameCount) { core.TrySetResult(AsyncUnit.Default); return false; } return true; } bool TryReturn() { TaskTracker.RemoveTracking(this); core.Reset(); currentFrameCount = default; delayFrameCount = default; cancellationToken = default; return pool.TryPush(this); } } sealed class DelayPromise : IGDTaskSource, IPlayerLoopItem, ITaskPoolNode { static TaskPool pool; DelayPromise nextNode; public ref DelayPromise NextNode => ref nextNode; static DelayPromise() { TaskPool.RegisterSizeGetter(typeof(DelayPromise), () => pool.Size); } bool isMainThread; ulong initialFrame; double delayTimeSpan; double elapsed; PlayerLoopTiming timing; CancellationToken cancellationToken; GDTaskCompletionSourceCore core; DelayPromise() { } public static IGDTaskSource Create(TimeSpan delayTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token) { if (cancellationToken.IsCancellationRequested) { return AutoResetGDTaskCompletionSource.CreateFromCanceled(cancellationToken, out token); } if (!pool.TryPop(out var result)) { result = new DelayPromise(); } result.elapsed = 0.0f; result.delayTimeSpan = (float)delayTimeSpan.TotalSeconds; result.cancellationToken = cancellationToken; result.isMainThread = GDTaskPlayerLoopAutoload.IsMainThread; result.timing = timing; if (result.isMainThread) result.initialFrame = Engine.GetProcessFrames(); TaskTracker.TrackActiveTask(result, 3); GDTaskPlayerLoopAutoload.AddAction(timing, result); token = result.core.Version; return result; } public void GetResult(short token) { try { core.GetResult(token); } finally { TryReturn(); } } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public bool MoveNext() { if (cancellationToken.IsCancellationRequested) { core.TrySetCanceled(cancellationToken); return false; } if (elapsed == 0.0f) { if (isMainThread && initialFrame == Engine.GetProcessFrames()) { return true; } } if (timing == PlayerLoopTiming.Process || timing == PlayerLoopTiming.PauseProcess) elapsed += GDTaskPlayerLoopAutoload.Global.DeltaTime; else elapsed += GDTaskPlayerLoopAutoload.Global.PhysicsDeltaTime; if (elapsed >= delayTimeSpan) { core.TrySetResult(null); return false; } return true; } bool TryReturn() { TaskTracker.RemoveTracking(this); core.Reset(); delayTimeSpan = default; elapsed = default; cancellationToken = default; return pool.TryPush(this); } } sealed class DelayRealtimePromise : IGDTaskSource, IPlayerLoopItem, ITaskPoolNode { static TaskPool pool; DelayRealtimePromise nextNode; public ref DelayRealtimePromise NextNode => ref nextNode; static DelayRealtimePromise() { TaskPool.RegisterSizeGetter(typeof(DelayRealtimePromise), () => pool.Size); } long delayTimeSpanTicks; ValueStopwatch stopwatch; CancellationToken cancellationToken; GDTaskCompletionSourceCore core; DelayRealtimePromise() { } public static IGDTaskSource Create(TimeSpan delayTimeSpan, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token) { if (cancellationToken.IsCancellationRequested) { return AutoResetGDTaskCompletionSource.CreateFromCanceled(cancellationToken, out token); } if (!pool.TryPop(out var result)) { result = new DelayRealtimePromise(); } result.stopwatch = ValueStopwatch.StartNew(); result.delayTimeSpanTicks = delayTimeSpan.Ticks; result.cancellationToken = cancellationToken; TaskTracker.TrackActiveTask(result, 3); GDTaskPlayerLoopAutoload.AddAction(timing, result); token = result.core.Version; return result; } public void GetResult(short token) { try { core.GetResult(token); } finally { TryReturn(); } } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public bool MoveNext() { if (cancellationToken.IsCancellationRequested) { core.TrySetCanceled(cancellationToken); return false; } if (stopwatch.IsInvalid) { core.TrySetResult(AsyncUnit.Default); return false; } if (stopwatch.ElapsedTicks >= delayTimeSpanTicks) { core.TrySetResult(AsyncUnit.Default); return false; } return true; } bool TryReturn() { TaskTracker.RemoveTracking(this); core.Reset(); stopwatch = default; cancellationToken = default; return pool.TryPush(this); } } } public readonly struct YieldAwaitable { readonly PlayerLoopTiming timing; public YieldAwaitable(PlayerLoopTiming timing) { this.timing = timing; } public Awaiter GetAwaiter() { return new Awaiter(timing); } public GDTask ToGDTask() { return GDTask.Yield(timing, CancellationToken.None); } public readonly struct Awaiter : ICriticalNotifyCompletion { readonly PlayerLoopTiming timing; public Awaiter(PlayerLoopTiming timing) { this.timing = timing; } public bool IsCompleted => false; public void GetResult() { } public void OnCompleted(Action continuation) { GDTaskPlayerLoopAutoload.AddContinuation(timing, continuation); } public void UnsafeOnCompleted(Action continuation) { GDTaskPlayerLoopAutoload.AddContinuation(timing, continuation); } } } } ================================================ FILE: addons/GDTask/GDTask.Delay.cs.uid ================================================ uid://btyvmsmlux4qq ================================================ FILE: addons/GDTask/GDTask.Factory.cs ================================================ using Fractural.Tasks.Internal; using System; using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; using System.Threading; namespace Fractural.Tasks { public partial struct GDTask { static readonly GDTask CanceledGDTask = new Func(() => { return new GDTask(new CanceledResultSource(CancellationToken.None), 0); })(); static class CanceledGDTaskCache { public static readonly GDTask Task; static CanceledGDTaskCache() { Task = new GDTask(new CanceledResultSource(CancellationToken.None), 0); } } public static readonly GDTask CompletedTask = new GDTask(); public static GDTask FromException(Exception ex) { if (ex is OperationCanceledException oce) { return FromCanceled(oce.CancellationToken); } return new GDTask(new ExceptionResultSource(ex), 0); } public static GDTask FromException(Exception ex) { if (ex is OperationCanceledException oce) { return FromCanceled(oce.CancellationToken); } return new GDTask(new ExceptionResultSource(ex), 0); } public static GDTask FromResult(T value) { return new GDTask(value); } public static GDTask FromCanceled(CancellationToken cancellationToken = default) { if (cancellationToken == CancellationToken.None) { return CanceledGDTask; } else { return new GDTask(new CanceledResultSource(cancellationToken), 0); } } public static GDTask FromCanceled(CancellationToken cancellationToken = default) { if (cancellationToken == CancellationToken.None) { return CanceledGDTaskCache.Task; } else { return new GDTask(new CanceledResultSource(cancellationToken), 0); } } public static GDTask Create(Func factory) { return factory(); } public static GDTask Create(Func> factory) { return factory(); } public static AsyncLazy Lazy(Func factory) { return new AsyncLazy(factory); } public static AsyncLazy Lazy(Func> factory) { return new AsyncLazy(factory); } /// /// helper of fire and forget void action. /// public static void Void(Func asyncAction) { asyncAction().Forget(); } /// /// helper of fire and forget void action. /// public static void Void(Func asyncAction, CancellationToken cancellationToken) { asyncAction(cancellationToken).Forget(); } /// /// helper of fire and forget void action. /// public static void Void(Func asyncAction, T state) { asyncAction(state).Forget(); } /// /// helper of create add GDTaskVoid to delegate. /// For example: FooAction = GDTask.Action(async () => { /* */ }) /// public static Action Action(Func asyncAction) { return () => asyncAction().Forget(); } /// /// helper of create add GDTaskVoid to delegate. /// public static Action Action(Func asyncAction, CancellationToken cancellationToken) { return () => asyncAction(cancellationToken).Forget(); } /// /// Defer the task creation just before call await. /// public static GDTask Defer(Func factory) { return new GDTask(new DeferPromise(factory), 0); } /// /// Defer the task creation just before call await. /// public static GDTask Defer(Func> factory) { return new GDTask(new DeferPromise(factory), 0); } /// /// Never complete. /// public static GDTask Never(CancellationToken cancellationToken = default) { return new GDTask(new NeverPromise(cancellationToken), 0); } /// /// Never complete. /// public static GDTask Never(CancellationToken cancellationToken = default) { return new GDTask(new NeverPromise(cancellationToken), 0); } sealed class ExceptionResultSource : IGDTaskSource { readonly ExceptionDispatchInfo exception; bool calledGet; public ExceptionResultSource(Exception exception) { this.exception = ExceptionDispatchInfo.Capture(exception); } public void GetResult(short token) { if (!calledGet) { calledGet = true; GC.SuppressFinalize(this); } exception.Throw(); } public GDTaskStatus GetStatus(short token) { return GDTaskStatus.Faulted; } public GDTaskStatus UnsafeGetStatus() { return GDTaskStatus.Faulted; } public void OnCompleted(Action continuation, object state, short token) { continuation(state); } ~ExceptionResultSource() { if (!calledGet) { GDTaskScheduler.PublishUnobservedTaskException(exception.SourceException); } } } sealed class ExceptionResultSource : IGDTaskSource { readonly ExceptionDispatchInfo exception; bool calledGet; public ExceptionResultSource(Exception exception) { this.exception = ExceptionDispatchInfo.Capture(exception); } public T GetResult(short token) { if (!calledGet) { calledGet = true; GC.SuppressFinalize(this); } exception.Throw(); return default; } void IGDTaskSource.GetResult(short token) { if (!calledGet) { calledGet = true; GC.SuppressFinalize(this); } exception.Throw(); } public GDTaskStatus GetStatus(short token) { return GDTaskStatus.Faulted; } public GDTaskStatus UnsafeGetStatus() { return GDTaskStatus.Faulted; } public void OnCompleted(Action continuation, object state, short token) { continuation(state); } ~ExceptionResultSource() { if (!calledGet) { GDTaskScheduler.PublishUnobservedTaskException(exception.SourceException); } } } sealed class CanceledResultSource : IGDTaskSource { readonly CancellationToken cancellationToken; public CanceledResultSource(CancellationToken cancellationToken) { this.cancellationToken = cancellationToken; } public void GetResult(short token) { throw new OperationCanceledException(cancellationToken); } public GDTaskStatus GetStatus(short token) { return GDTaskStatus.Canceled; } public GDTaskStatus UnsafeGetStatus() { return GDTaskStatus.Canceled; } public void OnCompleted(Action continuation, object state, short token) { continuation(state); } } sealed class CanceledResultSource : IGDTaskSource { readonly CancellationToken cancellationToken; public CanceledResultSource(CancellationToken cancellationToken) { this.cancellationToken = cancellationToken; } public T GetResult(short token) { throw new OperationCanceledException(cancellationToken); } void IGDTaskSource.GetResult(short token) { throw new OperationCanceledException(cancellationToken); } public GDTaskStatus GetStatus(short token) { return GDTaskStatus.Canceled; } public GDTaskStatus UnsafeGetStatus() { return GDTaskStatus.Canceled; } public void OnCompleted(Action continuation, object state, short token) { continuation(state); } } sealed class DeferPromise : IGDTaskSource { Func factory; GDTask task; GDTask.Awaiter awaiter; public DeferPromise(Func factory) { this.factory = factory; } public void GetResult(short token) { awaiter.GetResult(); } public GDTaskStatus GetStatus(short token) { var f = Interlocked.Exchange(ref factory, null); if (f != null) { task = f(); awaiter = task.GetAwaiter(); } return task.Status; } public void OnCompleted(Action continuation, object state, short token) { awaiter.SourceOnCompleted(continuation, state); } public GDTaskStatus UnsafeGetStatus() { return task.Status; } } sealed class DeferPromise : IGDTaskSource { Func> factory; GDTask task; GDTask.Awaiter awaiter; public DeferPromise(Func> factory) { this.factory = factory; } public T GetResult(short token) { return awaiter.GetResult(); } void IGDTaskSource.GetResult(short token) { awaiter.GetResult(); } public GDTaskStatus GetStatus(short token) { var f = Interlocked.Exchange(ref factory, null); if (f != null) { task = f(); awaiter = task.GetAwaiter(); } return task.Status; } public void OnCompleted(Action continuation, object state, short token) { awaiter.SourceOnCompleted(continuation, state); } public GDTaskStatus UnsafeGetStatus() { return task.Status; } } sealed class NeverPromise : IGDTaskSource { static readonly Action cancellationCallback = CancellationCallback; CancellationToken cancellationToken; GDTaskCompletionSourceCore core; public NeverPromise(CancellationToken cancellationToken) { this.cancellationToken = cancellationToken; if (this.cancellationToken.CanBeCanceled) { this.cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, this); } } static void CancellationCallback(object state) { var self = (NeverPromise)state; self.core.TrySetCanceled(self.cancellationToken); } public T GetResult(short token) { return core.GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } void IGDTaskSource.GetResult(short token) { core.GetResult(token); } } } internal static class CompletedTasks { public static readonly GDTask AsyncUnit = GDTask.FromResult(Fractural.Tasks.AsyncUnit.Default); public static readonly GDTask True = GDTask.FromResult(true); public static readonly GDTask False = GDTask.FromResult(false); public static readonly GDTask Zero = GDTask.FromResult(0); public static readonly GDTask MinusOne = GDTask.FromResult(-1); public static readonly GDTask One = GDTask.FromResult(1); } } ================================================ FILE: addons/GDTask/GDTask.Factory.cs.uid ================================================ uid://p3ayqohsixwx ================================================ FILE: addons/GDTask/GDTask.Run.cs ================================================ using System; using System.Threading; namespace Fractural.Tasks { public partial struct GDTask { #region OBSOLETE_RUN [Obsolete("GDTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use GDTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use GDTask.Void(async void) or GDTask.Create(async GDTask) too.")] public static GDTask Run(Action action, bool configureAwait = true, CancellationToken cancellationToken = default) { return RunOnThreadPool(action, configureAwait, cancellationToken); } [Obsolete("GDTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use GDTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use GDTask.Void(async void) or GDTask.Create(async GDTask) too.")] public static GDTask Run(Action action, object state, bool configureAwait = true, CancellationToken cancellationToken = default) { return RunOnThreadPool(action, state, configureAwait, cancellationToken); } [Obsolete("GDTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use GDTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use GDTask.Void(async void) or GDTask.Create(async GDTask) too.")] public static GDTask Run(Func action, bool configureAwait = true, CancellationToken cancellationToken = default) { return RunOnThreadPool(action, configureAwait, cancellationToken); } [Obsolete("GDTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use GDTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use GDTask.Void(async void) or GDTask.Create(async GDTask) too.")] public static GDTask Run(Func action, object state, bool configureAwait = true, CancellationToken cancellationToken = default) { return RunOnThreadPool(action, state, configureAwait, cancellationToken); } [Obsolete("GDTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use GDTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use GDTask.Void(async void) or GDTask.Create(async GDTask) too.")] public static GDTask Run(Func func, bool configureAwait = true, CancellationToken cancellationToken = default) { return RunOnThreadPool(func, configureAwait, cancellationToken); } [Obsolete("GDTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use GDTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use GDTask.Void(async void) or GDTask.Create(async GDTask) too.")] public static GDTask Run(Func> func, bool configureAwait = true, CancellationToken cancellationToken = default) { return RunOnThreadPool(func, configureAwait, cancellationToken); } [Obsolete("GDTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use GDTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use GDTask.Void(async void) or GDTask.Create(async GDTask) too.")] public static GDTask Run(Func func, object state, bool configureAwait = true, CancellationToken cancellationToken = default) { return RunOnThreadPool(func, state, configureAwait, cancellationToken); } [Obsolete("GDTask.Run is similar as Task.Run, it uses ThreadPool. For equivalent behaviour, use GDTask.RunOnThreadPool instead. If you don't want to use ThreadPool, you can use GDTask.Void(async void) or GDTask.Create(async GDTask) too.")] public static GDTask Run(Func> func, object state, bool configureAwait = true, CancellationToken cancellationToken = default) { return RunOnThreadPool(func, state, configureAwait, cancellationToken); } #endregion /// Run action on the threadPool and return to main thread if configureAwait = true. public static async GDTask RunOnThreadPool(Action action, bool configureAwait = true, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); await GDTask.SwitchToThreadPool(); cancellationToken.ThrowIfCancellationRequested(); if (configureAwait) { try { action(); } finally { await GDTask.Yield(); } } else { action(); } cancellationToken.ThrowIfCancellationRequested(); } /// Run action on the threadPool and return to main thread if configureAwait = true. public static async GDTask RunOnThreadPool(Action action, object state, bool configureAwait = true, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); await GDTask.SwitchToThreadPool(); cancellationToken.ThrowIfCancellationRequested(); if (configureAwait) { try { action(state); } finally { await GDTask.Yield(); } } else { action(state); } cancellationToken.ThrowIfCancellationRequested(); } /// Run action on the threadPool and return to main thread if configureAwait = true. public static async GDTask RunOnThreadPool(Func action, bool configureAwait = true, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); await GDTask.SwitchToThreadPool(); cancellationToken.ThrowIfCancellationRequested(); if (configureAwait) { try { await action(); } finally { await GDTask.Yield(); } } else { await action(); } cancellationToken.ThrowIfCancellationRequested(); } /// Run action on the threadPool and return to main thread if configureAwait = true. public static async GDTask RunOnThreadPool(Func action, object state, bool configureAwait = true, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); await GDTask.SwitchToThreadPool(); cancellationToken.ThrowIfCancellationRequested(); if (configureAwait) { try { await action(state); } finally { await GDTask.Yield(); } } else { await action(state); } cancellationToken.ThrowIfCancellationRequested(); } /// Run action on the threadPool and return to main thread if configureAwait = true. public static async GDTask RunOnThreadPool(Func func, bool configureAwait = true, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); await GDTask.SwitchToThreadPool(); cancellationToken.ThrowIfCancellationRequested(); if (configureAwait) { try { return func(); } finally { await GDTask.Yield(); cancellationToken.ThrowIfCancellationRequested(); } } else { return func(); } } /// Run action on the threadPool and return to main thread if configureAwait = true. public static async GDTask RunOnThreadPool(Func> func, bool configureAwait = true, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); await GDTask.SwitchToThreadPool(); cancellationToken.ThrowIfCancellationRequested(); if (configureAwait) { try { return await func(); } finally { cancellationToken.ThrowIfCancellationRequested(); await GDTask.Yield(); cancellationToken.ThrowIfCancellationRequested(); } } else { var result = await func(); cancellationToken.ThrowIfCancellationRequested(); return result; } } /// Run action on the threadPool and return to main thread if configureAwait = true. public static async GDTask RunOnThreadPool(Func func, object state, bool configureAwait = true, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); await GDTask.SwitchToThreadPool(); cancellationToken.ThrowIfCancellationRequested(); if (configureAwait) { try { return func(state); } finally { await GDTask.Yield(); cancellationToken.ThrowIfCancellationRequested(); } } else { return func(state); } } /// Run action on the threadPool and return to main thread if configureAwait = true. public static async GDTask RunOnThreadPool(Func> func, object state, bool configureAwait = true, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); await GDTask.SwitchToThreadPool(); cancellationToken.ThrowIfCancellationRequested(); if (configureAwait) { try { return await func(state); } finally { cancellationToken.ThrowIfCancellationRequested(); await GDTask.Yield(); cancellationToken.ThrowIfCancellationRequested(); } } else { var result = await func(state); cancellationToken.ThrowIfCancellationRequested(); return result; } } } } ================================================ FILE: addons/GDTask/GDTask.Run.cs.uid ================================================ uid://daid4jdjbp0au ================================================ FILE: addons/GDTask/GDTask.Threading.cs ================================================ using System; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using Fractural.Tasks.Internal; namespace Fractural.Tasks { public partial struct GDTask { /// /// If running on mainthread, do nothing. Otherwise, same as GDTask.Yield(PlayerLoopTiming.Update). /// public static SwitchToMainThreadAwaitable SwitchToMainThread(CancellationToken cancellationToken = default) { return new SwitchToMainThreadAwaitable(PlayerLoopTiming.Process, cancellationToken); } /// /// If running on mainthread, do nothing. Otherwise, same as GDTask.Yield(timing). /// public static SwitchToMainThreadAwaitable SwitchToMainThread(PlayerLoopTiming timing, CancellationToken cancellationToken = default) { return new SwitchToMainThreadAwaitable(timing, cancellationToken); } /// /// Return to mainthread(same as await SwitchToMainThread) after using scope is closed. /// public static ReturnToMainThread ReturnToMainThread(CancellationToken cancellationToken = default) { return new ReturnToMainThread(PlayerLoopTiming.Process, cancellationToken); } /// /// Return to mainthread(same as await SwitchToMainThread) after using scope is closed. /// public static ReturnToMainThread ReturnToMainThread(PlayerLoopTiming timing, CancellationToken cancellationToken = default) { return new ReturnToMainThread(timing, cancellationToken); } /// /// Queue the action to PlayerLoop. /// public static void Post(Action action, PlayerLoopTiming timing = PlayerLoopTiming.Process) { GDTaskPlayerLoopAutoload.AddContinuation(timing, action); } public static SwitchToThreadPoolAwaitable SwitchToThreadPool() { return new SwitchToThreadPoolAwaitable(); } /// /// Note: use SwitchToThreadPool is recommended. /// public static SwitchToTaskPoolAwaitable SwitchToTaskPool() { return new SwitchToTaskPoolAwaitable(); } public static SwitchToSynchronizationContextAwaitable SwitchToSynchronizationContext(SynchronizationContext synchronizationContext, CancellationToken cancellationToken = default) { Error.ThrowArgumentNullException(synchronizationContext, nameof(synchronizationContext)); return new SwitchToSynchronizationContextAwaitable(synchronizationContext, cancellationToken); } public static ReturnToSynchronizationContext ReturnToSynchronizationContext(SynchronizationContext synchronizationContext, CancellationToken cancellationToken = default) { return new ReturnToSynchronizationContext(synchronizationContext, false, cancellationToken); } public static ReturnToSynchronizationContext ReturnToCurrentSynchronizationContext(bool dontPostWhenSameContext = true, CancellationToken cancellationToken = default) { return new ReturnToSynchronizationContext(SynchronizationContext.Current, dontPostWhenSameContext, cancellationToken); } } public struct SwitchToMainThreadAwaitable { readonly PlayerLoopTiming playerLoopTiming; readonly CancellationToken cancellationToken; public SwitchToMainThreadAwaitable(PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken) { this.playerLoopTiming = playerLoopTiming; this.cancellationToken = cancellationToken; } public Awaiter GetAwaiter() => new Awaiter(playerLoopTiming, cancellationToken); public struct Awaiter : ICriticalNotifyCompletion { readonly PlayerLoopTiming playerLoopTiming; readonly CancellationToken cancellationToken; public Awaiter(PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken) { this.playerLoopTiming = playerLoopTiming; this.cancellationToken = cancellationToken; } public bool IsCompleted { get { var currentThreadId = System.Threading.Thread.CurrentThread.ManagedThreadId; if (GDTaskPlayerLoopAutoload.MainThreadId == currentThreadId) { return true; // run immediate. } else { return false; // register continuation. } } } public void GetResult() { cancellationToken.ThrowIfCancellationRequested(); } public void OnCompleted(Action continuation) { GDTaskPlayerLoopAutoload.AddContinuation(playerLoopTiming, continuation); } public void UnsafeOnCompleted(Action continuation) { GDTaskPlayerLoopAutoload.AddContinuation(playerLoopTiming, continuation); } } } public struct ReturnToMainThread { readonly PlayerLoopTiming playerLoopTiming; readonly CancellationToken cancellationToken; public ReturnToMainThread(PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken) { this.playerLoopTiming = playerLoopTiming; this.cancellationToken = cancellationToken; } public Awaiter DisposeAsync() { return new Awaiter(playerLoopTiming, cancellationToken); // run immediate. } public readonly struct Awaiter : ICriticalNotifyCompletion { readonly PlayerLoopTiming timing; readonly CancellationToken cancellationToken; public Awaiter(PlayerLoopTiming timing, CancellationToken cancellationToken) { this.timing = timing; this.cancellationToken = cancellationToken; } public Awaiter GetAwaiter() => this; public bool IsCompleted => GDTaskPlayerLoopAutoload.MainThreadId == System.Threading.Thread.CurrentThread.ManagedThreadId; public void GetResult() { cancellationToken.ThrowIfCancellationRequested(); } public void OnCompleted(Action continuation) { GDTaskPlayerLoopAutoload.AddContinuation(timing, continuation); } public void UnsafeOnCompleted(Action continuation) { GDTaskPlayerLoopAutoload.AddContinuation(timing, continuation); } } } public struct SwitchToThreadPoolAwaitable { public Awaiter GetAwaiter() => new Awaiter(); public struct Awaiter : ICriticalNotifyCompletion { static readonly WaitCallback switchToCallback = Callback; public bool IsCompleted => false; public void GetResult() { } public void OnCompleted(Action continuation) { ThreadPool.QueueUserWorkItem(switchToCallback, continuation); } public void UnsafeOnCompleted(Action continuation) { ThreadPool.UnsafeQueueUserWorkItem(switchToCallback, continuation); } static void Callback(object state) { var continuation = (Action)state; continuation(); } } } public struct SwitchToTaskPoolAwaitable { public Awaiter GetAwaiter() => new Awaiter(); public struct Awaiter : ICriticalNotifyCompletion { static readonly Action switchToCallback = Callback; public bool IsCompleted => false; public void GetResult() { } public void OnCompleted(Action continuation) { Task.Factory.StartNew(switchToCallback, continuation, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); } public void UnsafeOnCompleted(Action continuation) { Task.Factory.StartNew(switchToCallback, continuation, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); } static void Callback(object state) { var continuation = (Action)state; continuation(); } } } public struct SwitchToSynchronizationContextAwaitable { readonly SynchronizationContext synchronizationContext; readonly CancellationToken cancellationToken; public SwitchToSynchronizationContextAwaitable(SynchronizationContext synchronizationContext, CancellationToken cancellationToken) { this.synchronizationContext = synchronizationContext; this.cancellationToken = cancellationToken; } public Awaiter GetAwaiter() => new Awaiter(synchronizationContext, cancellationToken); public struct Awaiter : ICriticalNotifyCompletion { static readonly SendOrPostCallback switchToCallback = Callback; readonly SynchronizationContext synchronizationContext; readonly CancellationToken cancellationToken; public Awaiter(SynchronizationContext synchronizationContext, CancellationToken cancellationToken) { this.synchronizationContext = synchronizationContext; this.cancellationToken = cancellationToken; } public bool IsCompleted => false; public void GetResult() { cancellationToken.ThrowIfCancellationRequested(); } public void OnCompleted(Action continuation) { synchronizationContext.Post(switchToCallback, continuation); } public void UnsafeOnCompleted(Action continuation) { synchronizationContext.Post(switchToCallback, continuation); } static void Callback(object state) { var continuation = (Action)state; continuation(); } } } public struct ReturnToSynchronizationContext { readonly SynchronizationContext syncContext; readonly bool dontPostWhenSameContext; readonly CancellationToken cancellationToken; public ReturnToSynchronizationContext(SynchronizationContext syncContext, bool dontPostWhenSameContext, CancellationToken cancellationToken) { this.syncContext = syncContext; this.dontPostWhenSameContext = dontPostWhenSameContext; this.cancellationToken = cancellationToken; } public Awaiter DisposeAsync() { return new Awaiter(syncContext, dontPostWhenSameContext, cancellationToken); } public struct Awaiter : ICriticalNotifyCompletion { static readonly SendOrPostCallback switchToCallback = Callback; readonly SynchronizationContext synchronizationContext; readonly bool dontPostWhenSameContext; readonly CancellationToken cancellationToken; public Awaiter(SynchronizationContext synchronizationContext, bool dontPostWhenSameContext, CancellationToken cancellationToken) { this.synchronizationContext = synchronizationContext; this.dontPostWhenSameContext = dontPostWhenSameContext; this.cancellationToken = cancellationToken; } public Awaiter GetAwaiter() => this; public bool IsCompleted { get { if (!dontPostWhenSameContext) return false; var current = SynchronizationContext.Current; if (current == synchronizationContext) { return true; } else { return false; } } } public void GetResult() { cancellationToken.ThrowIfCancellationRequested(); } public void OnCompleted(Action continuation) { synchronizationContext.Post(switchToCallback, continuation); } public void UnsafeOnCompleted(Action continuation) { synchronizationContext.Post(switchToCallback, continuation); } static void Callback(object state) { var continuation = (Action)state; continuation(); } } } } ================================================ FILE: addons/GDTask/GDTask.Threading.cs.uid ================================================ uid://dwpp8canxmyfw ================================================ FILE: addons/GDTask/GDTask.ToSignal.cs ================================================ using Godot; using System.Threading; namespace Fractural.Tasks { public partial struct GDTask { public static async GDTask ToSignal(GodotObject self, StringName signal) { return await self.ToSignal(self, signal); } public static async GDTask ToSignal(GodotObject self, StringName signal, CancellationToken ct) { 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; } } } ================================================ FILE: addons/GDTask/GDTask.ToSignal.cs.uid ================================================ uid://coomhn117gtgx ================================================ FILE: addons/GDTask/GDTask.WaitUntil.cs ================================================ using System; using System.Collections.Generic; using System.Threading; using Fractural.Tasks.Internal; using Godot; namespace Fractural.Tasks { public partial struct GDTask { public static GDTask WaitUntil(GodotObject target, Func predicate, PlayerLoopTiming timing = PlayerLoopTiming.Process, CancellationToken cancellationToken = default) { return new GDTask(WaitUntilPromise.Create(target, predicate, timing, cancellationToken, out var token), token); } public static GDTask WaitUntil(Func predicate, PlayerLoopTiming timing = PlayerLoopTiming.Process, CancellationToken cancellationToken = default) { return WaitUntil(null, predicate, timing, cancellationToken); } public static GDTask WaitWhile(GodotObject target, Func predicate, PlayerLoopTiming timing = PlayerLoopTiming.Process, CancellationToken cancellationToken = default) { return new GDTask(WaitWhilePromise.Create(target, predicate, timing, cancellationToken, out var token), token); } public static GDTask WaitWhile(Func predicate, PlayerLoopTiming timing = PlayerLoopTiming.Process, CancellationToken cancellationToken = default) { return WaitWhile(null, predicate, timing, cancellationToken); } public static GDTask WaitUntilCanceled(GodotObject target, CancellationToken cancellationToken, PlayerLoopTiming timing = PlayerLoopTiming.Process) { return new GDTask(WaitUntilCanceledPromise.Create(target, cancellationToken, timing, out var token), token); } public static GDTask WaitUntilCanceled(CancellationToken cancellationToken, PlayerLoopTiming timing = PlayerLoopTiming.Process) { return WaitUntilCanceled(null, cancellationToken, timing); } public static GDTask WaitUntilValueChanged(T target, Func monitorFunction, PlayerLoopTiming monitorTiming = PlayerLoopTiming.Process, IEqualityComparer equalityComparer = null, CancellationToken cancellationToken = default) where T : class { return new GDTask(target is GodotObject ? WaitUntilValueChangedGodotObjectPromise.Create(target, monitorFunction, equalityComparer, monitorTiming, cancellationToken, out var token) : WaitUntilValueChangedStandardObjectPromise.Create(target, monitorFunction, equalityComparer, monitorTiming, cancellationToken, out token), token); } sealed class WaitUntilPromise : IGDTaskSource, IPlayerLoopItem, ITaskPoolNode { static TaskPool pool; WaitUntilPromise nextNode; public ref WaitUntilPromise NextNode => ref nextNode; static WaitUntilPromise() { TaskPool.RegisterSizeGetter(typeof(WaitUntilPromise), () => pool.Size); } GodotObject target; Func predicate; CancellationToken cancellationToken; GDTaskCompletionSourceCore core; WaitUntilPromise() { } public static IGDTaskSource Create(GodotObject target, Func predicate, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token) { if (cancellationToken.IsCancellationRequested) { return AutoResetGDTaskCompletionSource.CreateFromCanceled(cancellationToken, out token); } if (!pool.TryPop(out var result)) { result = new WaitUntilPromise(); } result.target = target; result.predicate = predicate; result.cancellationToken = cancellationToken; TaskTracker.TrackActiveTask(result, 3); GDTaskPlayerLoopAutoload.AddAction(timing, result); token = result.core.Version; return result; } public void GetResult(short token) { try { core.GetResult(token); } finally { TryReturn(); } } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public bool MoveNext() { if (cancellationToken.IsCancellationRequested || (target is not null && !GodotObject.IsInstanceValid(target))) // Cancel when destroyed { core.TrySetCanceled(cancellationToken); return false; } try { if (!predicate()) { return true; } } catch (Exception ex) { core.TrySetException(ex); return false; } core.TrySetResult(null); return false; } bool TryReturn() { TaskTracker.RemoveTracking(this); core.Reset(); predicate = default; cancellationToken = default; return pool.TryPush(this); } } sealed class WaitWhilePromise : IGDTaskSource, IPlayerLoopItem, ITaskPoolNode { static TaskPool pool; WaitWhilePromise nextNode; public ref WaitWhilePromise NextNode => ref nextNode; static WaitWhilePromise() { TaskPool.RegisterSizeGetter(typeof(WaitWhilePromise), () => pool.Size); } GodotObject target; Func predicate; CancellationToken cancellationToken; GDTaskCompletionSourceCore core; WaitWhilePromise() { } public static IGDTaskSource Create(GodotObject target, Func predicate, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token) { if (cancellationToken.IsCancellationRequested) { return AutoResetGDTaskCompletionSource.CreateFromCanceled(cancellationToken, out token); } if (!pool.TryPop(out var result)) { result = new WaitWhilePromise(); } result.target = target; result.predicate = predicate; result.cancellationToken = cancellationToken; TaskTracker.TrackActiveTask(result, 3); GDTaskPlayerLoopAutoload.AddAction(timing, result); token = result.core.Version; return result; } public void GetResult(short token) { try { core.GetResult(token); } finally { TryReturn(); } } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public bool MoveNext() { if (cancellationToken.IsCancellationRequested || (target is not null && !GodotObject.IsInstanceValid(target))) // Cancel when destroyed { core.TrySetCanceled(cancellationToken); return false; } try { if (predicate()) { return true; } } catch (Exception ex) { core.TrySetException(ex); return false; } core.TrySetResult(null); return false; } bool TryReturn() { TaskTracker.RemoveTracking(this); core.Reset(); predicate = default; cancellationToken = default; return pool.TryPush(this); } } sealed class WaitUntilCanceledPromise : IGDTaskSource, IPlayerLoopItem, ITaskPoolNode { static TaskPool pool; WaitUntilCanceledPromise nextNode; public ref WaitUntilCanceledPromise NextNode => ref nextNode; static WaitUntilCanceledPromise() { TaskPool.RegisterSizeGetter(typeof(WaitUntilCanceledPromise), () => pool.Size); } GodotObject target; CancellationToken cancellationToken; GDTaskCompletionSourceCore core; WaitUntilCanceledPromise() { } public static IGDTaskSource Create(GodotObject target, CancellationToken cancellationToken, PlayerLoopTiming timing, out short token) { if (cancellationToken.IsCancellationRequested) { return AutoResetGDTaskCompletionSource.CreateFromCanceled(cancellationToken, out token); } if (!pool.TryPop(out var result)) { result = new WaitUntilCanceledPromise(); } result.target = target; result.cancellationToken = cancellationToken; TaskTracker.TrackActiveTask(result, 3); GDTaskPlayerLoopAutoload.AddAction(timing, result); token = result.core.Version; return result; } public void GetResult(short token) { try { core.GetResult(token); } finally { TryReturn(); } } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public bool MoveNext() { if (cancellationToken.IsCancellationRequested || (target is not null && !GodotObject.IsInstanceValid(target))) // Cancel when destroyed { core.TrySetResult(null); return false; } return true; } bool TryReturn() { TaskTracker.RemoveTracking(this); core.Reset(); cancellationToken = default; return pool.TryPush(this); } } // Cannot add `where T : GodotObject` because `WaitUntilValueChanged` doesn't have the constraint. sealed class WaitUntilValueChangedGodotObjectPromise : IGDTaskSource, IPlayerLoopItem, ITaskPoolNode> { static TaskPool> pool; WaitUntilValueChangedGodotObjectPromise nextNode; public ref WaitUntilValueChangedGodotObjectPromise NextNode => ref nextNode; static WaitUntilValueChangedGodotObjectPromise() { TaskPool.RegisterSizeGetter(typeof(WaitUntilValueChangedGodotObjectPromise), () => pool.Size); } T target; GodotObject targetGodotObject; U currentValue; Func monitorFunction; IEqualityComparer equalityComparer; CancellationToken cancellationToken; GDTaskCompletionSourceCore core; WaitUntilValueChangedGodotObjectPromise() { } public static IGDTaskSource Create(T target, Func monitorFunction, IEqualityComparer equalityComparer, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token) { if (cancellationToken.IsCancellationRequested) { return AutoResetGDTaskCompletionSource.CreateFromCanceled(cancellationToken, out token); } if (!pool.TryPop(out var result)) { result = new WaitUntilValueChangedGodotObjectPromise(); } result.target = target; result.targetGodotObject = target as GodotObject; result.monitorFunction = monitorFunction; result.currentValue = monitorFunction(target); result.equalityComparer = equalityComparer ?? GodotEqualityComparer.GetDefault(); result.cancellationToken = cancellationToken; TaskTracker.TrackActiveTask(result, 3); GDTaskPlayerLoopAutoload.AddAction(timing, result); token = result.core.Version; return result; } public U GetResult(short token) { try { return core.GetResult(token); } finally { TryReturn(); } } void IGDTaskSource.GetResult(short token) { GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public bool MoveNext() { if (cancellationToken.IsCancellationRequested || (target is not null && !GodotObject.IsInstanceValid(targetGodotObject))) // Cancel when destroyed { core.TrySetCanceled(cancellationToken); return false; } U nextValue = default; try { nextValue = monitorFunction(target); if (equalityComparer.Equals(currentValue, nextValue)) { return true; } } catch (Exception ex) { core.TrySetException(ex); return false; } core.TrySetResult(nextValue); return false; } bool TryReturn() { TaskTracker.RemoveTracking(this); core.Reset(); target = default; currentValue = default; monitorFunction = default; equalityComparer = default; cancellationToken = default; return pool.TryPush(this); } } sealed class WaitUntilValueChangedStandardObjectPromise : IGDTaskSource, IPlayerLoopItem, ITaskPoolNode> where T : class { static TaskPool> pool; WaitUntilValueChangedStandardObjectPromise nextNode; public ref WaitUntilValueChangedStandardObjectPromise NextNode => ref nextNode; static WaitUntilValueChangedStandardObjectPromise() { TaskPool.RegisterSizeGetter(typeof(WaitUntilValueChangedStandardObjectPromise), () => pool.Size); } WeakReference target; U currentValue; Func monitorFunction; IEqualityComparer equalityComparer; CancellationToken cancellationToken; GDTaskCompletionSourceCore core; WaitUntilValueChangedStandardObjectPromise() { } public static IGDTaskSource Create(T target, Func monitorFunction, IEqualityComparer equalityComparer, PlayerLoopTiming timing, CancellationToken cancellationToken, out short token) { if (cancellationToken.IsCancellationRequested) { return AutoResetGDTaskCompletionSource.CreateFromCanceled(cancellationToken, out token); } if (!pool.TryPop(out var result)) { result = new WaitUntilValueChangedStandardObjectPromise(); } result.target = new WeakReference(target, false); // wrap in WeakReference. result.monitorFunction = monitorFunction; result.currentValue = monitorFunction(target); result.equalityComparer = equalityComparer ?? GodotEqualityComparer.GetDefault(); result.cancellationToken = cancellationToken; TaskTracker.TrackActiveTask(result, 3); GDTaskPlayerLoopAutoload.AddAction(timing, result); token = result.core.Version; return result; } public U GetResult(short token) { try { return core.GetResult(token); } finally { TryReturn(); } } void IGDTaskSource.GetResult(short token) { GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public bool MoveNext() { if (cancellationToken.IsCancellationRequested || !target.TryGetTarget(out var t)) // doesn't find = cancel. { core.TrySetCanceled(cancellationToken); return false; } U nextValue = default; try { nextValue = monitorFunction(t); if (equalityComparer.Equals(currentValue, nextValue)) { return true; } } catch (Exception ex) { core.TrySetException(ex); return false; } core.TrySetResult(nextValue); return false; } bool TryReturn() { TaskTracker.RemoveTracking(this); core.Reset(); target = default; currentValue = default; monitorFunction = default; equalityComparer = default; cancellationToken = default; return pool.TryPush(this); } } } } ================================================ FILE: addons/GDTask/GDTask.WaitUntil.cs.uid ================================================ uid://cxbbjjhs4etts ================================================ FILE: addons/GDTask/GDTask.WhenAll.Generated.cs ================================================ using System; using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; using System.Threading; using Fractural.Tasks.Internal; namespace Fractural.Tasks { public partial struct GDTask { public static GDTask<(T1, T2)> WhenAll(GDTask task1, GDTask task2) { if (task1.Status.IsCompletedSuccessfully() && task2.Status.IsCompletedSuccessfully()) { return new GDTask<(T1, T2)>((task1.GetAwaiter().GetResult(), task2.GetAwaiter().GetResult())); } return new GDTask<(T1, T2)>(new WhenAllPromise(task1, task2), 0); } sealed class WhenAllPromise : IGDTaskSource<(T1, T2)> { T1 t1 = default; T2 t2 = default; int completedCount; GDTaskCompletionSourceCore<(T1, T2)> core; public WhenAllPromise(GDTask task1, GDTask task2) { TaskTracker.TrackActiveTask(this, 3); this.completedCount = 0; { var awaiter = task1.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT1(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT1(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task2.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT2(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT2(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } } static void TryInvokeContinuationT1(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t1 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 2) { self.core.TrySetResult((self.t1, self.t2)); } } static void TryInvokeContinuationT2(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t2 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 2) { self.core.TrySetResult((self.t1, self.t2)); } } public (T1, T2) GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } void IGDTaskSource.GetResult(short token) { GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } } public static GDTask<(T1, T2, T3)> WhenAll(GDTask task1, GDTask task2, GDTask task3) { if (task1.Status.IsCompletedSuccessfully() && task2.Status.IsCompletedSuccessfully() && task3.Status.IsCompletedSuccessfully()) { return new GDTask<(T1, T2, T3)>((task1.GetAwaiter().GetResult(), task2.GetAwaiter().GetResult(), task3.GetAwaiter().GetResult())); } return new GDTask<(T1, T2, T3)>(new WhenAllPromise(task1, task2, task3), 0); } sealed class WhenAllPromise : IGDTaskSource<(T1, T2, T3)> { T1 t1 = default; T2 t2 = default; T3 t3 = default; int completedCount; GDTaskCompletionSourceCore<(T1, T2, T3)> core; public WhenAllPromise(GDTask task1, GDTask task2, GDTask task3) { TaskTracker.TrackActiveTask(this, 3); this.completedCount = 0; { var awaiter = task1.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT1(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT1(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task2.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT2(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT2(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task3.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT3(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT3(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } } static void TryInvokeContinuationT1(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t1 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 3) { self.core.TrySetResult((self.t1, self.t2, self.t3)); } } static void TryInvokeContinuationT2(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t2 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 3) { self.core.TrySetResult((self.t1, self.t2, self.t3)); } } static void TryInvokeContinuationT3(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t3 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 3) { self.core.TrySetResult((self.t1, self.t2, self.t3)); } } public (T1, T2, T3) GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } void IGDTaskSource.GetResult(short token) { GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } } public static GDTask<(T1, T2, T3, T4)> WhenAll(GDTask task1, GDTask task2, GDTask task3, GDTask task4) { if (task1.Status.IsCompletedSuccessfully() && task2.Status.IsCompletedSuccessfully() && task3.Status.IsCompletedSuccessfully() && task4.Status.IsCompletedSuccessfully()) { return new GDTask<(T1, T2, T3, T4)>((task1.GetAwaiter().GetResult(), task2.GetAwaiter().GetResult(), task3.GetAwaiter().GetResult(), task4.GetAwaiter().GetResult())); } return new GDTask<(T1, T2, T3, T4)>(new WhenAllPromise(task1, task2, task3, task4), 0); } sealed class WhenAllPromise : IGDTaskSource<(T1, T2, T3, T4)> { T1 t1 = default; T2 t2 = default; T3 t3 = default; T4 t4 = default; int completedCount; GDTaskCompletionSourceCore<(T1, T2, T3, T4)> core; public WhenAllPromise(GDTask task1, GDTask task2, GDTask task3, GDTask task4) { TaskTracker.TrackActiveTask(this, 3); this.completedCount = 0; { var awaiter = task1.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT1(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT1(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task2.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT2(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT2(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task3.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT3(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT3(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task4.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT4(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT4(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } } static void TryInvokeContinuationT1(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t1 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 4) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4)); } } static void TryInvokeContinuationT2(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t2 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 4) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4)); } } static void TryInvokeContinuationT3(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t3 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 4) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4)); } } static void TryInvokeContinuationT4(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t4 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 4) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4)); } } public (T1, T2, T3, T4) GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } void IGDTaskSource.GetResult(short token) { GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } } public static GDTask<(T1, T2, T3, T4, T5)> WhenAll(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5) { if (task1.Status.IsCompletedSuccessfully() && task2.Status.IsCompletedSuccessfully() && task3.Status.IsCompletedSuccessfully() && task4.Status.IsCompletedSuccessfully() && task5.Status.IsCompletedSuccessfully()) { return new GDTask<(T1, T2, T3, T4, T5)>((task1.GetAwaiter().GetResult(), task2.GetAwaiter().GetResult(), task3.GetAwaiter().GetResult(), task4.GetAwaiter().GetResult(), task5.GetAwaiter().GetResult())); } return new GDTask<(T1, T2, T3, T4, T5)>(new WhenAllPromise(task1, task2, task3, task4, task5), 0); } sealed class WhenAllPromise : IGDTaskSource<(T1, T2, T3, T4, T5)> { T1 t1 = default; T2 t2 = default; T3 t3 = default; T4 t4 = default; T5 t5 = default; int completedCount; GDTaskCompletionSourceCore<(T1, T2, T3, T4, T5)> core; public WhenAllPromise(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5) { TaskTracker.TrackActiveTask(this, 3); this.completedCount = 0; { var awaiter = task1.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT1(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT1(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task2.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT2(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT2(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task3.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT3(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT3(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task4.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT4(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT4(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task5.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT5(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT5(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } } static void TryInvokeContinuationT1(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t1 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 5) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5)); } } static void TryInvokeContinuationT2(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t2 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 5) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5)); } } static void TryInvokeContinuationT3(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t3 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 5) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5)); } } static void TryInvokeContinuationT4(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t4 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 5) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5)); } } static void TryInvokeContinuationT5(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t5 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 5) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5)); } } public (T1, T2, T3, T4, T5) GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } void IGDTaskSource.GetResult(short token) { GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } } public static GDTask<(T1, T2, T3, T4, T5, T6)> WhenAll(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6) { if (task1.Status.IsCompletedSuccessfully() && task2.Status.IsCompletedSuccessfully() && task3.Status.IsCompletedSuccessfully() && task4.Status.IsCompletedSuccessfully() && task5.Status.IsCompletedSuccessfully() && task6.Status.IsCompletedSuccessfully()) { return new GDTask<(T1, T2, T3, T4, T5, T6)>((task1.GetAwaiter().GetResult(), task2.GetAwaiter().GetResult(), task3.GetAwaiter().GetResult(), task4.GetAwaiter().GetResult(), task5.GetAwaiter().GetResult(), task6.GetAwaiter().GetResult())); } return new GDTask<(T1, T2, T3, T4, T5, T6)>(new WhenAllPromise(task1, task2, task3, task4, task5, task6), 0); } sealed class WhenAllPromise : IGDTaskSource<(T1, T2, T3, T4, T5, T6)> { T1 t1 = default; T2 t2 = default; T3 t3 = default; T4 t4 = default; T5 t5 = default; T6 t6 = default; int completedCount; GDTaskCompletionSourceCore<(T1, T2, T3, T4, T5, T6)> core; public WhenAllPromise(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6) { TaskTracker.TrackActiveTask(this, 3); this.completedCount = 0; { var awaiter = task1.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT1(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT1(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task2.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT2(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT2(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task3.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT3(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT3(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task4.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT4(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT4(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task5.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT5(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT5(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task6.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT6(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT6(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } } static void TryInvokeContinuationT1(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t1 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 6) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6)); } } static void TryInvokeContinuationT2(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t2 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 6) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6)); } } static void TryInvokeContinuationT3(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t3 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 6) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6)); } } static void TryInvokeContinuationT4(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t4 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 6) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6)); } } static void TryInvokeContinuationT5(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t5 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 6) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6)); } } static void TryInvokeContinuationT6(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t6 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 6) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6)); } } public (T1, T2, T3, T4, T5, T6) GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } void IGDTaskSource.GetResult(short token) { GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } } public static GDTask<(T1, T2, T3, T4, T5, T6, T7)> WhenAll(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7) { if (task1.Status.IsCompletedSuccessfully() && task2.Status.IsCompletedSuccessfully() && task3.Status.IsCompletedSuccessfully() && task4.Status.IsCompletedSuccessfully() && task5.Status.IsCompletedSuccessfully() && task6.Status.IsCompletedSuccessfully() && task7.Status.IsCompletedSuccessfully()) { return new GDTask<(T1, T2, T3, T4, T5, T6, T7)>((task1.GetAwaiter().GetResult(), task2.GetAwaiter().GetResult(), task3.GetAwaiter().GetResult(), task4.GetAwaiter().GetResult(), task5.GetAwaiter().GetResult(), task6.GetAwaiter().GetResult(), task7.GetAwaiter().GetResult())); } return new GDTask<(T1, T2, T3, T4, T5, T6, T7)>(new WhenAllPromise(task1, task2, task3, task4, task5, task6, task7), 0); } sealed class WhenAllPromise : IGDTaskSource<(T1, T2, T3, T4, T5, T6, T7)> { T1 t1 = default; T2 t2 = default; T3 t3 = default; T4 t4 = default; T5 t5 = default; T6 t6 = default; T7 t7 = default; int completedCount; GDTaskCompletionSourceCore<(T1, T2, T3, T4, T5, T6, T7)> core; public WhenAllPromise(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7) { TaskTracker.TrackActiveTask(this, 3); this.completedCount = 0; { var awaiter = task1.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT1(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT1(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task2.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT2(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT2(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task3.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT3(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT3(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task4.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT4(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT4(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task5.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT5(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT5(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task6.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT6(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT6(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task7.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT7(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT7(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } } static void TryInvokeContinuationT1(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t1 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 7) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7)); } } static void TryInvokeContinuationT2(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t2 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 7) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7)); } } static void TryInvokeContinuationT3(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t3 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 7) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7)); } } static void TryInvokeContinuationT4(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t4 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 7) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7)); } } static void TryInvokeContinuationT5(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t5 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 7) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7)); } } static void TryInvokeContinuationT6(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t6 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 7) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7)); } } static void TryInvokeContinuationT7(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t7 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 7) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7)); } } public (T1, T2, T3, T4, T5, T6, T7) GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } void IGDTaskSource.GetResult(short token) { GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } } public static GDTask<(T1, T2, T3, T4, T5, T6, T7, T8)> WhenAll(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8) { if (task1.Status.IsCompletedSuccessfully() && task2.Status.IsCompletedSuccessfully() && task3.Status.IsCompletedSuccessfully() && task4.Status.IsCompletedSuccessfully() && task5.Status.IsCompletedSuccessfully() && task6.Status.IsCompletedSuccessfully() && task7.Status.IsCompletedSuccessfully() && task8.Status.IsCompletedSuccessfully()) { return new GDTask<(T1, T2, T3, T4, T5, T6, T7, T8)>((task1.GetAwaiter().GetResult(), task2.GetAwaiter().GetResult(), task3.GetAwaiter().GetResult(), task4.GetAwaiter().GetResult(), task5.GetAwaiter().GetResult(), task6.GetAwaiter().GetResult(), task7.GetAwaiter().GetResult(), task8.GetAwaiter().GetResult())); } return new GDTask<(T1, T2, T3, T4, T5, T6, T7, T8)>(new WhenAllPromise(task1, task2, task3, task4, task5, task6, task7, task8), 0); } sealed class WhenAllPromise : IGDTaskSource<(T1, T2, T3, T4, T5, T6, T7, T8)> { T1 t1 = default; T2 t2 = default; T3 t3 = default; T4 t4 = default; T5 t5 = default; T6 t6 = default; T7 t7 = default; T8 t8 = default; int completedCount; GDTaskCompletionSourceCore<(T1, T2, T3, T4, T5, T6, T7, T8)> core; public WhenAllPromise(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8) { TaskTracker.TrackActiveTask(this, 3); this.completedCount = 0; { var awaiter = task1.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT1(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT1(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task2.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT2(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT2(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task3.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT3(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT3(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task4.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT4(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT4(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task5.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT5(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT5(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task6.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT6(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT6(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task7.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT7(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT7(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task8.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT8(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT8(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } } static void TryInvokeContinuationT1(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t1 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 8) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8)); } } static void TryInvokeContinuationT2(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t2 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 8) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8)); } } static void TryInvokeContinuationT3(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t3 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 8) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8)); } } static void TryInvokeContinuationT4(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t4 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 8) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8)); } } static void TryInvokeContinuationT5(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t5 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 8) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8)); } } static void TryInvokeContinuationT6(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t6 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 8) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8)); } } static void TryInvokeContinuationT7(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t7 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 8) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8)); } } static void TryInvokeContinuationT8(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t8 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 8) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8)); } } public (T1, T2, T3, T4, T5, T6, T7, T8) GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } void IGDTaskSource.GetResult(short token) { GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } } public static GDTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9)> WhenAll(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9) { if (task1.Status.IsCompletedSuccessfully() && task2.Status.IsCompletedSuccessfully() && task3.Status.IsCompletedSuccessfully() && task4.Status.IsCompletedSuccessfully() && task5.Status.IsCompletedSuccessfully() && task6.Status.IsCompletedSuccessfully() && task7.Status.IsCompletedSuccessfully() && task8.Status.IsCompletedSuccessfully() && task9.Status.IsCompletedSuccessfully()) { return new GDTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9)>((task1.GetAwaiter().GetResult(), task2.GetAwaiter().GetResult(), task3.GetAwaiter().GetResult(), task4.GetAwaiter().GetResult(), task5.GetAwaiter().GetResult(), task6.GetAwaiter().GetResult(), task7.GetAwaiter().GetResult(), task8.GetAwaiter().GetResult(), task9.GetAwaiter().GetResult())); } return new GDTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9)>(new WhenAllPromise(task1, task2, task3, task4, task5, task6, task7, task8, task9), 0); } sealed class WhenAllPromise : IGDTaskSource<(T1, T2, T3, T4, T5, T6, T7, T8, T9)> { T1 t1 = default; T2 t2 = default; T3 t3 = default; T4 t4 = default; T5 t5 = default; T6 t6 = default; T7 t7 = default; T8 t8 = default; T9 t9 = default; int completedCount; GDTaskCompletionSourceCore<(T1, T2, T3, T4, T5, T6, T7, T8, T9)> core; public WhenAllPromise(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9) { TaskTracker.TrackActiveTask(this, 3); this.completedCount = 0; { var awaiter = task1.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT1(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT1(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task2.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT2(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT2(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task3.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT3(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT3(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task4.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT4(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT4(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task5.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT5(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT5(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task6.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT6(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT6(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task7.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT7(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT7(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task8.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT8(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT8(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task9.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT9(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT9(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } } static void TryInvokeContinuationT1(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t1 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 9) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9)); } } static void TryInvokeContinuationT2(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t2 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 9) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9)); } } static void TryInvokeContinuationT3(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t3 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 9) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9)); } } static void TryInvokeContinuationT4(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t4 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 9) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9)); } } static void TryInvokeContinuationT5(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t5 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 9) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9)); } } static void TryInvokeContinuationT6(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t6 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 9) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9)); } } static void TryInvokeContinuationT7(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t7 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 9) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9)); } } static void TryInvokeContinuationT8(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t8 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 9) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9)); } } static void TryInvokeContinuationT9(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t9 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 9) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9)); } } public (T1, T2, T3, T4, T5, T6, T7, T8, T9) GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } void IGDTaskSource.GetResult(short token) { GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } } public static GDTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)> WhenAll(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10) { if (task1.Status.IsCompletedSuccessfully() && task2.Status.IsCompletedSuccessfully() && task3.Status.IsCompletedSuccessfully() && task4.Status.IsCompletedSuccessfully() && task5.Status.IsCompletedSuccessfully() && task6.Status.IsCompletedSuccessfully() && task7.Status.IsCompletedSuccessfully() && task8.Status.IsCompletedSuccessfully() && task9.Status.IsCompletedSuccessfully() && task10.Status.IsCompletedSuccessfully()) { return new GDTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)>((task1.GetAwaiter().GetResult(), task2.GetAwaiter().GetResult(), task3.GetAwaiter().GetResult(), task4.GetAwaiter().GetResult(), task5.GetAwaiter().GetResult(), task6.GetAwaiter().GetResult(), task7.GetAwaiter().GetResult(), task8.GetAwaiter().GetResult(), task9.GetAwaiter().GetResult(), task10.GetAwaiter().GetResult())); } return new GDTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)>(new WhenAllPromise(task1, task2, task3, task4, task5, task6, task7, task8, task9, task10), 0); } sealed class WhenAllPromise : IGDTaskSource<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)> { T1 t1 = default; T2 t2 = default; T3 t3 = default; T4 t4 = default; T5 t5 = default; T6 t6 = default; T7 t7 = default; T8 t8 = default; T9 t9 = default; T10 t10 = default; int completedCount; GDTaskCompletionSourceCore<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)> core; public WhenAllPromise(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10) { TaskTracker.TrackActiveTask(this, 3); this.completedCount = 0; { var awaiter = task1.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT1(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT1(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task2.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT2(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT2(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task3.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT3(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT3(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task4.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT4(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT4(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task5.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT5(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT5(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task6.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT6(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT6(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task7.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT7(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT7(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task8.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT8(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT8(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task9.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT9(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT9(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task10.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT10(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT10(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } } static void TryInvokeContinuationT1(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t1 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 10) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10)); } } static void TryInvokeContinuationT2(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t2 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 10) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10)); } } static void TryInvokeContinuationT3(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t3 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 10) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10)); } } static void TryInvokeContinuationT4(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t4 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 10) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10)); } } static void TryInvokeContinuationT5(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t5 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 10) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10)); } } static void TryInvokeContinuationT6(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t6 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 10) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10)); } } static void TryInvokeContinuationT7(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t7 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 10) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10)); } } static void TryInvokeContinuationT8(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t8 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 10) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10)); } } static void TryInvokeContinuationT9(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t9 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 10) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10)); } } static void TryInvokeContinuationT10(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t10 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 10) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10)); } } public (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } void IGDTaskSource.GetResult(short token) { GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } } public static GDTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11)> WhenAll(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10, GDTask task11) { if (task1.Status.IsCompletedSuccessfully() && task2.Status.IsCompletedSuccessfully() && task3.Status.IsCompletedSuccessfully() && task4.Status.IsCompletedSuccessfully() && task5.Status.IsCompletedSuccessfully() && task6.Status.IsCompletedSuccessfully() && task7.Status.IsCompletedSuccessfully() && task8.Status.IsCompletedSuccessfully() && task9.Status.IsCompletedSuccessfully() && task10.Status.IsCompletedSuccessfully() && task11.Status.IsCompletedSuccessfully()) { return new GDTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11)>((task1.GetAwaiter().GetResult(), task2.GetAwaiter().GetResult(), task3.GetAwaiter().GetResult(), task4.GetAwaiter().GetResult(), task5.GetAwaiter().GetResult(), task6.GetAwaiter().GetResult(), task7.GetAwaiter().GetResult(), task8.GetAwaiter().GetResult(), task9.GetAwaiter().GetResult(), task10.GetAwaiter().GetResult(), task11.GetAwaiter().GetResult())); } return new GDTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11)>(new WhenAllPromise(task1, task2, task3, task4, task5, task6, task7, task8, task9, task10, task11), 0); } sealed class WhenAllPromise : IGDTaskSource<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11)> { T1 t1 = default; T2 t2 = default; T3 t3 = default; T4 t4 = default; T5 t5 = default; T6 t6 = default; T7 t7 = default; T8 t8 = default; T9 t9 = default; T10 t10 = default; T11 t11 = default; int completedCount; GDTaskCompletionSourceCore<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11)> core; public WhenAllPromise(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10, GDTask task11) { TaskTracker.TrackActiveTask(this, 3); this.completedCount = 0; { var awaiter = task1.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT1(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT1(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task2.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT2(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT2(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task3.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT3(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT3(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task4.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT4(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT4(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task5.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT5(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT5(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task6.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT6(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT6(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task7.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT7(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT7(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task8.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT8(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT8(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task9.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT9(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT9(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task10.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT10(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT10(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task11.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT11(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT11(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } } static void TryInvokeContinuationT1(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t1 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 11) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11)); } } static void TryInvokeContinuationT2(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t2 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 11) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11)); } } static void TryInvokeContinuationT3(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t3 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 11) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11)); } } static void TryInvokeContinuationT4(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t4 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 11) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11)); } } static void TryInvokeContinuationT5(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t5 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 11) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11)); } } static void TryInvokeContinuationT6(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t6 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 11) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11)); } } static void TryInvokeContinuationT7(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t7 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 11) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11)); } } static void TryInvokeContinuationT8(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t8 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 11) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11)); } } static void TryInvokeContinuationT9(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t9 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 11) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11)); } } static void TryInvokeContinuationT10(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t10 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 11) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11)); } } static void TryInvokeContinuationT11(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t11 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 11) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11)); } } public (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } void IGDTaskSource.GetResult(short token) { GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } } public static GDTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12)> WhenAll(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10, GDTask task11, GDTask task12) { if (task1.Status.IsCompletedSuccessfully() && task2.Status.IsCompletedSuccessfully() && task3.Status.IsCompletedSuccessfully() && task4.Status.IsCompletedSuccessfully() && task5.Status.IsCompletedSuccessfully() && task6.Status.IsCompletedSuccessfully() && task7.Status.IsCompletedSuccessfully() && task8.Status.IsCompletedSuccessfully() && task9.Status.IsCompletedSuccessfully() && task10.Status.IsCompletedSuccessfully() && task11.Status.IsCompletedSuccessfully() && task12.Status.IsCompletedSuccessfully()) { return new GDTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12)>((task1.GetAwaiter().GetResult(), task2.GetAwaiter().GetResult(), task3.GetAwaiter().GetResult(), task4.GetAwaiter().GetResult(), task5.GetAwaiter().GetResult(), task6.GetAwaiter().GetResult(), task7.GetAwaiter().GetResult(), task8.GetAwaiter().GetResult(), task9.GetAwaiter().GetResult(), task10.GetAwaiter().GetResult(), task11.GetAwaiter().GetResult(), task12.GetAwaiter().GetResult())); } return new GDTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12)>(new WhenAllPromise(task1, task2, task3, task4, task5, task6, task7, task8, task9, task10, task11, task12), 0); } sealed class WhenAllPromise : IGDTaskSource<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12)> { T1 t1 = default; T2 t2 = default; T3 t3 = default; T4 t4 = default; T5 t5 = default; T6 t6 = default; T7 t7 = default; T8 t8 = default; T9 t9 = default; T10 t10 = default; T11 t11 = default; T12 t12 = default; int completedCount; GDTaskCompletionSourceCore<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12)> core; public WhenAllPromise(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10, GDTask task11, GDTask task12) { TaskTracker.TrackActiveTask(this, 3); this.completedCount = 0; { var awaiter = task1.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT1(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT1(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task2.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT2(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT2(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task3.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT3(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT3(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task4.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT4(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT4(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task5.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT5(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT5(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task6.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT6(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT6(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task7.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT7(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT7(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task8.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT8(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT8(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task9.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT9(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT9(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task10.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT10(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT10(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task11.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT11(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT11(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task12.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT12(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT12(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } } static void TryInvokeContinuationT1(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t1 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 12) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12)); } } static void TryInvokeContinuationT2(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t2 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 12) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12)); } } static void TryInvokeContinuationT3(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t3 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 12) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12)); } } static void TryInvokeContinuationT4(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t4 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 12) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12)); } } static void TryInvokeContinuationT5(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t5 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 12) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12)); } } static void TryInvokeContinuationT6(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t6 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 12) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12)); } } static void TryInvokeContinuationT7(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t7 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 12) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12)); } } static void TryInvokeContinuationT8(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t8 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 12) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12)); } } static void TryInvokeContinuationT9(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t9 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 12) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12)); } } static void TryInvokeContinuationT10(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t10 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 12) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12)); } } static void TryInvokeContinuationT11(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t11 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 12) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12)); } } static void TryInvokeContinuationT12(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t12 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 12) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12)); } } public (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } void IGDTaskSource.GetResult(short token) { GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } } public static GDTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13)> WhenAll(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10, GDTask task11, GDTask task12, GDTask task13) { if (task1.Status.IsCompletedSuccessfully() && task2.Status.IsCompletedSuccessfully() && task3.Status.IsCompletedSuccessfully() && task4.Status.IsCompletedSuccessfully() && task5.Status.IsCompletedSuccessfully() && task6.Status.IsCompletedSuccessfully() && task7.Status.IsCompletedSuccessfully() && task8.Status.IsCompletedSuccessfully() && task9.Status.IsCompletedSuccessfully() && task10.Status.IsCompletedSuccessfully() && task11.Status.IsCompletedSuccessfully() && task12.Status.IsCompletedSuccessfully() && task13.Status.IsCompletedSuccessfully()) { return new GDTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13)>((task1.GetAwaiter().GetResult(), task2.GetAwaiter().GetResult(), task3.GetAwaiter().GetResult(), task4.GetAwaiter().GetResult(), task5.GetAwaiter().GetResult(), task6.GetAwaiter().GetResult(), task7.GetAwaiter().GetResult(), task8.GetAwaiter().GetResult(), task9.GetAwaiter().GetResult(), task10.GetAwaiter().GetResult(), task11.GetAwaiter().GetResult(), task12.GetAwaiter().GetResult(), task13.GetAwaiter().GetResult())); } return new GDTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13)>(new WhenAllPromise(task1, task2, task3, task4, task5, task6, task7, task8, task9, task10, task11, task12, task13), 0); } sealed class WhenAllPromise : IGDTaskSource<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13)> { T1 t1 = default; T2 t2 = default; T3 t3 = default; T4 t4 = default; T5 t5 = default; T6 t6 = default; T7 t7 = default; T8 t8 = default; T9 t9 = default; T10 t10 = default; T11 t11 = default; T12 t12 = default; T13 t13 = default; int completedCount; GDTaskCompletionSourceCore<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13)> core; public WhenAllPromise(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10, GDTask task11, GDTask task12, GDTask task13) { TaskTracker.TrackActiveTask(this, 3); this.completedCount = 0; { var awaiter = task1.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT1(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT1(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task2.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT2(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT2(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task3.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT3(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT3(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task4.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT4(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT4(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task5.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT5(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT5(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task6.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT6(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT6(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task7.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT7(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT7(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task8.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT8(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT8(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task9.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT9(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT9(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task10.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT10(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT10(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task11.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT11(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT11(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task12.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT12(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT12(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task13.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT13(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT13(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } } static void TryInvokeContinuationT1(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t1 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 13) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13)); } } static void TryInvokeContinuationT2(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t2 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 13) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13)); } } static void TryInvokeContinuationT3(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t3 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 13) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13)); } } static void TryInvokeContinuationT4(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t4 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 13) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13)); } } static void TryInvokeContinuationT5(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t5 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 13) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13)); } } static void TryInvokeContinuationT6(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t6 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 13) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13)); } } static void TryInvokeContinuationT7(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t7 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 13) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13)); } } static void TryInvokeContinuationT8(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t8 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 13) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13)); } } static void TryInvokeContinuationT9(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t9 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 13) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13)); } } static void TryInvokeContinuationT10(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t10 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 13) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13)); } } static void TryInvokeContinuationT11(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t11 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 13) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13)); } } static void TryInvokeContinuationT12(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t12 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 13) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13)); } } static void TryInvokeContinuationT13(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t13 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 13) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13)); } } public (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } void IGDTaskSource.GetResult(short token) { GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } } public static GDTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14)> WhenAll(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10, GDTask task11, GDTask task12, GDTask task13, GDTask task14) { if (task1.Status.IsCompletedSuccessfully() && task2.Status.IsCompletedSuccessfully() && task3.Status.IsCompletedSuccessfully() && task4.Status.IsCompletedSuccessfully() && task5.Status.IsCompletedSuccessfully() && task6.Status.IsCompletedSuccessfully() && task7.Status.IsCompletedSuccessfully() && task8.Status.IsCompletedSuccessfully() && task9.Status.IsCompletedSuccessfully() && task10.Status.IsCompletedSuccessfully() && task11.Status.IsCompletedSuccessfully() && task12.Status.IsCompletedSuccessfully() && task13.Status.IsCompletedSuccessfully() && task14.Status.IsCompletedSuccessfully()) { return new GDTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14)>((task1.GetAwaiter().GetResult(), task2.GetAwaiter().GetResult(), task3.GetAwaiter().GetResult(), task4.GetAwaiter().GetResult(), task5.GetAwaiter().GetResult(), task6.GetAwaiter().GetResult(), task7.GetAwaiter().GetResult(), task8.GetAwaiter().GetResult(), task9.GetAwaiter().GetResult(), task10.GetAwaiter().GetResult(), task11.GetAwaiter().GetResult(), task12.GetAwaiter().GetResult(), task13.GetAwaiter().GetResult(), task14.GetAwaiter().GetResult())); } return new GDTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14)>(new WhenAllPromise(task1, task2, task3, task4, task5, task6, task7, task8, task9, task10, task11, task12, task13, task14), 0); } sealed class WhenAllPromise : IGDTaskSource<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14)> { T1 t1 = default; T2 t2 = default; T3 t3 = default; T4 t4 = default; T5 t5 = default; T6 t6 = default; T7 t7 = default; T8 t8 = default; T9 t9 = default; T10 t10 = default; T11 t11 = default; T12 t12 = default; T13 t13 = default; T14 t14 = default; int completedCount; GDTaskCompletionSourceCore<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14)> core; public WhenAllPromise(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10, GDTask task11, GDTask task12, GDTask task13, GDTask task14) { TaskTracker.TrackActiveTask(this, 3); this.completedCount = 0; { var awaiter = task1.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT1(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT1(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task2.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT2(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT2(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task3.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT3(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT3(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task4.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT4(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT4(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task5.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT5(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT5(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task6.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT6(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT6(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task7.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT7(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT7(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task8.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT8(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT8(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task9.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT9(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT9(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task10.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT10(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT10(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task11.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT11(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT11(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task12.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT12(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT12(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task13.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT13(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT13(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task14.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT14(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT14(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } } static void TryInvokeContinuationT1(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t1 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 14) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13, self.t14)); } } static void TryInvokeContinuationT2(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t2 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 14) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13, self.t14)); } } static void TryInvokeContinuationT3(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t3 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 14) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13, self.t14)); } } static void TryInvokeContinuationT4(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t4 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 14) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13, self.t14)); } } static void TryInvokeContinuationT5(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t5 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 14) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13, self.t14)); } } static void TryInvokeContinuationT6(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t6 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 14) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13, self.t14)); } } static void TryInvokeContinuationT7(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t7 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 14) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13, self.t14)); } } static void TryInvokeContinuationT8(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t8 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 14) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13, self.t14)); } } static void TryInvokeContinuationT9(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t9 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 14) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13, self.t14)); } } static void TryInvokeContinuationT10(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t10 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 14) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13, self.t14)); } } static void TryInvokeContinuationT11(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t11 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 14) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13, self.t14)); } } static void TryInvokeContinuationT12(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t12 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 14) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13, self.t14)); } } static void TryInvokeContinuationT13(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t13 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 14) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13, self.t14)); } } static void TryInvokeContinuationT14(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t14 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 14) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13, self.t14)); } } public (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14) GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } void IGDTaskSource.GetResult(short token) { GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } } public static GDTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15)> WhenAll(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10, GDTask task11, GDTask task12, GDTask task13, GDTask task14, GDTask task15) { if (task1.Status.IsCompletedSuccessfully() && task2.Status.IsCompletedSuccessfully() && task3.Status.IsCompletedSuccessfully() && task4.Status.IsCompletedSuccessfully() && task5.Status.IsCompletedSuccessfully() && task6.Status.IsCompletedSuccessfully() && task7.Status.IsCompletedSuccessfully() && task8.Status.IsCompletedSuccessfully() && task9.Status.IsCompletedSuccessfully() && task10.Status.IsCompletedSuccessfully() && task11.Status.IsCompletedSuccessfully() && task12.Status.IsCompletedSuccessfully() && task13.Status.IsCompletedSuccessfully() && task14.Status.IsCompletedSuccessfully() && task15.Status.IsCompletedSuccessfully()) { return new GDTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15)>((task1.GetAwaiter().GetResult(), task2.GetAwaiter().GetResult(), task3.GetAwaiter().GetResult(), task4.GetAwaiter().GetResult(), task5.GetAwaiter().GetResult(), task6.GetAwaiter().GetResult(), task7.GetAwaiter().GetResult(), task8.GetAwaiter().GetResult(), task9.GetAwaiter().GetResult(), task10.GetAwaiter().GetResult(), task11.GetAwaiter().GetResult(), task12.GetAwaiter().GetResult(), task13.GetAwaiter().GetResult(), task14.GetAwaiter().GetResult(), task15.GetAwaiter().GetResult())); } return new GDTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15)>(new WhenAllPromise(task1, task2, task3, task4, task5, task6, task7, task8, task9, task10, task11, task12, task13, task14, task15), 0); } sealed class WhenAllPromise : IGDTaskSource<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15)> { T1 t1 = default; T2 t2 = default; T3 t3 = default; T4 t4 = default; T5 t5 = default; T6 t6 = default; T7 t7 = default; T8 t8 = default; T9 t9 = default; T10 t10 = default; T11 t11 = default; T12 t12 = default; T13 t13 = default; T14 t14 = default; T15 t15 = default; int completedCount; GDTaskCompletionSourceCore<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15)> core; public WhenAllPromise(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10, GDTask task11, GDTask task12, GDTask task13, GDTask task14, GDTask task15) { TaskTracker.TrackActiveTask(this, 3); this.completedCount = 0; { var awaiter = task1.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT1(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT1(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task2.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT2(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT2(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task3.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT3(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT3(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task4.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT4(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT4(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task5.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT5(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT5(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task6.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT6(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT6(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task7.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT7(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT7(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task8.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT8(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT8(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task9.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT9(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT9(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task10.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT10(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT10(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task11.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT11(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT11(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task12.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT12(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT12(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task13.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT13(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT13(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task14.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT14(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT14(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task15.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT15(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT15(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } } static void TryInvokeContinuationT1(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t1 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 15) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13, self.t14, self.t15)); } } static void TryInvokeContinuationT2(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t2 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 15) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13, self.t14, self.t15)); } } static void TryInvokeContinuationT3(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t3 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 15) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13, self.t14, self.t15)); } } static void TryInvokeContinuationT4(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t4 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 15) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13, self.t14, self.t15)); } } static void TryInvokeContinuationT5(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t5 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 15) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13, self.t14, self.t15)); } } static void TryInvokeContinuationT6(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t6 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 15) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13, self.t14, self.t15)); } } static void TryInvokeContinuationT7(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t7 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 15) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13, self.t14, self.t15)); } } static void TryInvokeContinuationT8(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t8 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 15) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13, self.t14, self.t15)); } } static void TryInvokeContinuationT9(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t9 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 15) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13, self.t14, self.t15)); } } static void TryInvokeContinuationT10(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t10 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 15) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13, self.t14, self.t15)); } } static void TryInvokeContinuationT11(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t11 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 15) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13, self.t14, self.t15)); } } static void TryInvokeContinuationT12(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t12 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 15) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13, self.t14, self.t15)); } } static void TryInvokeContinuationT13(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t13 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 15) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13, self.t14, self.t15)); } } static void TryInvokeContinuationT14(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t14 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 15) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13, self.t14, self.t15)); } } static void TryInvokeContinuationT15(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { self.t15 = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 15) { self.core.TrySetResult((self.t1, self.t2, self.t3, self.t4, self.t5, self.t6, self.t7, self.t8, self.t9, self.t10, self.t11, self.t12, self.t13, self.t14, self.t15)); } } public (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15) GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } void IGDTaskSource.GetResult(short token) { GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } } } } ================================================ FILE: addons/GDTask/GDTask.WhenAll.Generated.cs.uid ================================================ uid://dymqkcsrwsqun ================================================ FILE: addons/GDTask/GDTask.WhenAll.cs ================================================ using System; using System.Collections.Generic; using System.Threading; using Fractural.Tasks.Internal; namespace Fractural.Tasks { public partial struct GDTask { public static GDTask WhenAll(params GDTask[] tasks) { if (tasks.Length == 0) { return GDTask.FromResult(Array.Empty()); } return new GDTask(new WhenAllPromise(tasks, tasks.Length), 0); } public static GDTask WhenAll(IEnumerable> tasks) { using (var span = ArrayPoolUtil.Materialize(tasks)) { var promise = new WhenAllPromise(span.Array, span.Length); // consumed array in constructor. return new GDTask(promise, 0); } } public static GDTask WhenAll(params GDTask[] tasks) { if (tasks.Length == 0) { return GDTask.CompletedTask; } return new GDTask(new WhenAllPromise(tasks, tasks.Length), 0); } public static GDTask WhenAll(IEnumerable tasks) { using (var span = ArrayPoolUtil.Materialize(tasks)) { var promise = new WhenAllPromise(span.Array, span.Length); // consumed array in constructor. return new GDTask(promise, 0); } } sealed class WhenAllPromise : IGDTaskSource { T[] result; int completeCount; GDTaskCompletionSourceCore core; // don't reset(called after GetResult, will invoke TrySetException.) public WhenAllPromise(GDTask[] tasks, int tasksLength) { TaskTracker.TrackActiveTask(this, 3); this.completeCount = 0; if (tasksLength == 0) { this.result = Array.Empty(); core.TrySetResult(result); return; } this.result = new T[tasksLength]; for (int i = 0; i < tasksLength; i++) { GDTask.Awaiter awaiter; try { awaiter = tasks[i].GetAwaiter(); } catch (Exception ex) { core.TrySetException(ex); continue; } if (awaiter.IsCompleted) { TryInvokeContinuation(this, awaiter, i); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter, int>)state) { TryInvokeContinuation(t.Item1, t.Item2, t.Item3); } }, StateTuple.Create(this, awaiter, i)); } } } static void TryInvokeContinuation(WhenAllPromise self, in GDTask.Awaiter awaiter, int i) { try { self.result[i] = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completeCount) == self.result.Length) { self.core.TrySetResult(self.result); } } public T[] GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } void IGDTaskSource.GetResult(short token) { GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } } sealed class WhenAllPromise : IGDTaskSource { int completeCount; int tasksLength; GDTaskCompletionSourceCore core; // don't reset(called after GetResult, will invoke TrySetException.) public WhenAllPromise(GDTask[] tasks, int tasksLength) { TaskTracker.TrackActiveTask(this, 3); this.tasksLength = tasksLength; this.completeCount = 0; if (tasksLength == 0) { core.TrySetResult(AsyncUnit.Default); return; } for (int i = 0; i < tasksLength; i++) { GDTask.Awaiter awaiter; try { awaiter = tasks[i].GetAwaiter(); } catch (Exception ex) { core.TrySetException(ex); continue; } if (awaiter.IsCompleted) { TryInvokeContinuation(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple)state) { TryInvokeContinuation(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } } static void TryInvokeContinuation(WhenAllPromise self, in GDTask.Awaiter awaiter) { try { awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completeCount) == self.tasksLength) { self.core.TrySetResult(AsyncUnit.Default); } } public void GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); core.GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } } } } ================================================ FILE: addons/GDTask/GDTask.WhenAll.cs.uid ================================================ uid://21c8h3tf3ihy ================================================ FILE: addons/GDTask/GDTask.WhenAny.Generated.cs ================================================ using System; using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; using System.Threading; using Fractural.Tasks.Internal; namespace Fractural.Tasks { public partial struct GDTask { public static GDTask<(int winArgumentIndex, T1 result1, T2 result2)> WhenAny(GDTask task1, GDTask task2) { return new GDTask<(int winArgumentIndex, T1 result1, T2 result2)>(new WhenAnyPromise(task1, task2), 0); } sealed class WhenAnyPromise : IGDTaskSource<(int, T1 result1, T2 result2)> { int completedCount; GDTaskCompletionSourceCore<(int, T1 result1, T2 result2)> core; public WhenAnyPromise(GDTask task1, GDTask task2) { TaskTracker.TrackActiveTask(this, 3); this.completedCount = 0; { var awaiter = task1.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT1(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT1(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task2.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT2(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT2(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } } static void TryInvokeContinuationT1(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T1 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((0, result, default)); } } static void TryInvokeContinuationT2(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T2 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((1, default, result)); } } public (int, T1 result1, T2 result2) GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } void IGDTaskSource.GetResult(short token) { GetResult(token); } } public static GDTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3)> WhenAny(GDTask task1, GDTask task2, GDTask task3) { return new GDTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3)>(new WhenAnyPromise(task1, task2, task3), 0); } sealed class WhenAnyPromise : IGDTaskSource<(int, T1 result1, T2 result2, T3 result3)> { int completedCount; GDTaskCompletionSourceCore<(int, T1 result1, T2 result2, T3 result3)> core; public WhenAnyPromise(GDTask task1, GDTask task2, GDTask task3) { TaskTracker.TrackActiveTask(this, 3); this.completedCount = 0; { var awaiter = task1.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT1(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT1(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task2.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT2(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT2(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task3.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT3(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT3(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } } static void TryInvokeContinuationT1(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T1 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((0, result, default, default)); } } static void TryInvokeContinuationT2(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T2 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((1, default, result, default)); } } static void TryInvokeContinuationT3(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T3 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((2, default, default, result)); } } public (int, T1 result1, T2 result2, T3 result3) GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } void IGDTaskSource.GetResult(short token) { GetResult(token); } } public static GDTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4)> WhenAny(GDTask task1, GDTask task2, GDTask task3, GDTask task4) { return new GDTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4)>(new WhenAnyPromise(task1, task2, task3, task4), 0); } sealed class WhenAnyPromise : IGDTaskSource<(int, T1 result1, T2 result2, T3 result3, T4 result4)> { int completedCount; GDTaskCompletionSourceCore<(int, T1 result1, T2 result2, T3 result3, T4 result4)> core; public WhenAnyPromise(GDTask task1, GDTask task2, GDTask task3, GDTask task4) { TaskTracker.TrackActiveTask(this, 3); this.completedCount = 0; { var awaiter = task1.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT1(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT1(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task2.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT2(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT2(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task3.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT3(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT3(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task4.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT4(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT4(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } } static void TryInvokeContinuationT1(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T1 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((0, result, default, default, default)); } } static void TryInvokeContinuationT2(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T2 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((1, default, result, default, default)); } } static void TryInvokeContinuationT3(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T3 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((2, default, default, result, default)); } } static void TryInvokeContinuationT4(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T4 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((3, default, default, default, result)); } } public (int, T1 result1, T2 result2, T3 result3, T4 result4) GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } void IGDTaskSource.GetResult(short token) { GetResult(token); } } public static GDTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5)> WhenAny(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5) { return new GDTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5)>(new WhenAnyPromise(task1, task2, task3, task4, task5), 0); } sealed class WhenAnyPromise : IGDTaskSource<(int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5)> { int completedCount; GDTaskCompletionSourceCore<(int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5)> core; public WhenAnyPromise(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5) { TaskTracker.TrackActiveTask(this, 3); this.completedCount = 0; { var awaiter = task1.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT1(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT1(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task2.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT2(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT2(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task3.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT3(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT3(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task4.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT4(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT4(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task5.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT5(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT5(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } } static void TryInvokeContinuationT1(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T1 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((0, result, default, default, default, default)); } } static void TryInvokeContinuationT2(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T2 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((1, default, result, default, default, default)); } } static void TryInvokeContinuationT3(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T3 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((2, default, default, result, default, default)); } } static void TryInvokeContinuationT4(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T4 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((3, default, default, default, result, default)); } } static void TryInvokeContinuationT5(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T5 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((4, default, default, default, default, result)); } } public (int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5) GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } void IGDTaskSource.GetResult(short token) { GetResult(token); } } public static GDTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6)> WhenAny(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6) { return new GDTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6)>(new WhenAnyPromise(task1, task2, task3, task4, task5, task6), 0); } sealed class WhenAnyPromise : IGDTaskSource<(int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6)> { int completedCount; GDTaskCompletionSourceCore<(int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6)> core; public WhenAnyPromise(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6) { TaskTracker.TrackActiveTask(this, 3); this.completedCount = 0; { var awaiter = task1.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT1(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT1(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task2.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT2(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT2(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task3.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT3(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT3(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task4.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT4(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT4(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task5.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT5(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT5(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task6.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT6(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT6(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } } static void TryInvokeContinuationT1(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T1 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((0, result, default, default, default, default, default)); } } static void TryInvokeContinuationT2(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T2 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((1, default, result, default, default, default, default)); } } static void TryInvokeContinuationT3(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T3 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((2, default, default, result, default, default, default)); } } static void TryInvokeContinuationT4(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T4 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((3, default, default, default, result, default, default)); } } static void TryInvokeContinuationT5(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T5 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((4, default, default, default, default, result, default)); } } static void TryInvokeContinuationT6(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T6 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((5, default, default, default, default, default, result)); } } public (int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6) GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } void IGDTaskSource.GetResult(short token) { GetResult(token); } } public static GDTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7)> WhenAny(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7) { return new GDTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7)>(new WhenAnyPromise(task1, task2, task3, task4, task5, task6, task7), 0); } sealed class WhenAnyPromise : IGDTaskSource<(int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7)> { int completedCount; GDTaskCompletionSourceCore<(int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7)> core; public WhenAnyPromise(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7) { TaskTracker.TrackActiveTask(this, 3); this.completedCount = 0; { var awaiter = task1.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT1(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT1(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task2.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT2(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT2(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task3.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT3(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT3(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task4.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT4(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT4(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task5.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT5(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT5(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task6.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT6(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT6(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task7.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT7(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT7(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } } static void TryInvokeContinuationT1(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T1 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((0, result, default, default, default, default, default, default)); } } static void TryInvokeContinuationT2(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T2 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((1, default, result, default, default, default, default, default)); } } static void TryInvokeContinuationT3(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T3 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((2, default, default, result, default, default, default, default)); } } static void TryInvokeContinuationT4(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T4 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((3, default, default, default, result, default, default, default)); } } static void TryInvokeContinuationT5(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T5 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((4, default, default, default, default, result, default, default)); } } static void TryInvokeContinuationT6(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T6 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((5, default, default, default, default, default, result, default)); } } static void TryInvokeContinuationT7(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T7 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((6, default, default, default, default, default, default, result)); } } public (int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7) GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } void IGDTaskSource.GetResult(short token) { GetResult(token); } } public static GDTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8)> WhenAny(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8) { return new GDTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8)>(new WhenAnyPromise(task1, task2, task3, task4, task5, task6, task7, task8), 0); } sealed class WhenAnyPromise : IGDTaskSource<(int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8)> { int completedCount; GDTaskCompletionSourceCore<(int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8)> core; public WhenAnyPromise(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8) { TaskTracker.TrackActiveTask(this, 3); this.completedCount = 0; { var awaiter = task1.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT1(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT1(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task2.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT2(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT2(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task3.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT3(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT3(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task4.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT4(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT4(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task5.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT5(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT5(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task6.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT6(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT6(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task7.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT7(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT7(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task8.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT8(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT8(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } } static void TryInvokeContinuationT1(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T1 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((0, result, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT2(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T2 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((1, default, result, default, default, default, default, default, default)); } } static void TryInvokeContinuationT3(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T3 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((2, default, default, result, default, default, default, default, default)); } } static void TryInvokeContinuationT4(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T4 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((3, default, default, default, result, default, default, default, default)); } } static void TryInvokeContinuationT5(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T5 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((4, default, default, default, default, result, default, default, default)); } } static void TryInvokeContinuationT6(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T6 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((5, default, default, default, default, default, result, default, default)); } } static void TryInvokeContinuationT7(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T7 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((6, default, default, default, default, default, default, result, default)); } } static void TryInvokeContinuationT8(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T8 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((7, default, default, default, default, default, default, default, result)); } } public (int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8) GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } void IGDTaskSource.GetResult(short token) { GetResult(token); } } public static GDTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9)> WhenAny(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9) { return new GDTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9)>(new WhenAnyPromise(task1, task2, task3, task4, task5, task6, task7, task8, task9), 0); } sealed class WhenAnyPromise : IGDTaskSource<(int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9)> { int completedCount; GDTaskCompletionSourceCore<(int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9)> core; public WhenAnyPromise(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9) { TaskTracker.TrackActiveTask(this, 3); this.completedCount = 0; { var awaiter = task1.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT1(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT1(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task2.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT2(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT2(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task3.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT3(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT3(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task4.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT4(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT4(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task5.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT5(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT5(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task6.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT6(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT6(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task7.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT7(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT7(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task8.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT8(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT8(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task9.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT9(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT9(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } } static void TryInvokeContinuationT1(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T1 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((0, result, default, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT2(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T2 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((1, default, result, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT3(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T3 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((2, default, default, result, default, default, default, default, default, default)); } } static void TryInvokeContinuationT4(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T4 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((3, default, default, default, result, default, default, default, default, default)); } } static void TryInvokeContinuationT5(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T5 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((4, default, default, default, default, result, default, default, default, default)); } } static void TryInvokeContinuationT6(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T6 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((5, default, default, default, default, default, result, default, default, default)); } } static void TryInvokeContinuationT7(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T7 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((6, default, default, default, default, default, default, result, default, default)); } } static void TryInvokeContinuationT8(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T8 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((7, default, default, default, default, default, default, default, result, default)); } } static void TryInvokeContinuationT9(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T9 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((8, default, default, default, default, default, default, default, default, result)); } } public (int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9) GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } void IGDTaskSource.GetResult(short token) { GetResult(token); } } public static GDTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10)> WhenAny(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10) { return new GDTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10)>(new WhenAnyPromise(task1, task2, task3, task4, task5, task6, task7, task8, task9, task10), 0); } sealed class WhenAnyPromise : IGDTaskSource<(int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10)> { int completedCount; GDTaskCompletionSourceCore<(int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10)> core; public WhenAnyPromise(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10) { TaskTracker.TrackActiveTask(this, 3); this.completedCount = 0; { var awaiter = task1.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT1(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT1(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task2.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT2(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT2(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task3.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT3(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT3(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task4.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT4(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT4(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task5.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT5(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT5(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task6.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT6(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT6(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task7.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT7(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT7(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task8.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT8(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT8(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task9.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT9(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT9(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task10.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT10(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT10(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } } static void TryInvokeContinuationT1(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T1 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((0, result, default, default, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT2(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T2 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((1, default, result, default, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT3(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T3 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((2, default, default, result, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT4(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T4 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((3, default, default, default, result, default, default, default, default, default, default)); } } static void TryInvokeContinuationT5(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T5 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((4, default, default, default, default, result, default, default, default, default, default)); } } static void TryInvokeContinuationT6(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T6 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((5, default, default, default, default, default, result, default, default, default, default)); } } static void TryInvokeContinuationT7(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T7 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((6, default, default, default, default, default, default, result, default, default, default)); } } static void TryInvokeContinuationT8(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T8 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((7, default, default, default, default, default, default, default, result, default, default)); } } static void TryInvokeContinuationT9(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T9 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((8, default, default, default, default, default, default, default, default, result, default)); } } static void TryInvokeContinuationT10(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T10 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((9, default, default, default, default, default, default, default, default, default, result)); } } public (int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10) GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } void IGDTaskSource.GetResult(short token) { GetResult(token); } } public static GDTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10, T11 result11)> WhenAny(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10, GDTask task11) { return new GDTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10, T11 result11)>(new WhenAnyPromise(task1, task2, task3, task4, task5, task6, task7, task8, task9, task10, task11), 0); } sealed class WhenAnyPromise : IGDTaskSource<(int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10, T11 result11)> { int completedCount; GDTaskCompletionSourceCore<(int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10, T11 result11)> core; public WhenAnyPromise(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10, GDTask task11) { TaskTracker.TrackActiveTask(this, 3); this.completedCount = 0; { var awaiter = task1.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT1(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT1(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task2.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT2(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT2(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task3.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT3(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT3(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task4.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT4(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT4(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task5.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT5(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT5(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task6.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT6(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT6(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task7.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT7(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT7(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task8.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT8(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT8(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task9.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT9(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT9(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task10.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT10(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT10(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task11.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT11(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT11(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } } static void TryInvokeContinuationT1(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T1 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((0, result, default, default, default, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT2(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T2 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((1, default, result, default, default, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT3(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T3 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((2, default, default, result, default, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT4(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T4 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((3, default, default, default, result, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT5(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T5 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((4, default, default, default, default, result, default, default, default, default, default, default)); } } static void TryInvokeContinuationT6(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T6 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((5, default, default, default, default, default, result, default, default, default, default, default)); } } static void TryInvokeContinuationT7(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T7 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((6, default, default, default, default, default, default, result, default, default, default, default)); } } static void TryInvokeContinuationT8(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T8 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((7, default, default, default, default, default, default, default, result, default, default, default)); } } static void TryInvokeContinuationT9(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T9 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((8, default, default, default, default, default, default, default, default, result, default, default)); } } static void TryInvokeContinuationT10(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T10 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((9, default, default, default, default, default, default, default, default, default, result, default)); } } static void TryInvokeContinuationT11(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T11 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((10, default, default, default, default, default, default, default, default, default, default, result)); } } public (int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10, T11 result11) GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } void IGDTaskSource.GetResult(short token) { GetResult(token); } } public static GDTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10, T11 result11, T12 result12)> WhenAny(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10, GDTask task11, GDTask task12) { return new GDTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10, T11 result11, T12 result12)>(new WhenAnyPromise(task1, task2, task3, task4, task5, task6, task7, task8, task9, task10, task11, task12), 0); } sealed class WhenAnyPromise : IGDTaskSource<(int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10, T11 result11, T12 result12)> { int completedCount; GDTaskCompletionSourceCore<(int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10, T11 result11, T12 result12)> core; public WhenAnyPromise(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10, GDTask task11, GDTask task12) { TaskTracker.TrackActiveTask(this, 3); this.completedCount = 0; { var awaiter = task1.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT1(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT1(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task2.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT2(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT2(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task3.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT3(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT3(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task4.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT4(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT4(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task5.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT5(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT5(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task6.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT6(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT6(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task7.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT7(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT7(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task8.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT8(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT8(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task9.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT9(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT9(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task10.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT10(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT10(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task11.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT11(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT11(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task12.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT12(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT12(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } } static void TryInvokeContinuationT1(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T1 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((0, result, default, default, default, default, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT2(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T2 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((1, default, result, default, default, default, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT3(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T3 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((2, default, default, result, default, default, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT4(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T4 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((3, default, default, default, result, default, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT5(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T5 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((4, default, default, default, default, result, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT6(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T6 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((5, default, default, default, default, default, result, default, default, default, default, default, default)); } } static void TryInvokeContinuationT7(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T7 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((6, default, default, default, default, default, default, result, default, default, default, default, default)); } } static void TryInvokeContinuationT8(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T8 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((7, default, default, default, default, default, default, default, result, default, default, default, default)); } } static void TryInvokeContinuationT9(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T9 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((8, default, default, default, default, default, default, default, default, result, default, default, default)); } } static void TryInvokeContinuationT10(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T10 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((9, default, default, default, default, default, default, default, default, default, result, default, default)); } } static void TryInvokeContinuationT11(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T11 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((10, default, default, default, default, default, default, default, default, default, default, result, default)); } } static void TryInvokeContinuationT12(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T12 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((11, default, default, default, default, default, default, default, default, default, default, default, result)); } } public (int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10, T11 result11, T12 result12) GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } void IGDTaskSource.GetResult(short token) { GetResult(token); } } public static GDTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10, T11 result11, T12 result12, T13 result13)> WhenAny(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10, GDTask task11, GDTask task12, GDTask task13) { return new GDTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10, T11 result11, T12 result12, T13 result13)>(new WhenAnyPromise(task1, task2, task3, task4, task5, task6, task7, task8, task9, task10, task11, task12, task13), 0); } sealed class WhenAnyPromise : IGDTaskSource<(int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10, T11 result11, T12 result12, T13 result13)> { int completedCount; GDTaskCompletionSourceCore<(int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10, T11 result11, T12 result12, T13 result13)> core; public WhenAnyPromise(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10, GDTask task11, GDTask task12, GDTask task13) { TaskTracker.TrackActiveTask(this, 3); this.completedCount = 0; { var awaiter = task1.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT1(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT1(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task2.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT2(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT2(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task3.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT3(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT3(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task4.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT4(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT4(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task5.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT5(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT5(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task6.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT6(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT6(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task7.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT7(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT7(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task8.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT8(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT8(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task9.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT9(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT9(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task10.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT10(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT10(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task11.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT11(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT11(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task12.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT12(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT12(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task13.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT13(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT13(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } } static void TryInvokeContinuationT1(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T1 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((0, result, default, default, default, default, default, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT2(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T2 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((1, default, result, default, default, default, default, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT3(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T3 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((2, default, default, result, default, default, default, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT4(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T4 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((3, default, default, default, result, default, default, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT5(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T5 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((4, default, default, default, default, result, default, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT6(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T6 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((5, default, default, default, default, default, result, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT7(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T7 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((6, default, default, default, default, default, default, result, default, default, default, default, default, default)); } } static void TryInvokeContinuationT8(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T8 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((7, default, default, default, default, default, default, default, result, default, default, default, default, default)); } } static void TryInvokeContinuationT9(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T9 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((8, default, default, default, default, default, default, default, default, result, default, default, default, default)); } } static void TryInvokeContinuationT10(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T10 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((9, default, default, default, default, default, default, default, default, default, result, default, default, default)); } } static void TryInvokeContinuationT11(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T11 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((10, default, default, default, default, default, default, default, default, default, default, result, default, default)); } } static void TryInvokeContinuationT12(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T12 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((11, default, default, default, default, default, default, default, default, default, default, default, result, default)); } } static void TryInvokeContinuationT13(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T13 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((12, default, default, default, default, default, default, default, default, default, default, default, default, result)); } } public (int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10, T11 result11, T12 result12, T13 result13) GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } void IGDTaskSource.GetResult(short token) { GetResult(token); } } public static GDTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10, T11 result11, T12 result12, T13 result13, T14 result14)> WhenAny(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10, GDTask task11, GDTask task12, GDTask task13, GDTask task14) { return new GDTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10, T11 result11, T12 result12, T13 result13, T14 result14)>(new WhenAnyPromise(task1, task2, task3, task4, task5, task6, task7, task8, task9, task10, task11, task12, task13, task14), 0); } sealed class WhenAnyPromise : IGDTaskSource<(int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10, T11 result11, T12 result12, T13 result13, T14 result14)> { int completedCount; GDTaskCompletionSourceCore<(int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10, T11 result11, T12 result12, T13 result13, T14 result14)> core; public WhenAnyPromise(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10, GDTask task11, GDTask task12, GDTask task13, GDTask task14) { TaskTracker.TrackActiveTask(this, 3); this.completedCount = 0; { var awaiter = task1.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT1(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT1(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task2.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT2(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT2(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task3.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT3(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT3(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task4.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT4(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT4(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task5.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT5(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT5(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task6.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT6(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT6(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task7.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT7(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT7(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task8.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT8(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT8(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task9.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT9(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT9(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task10.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT10(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT10(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task11.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT11(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT11(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task12.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT12(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT12(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task13.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT13(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT13(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task14.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT14(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT14(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } } static void TryInvokeContinuationT1(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T1 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((0, result, default, default, default, default, default, default, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT2(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T2 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((1, default, result, default, default, default, default, default, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT3(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T3 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((2, default, default, result, default, default, default, default, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT4(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T4 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((3, default, default, default, result, default, default, default, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT5(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T5 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((4, default, default, default, default, result, default, default, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT6(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T6 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((5, default, default, default, default, default, result, default, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT7(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T7 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((6, default, default, default, default, default, default, result, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT8(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T8 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((7, default, default, default, default, default, default, default, result, default, default, default, default, default, default)); } } static void TryInvokeContinuationT9(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T9 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((8, default, default, default, default, default, default, default, default, result, default, default, default, default, default)); } } static void TryInvokeContinuationT10(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T10 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((9, default, default, default, default, default, default, default, default, default, result, default, default, default, default)); } } static void TryInvokeContinuationT11(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T11 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((10, default, default, default, default, default, default, default, default, default, default, result, default, default, default)); } } static void TryInvokeContinuationT12(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T12 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((11, default, default, default, default, default, default, default, default, default, default, default, result, default, default)); } } static void TryInvokeContinuationT13(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T13 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((12, default, default, default, default, default, default, default, default, default, default, default, default, result, default)); } } static void TryInvokeContinuationT14(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T14 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((13, default, default, default, default, default, default, default, default, default, default, default, default, default, result)); } } public (int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10, T11 result11, T12 result12, T13 result13, T14 result14) GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } void IGDTaskSource.GetResult(short token) { GetResult(token); } } public static GDTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10, T11 result11, T12 result12, T13 result13, T14 result14, T15 result15)> WhenAny(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10, GDTask task11, GDTask task12, GDTask task13, GDTask task14, GDTask task15) { return new GDTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10, T11 result11, T12 result12, T13 result13, T14 result14, T15 result15)>(new WhenAnyPromise(task1, task2, task3, task4, task5, task6, task7, task8, task9, task10, task11, task12, task13, task14, task15), 0); } sealed class WhenAnyPromise : IGDTaskSource<(int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10, T11 result11, T12 result12, T13 result13, T14 result14, T15 result15)> { int completedCount; GDTaskCompletionSourceCore<(int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10, T11 result11, T12 result12, T13 result13, T14 result14, T15 result15)> core; public WhenAnyPromise(GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10, GDTask task11, GDTask task12, GDTask task13, GDTask task14, GDTask task15) { TaskTracker.TrackActiveTask(this, 3); this.completedCount = 0; { var awaiter = task1.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT1(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT1(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task2.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT2(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT2(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task3.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT3(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT3(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task4.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT4(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT4(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task5.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT5(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT5(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task6.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT6(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT6(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task7.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT7(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT7(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task8.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT8(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT8(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task9.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT9(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT9(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task10.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT10(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT10(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task11.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT11(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT11(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task12.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT12(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT12(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task13.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT13(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT13(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task14.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT14(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT14(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } { var awaiter = task15.GetAwaiter(); if (awaiter.IsCompleted) { TryInvokeContinuationT15(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryInvokeContinuationT15(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } } static void TryInvokeContinuationT1(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T1 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((0, result, default, default, default, default, default, default, default, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT2(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T2 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((1, default, result, default, default, default, default, default, default, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT3(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T3 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((2, default, default, result, default, default, default, default, default, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT4(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T4 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((3, default, default, default, result, default, default, default, default, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT5(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T5 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((4, default, default, default, default, result, default, default, default, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT6(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T6 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((5, default, default, default, default, default, result, default, default, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT7(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T7 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((6, default, default, default, default, default, default, result, default, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT8(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T8 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((7, default, default, default, default, default, default, default, result, default, default, default, default, default, default, default)); } } static void TryInvokeContinuationT9(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T9 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((8, default, default, default, default, default, default, default, default, result, default, default, default, default, default, default)); } } static void TryInvokeContinuationT10(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T10 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((9, default, default, default, default, default, default, default, default, default, result, default, default, default, default, default)); } } static void TryInvokeContinuationT11(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T11 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((10, default, default, default, default, default, default, default, default, default, default, result, default, default, default, default)); } } static void TryInvokeContinuationT12(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T12 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((11, default, default, default, default, default, default, default, default, default, default, default, result, default, default, default)); } } static void TryInvokeContinuationT13(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T13 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((12, default, default, default, default, default, default, default, default, default, default, default, default, result, default, default)); } } static void TryInvokeContinuationT14(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T14 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((13, default, default, default, default, default, default, default, default, default, default, default, default, default, result, default)); } } static void TryInvokeContinuationT15(WhenAnyPromise self, in GDTask.Awaiter awaiter) { T15 result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((14, default, default, default, default, default, default, default, default, default, default, default, default, default, default, result)); } } public (int, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10, T11 result11, T12 result12, T13 result13, T14 result14, T15 result15) GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } void IGDTaskSource.GetResult(short token) { GetResult(token); } } } } ================================================ FILE: addons/GDTask/GDTask.WhenAny.Generated.cs.uid ================================================ uid://d4nthwpweeb5l ================================================ FILE: addons/GDTask/GDTask.WhenAny.cs ================================================ using System; using System.Collections.Generic; using System.Threading; using Fractural.Tasks.Internal; namespace Fractural.Tasks { public partial struct GDTask { public static GDTask<(bool hasResultLeft, T result)> WhenAny(GDTask leftTask, GDTask rightTask) { return new GDTask<(bool, T)>(new WhenAnyLRPromise(leftTask, rightTask), 0); } public static GDTask<(int winArgumentIndex, T result)> WhenAny(params GDTask[] tasks) { return new GDTask<(int, T)>(new WhenAnyPromise(tasks, tasks.Length), 0); } public static GDTask<(int winArgumentIndex, T result)> WhenAny(IEnumerable> tasks) { using (var span = ArrayPoolUtil.Materialize(tasks)) { return new GDTask<(int, T)>(new WhenAnyPromise(span.Array, span.Length), 0); } } /// Return value is winArgumentIndex public static GDTask WhenAny(params GDTask[] tasks) { return new GDTask(new WhenAnyPromise(tasks, tasks.Length), 0); } /// Return value is winArgumentIndex public static GDTask WhenAny(IEnumerable tasks) { using (var span = ArrayPoolUtil.Materialize(tasks)) { return new GDTask(new WhenAnyPromise(span.Array, span.Length), 0); } } sealed class WhenAnyLRPromise : IGDTaskSource<(bool, T)> { int completedCount; GDTaskCompletionSourceCore<(bool, T)> core; public WhenAnyLRPromise(GDTask leftTask, GDTask rightTask) { TaskTracker.TrackActiveTask(this, 3); { GDTask.Awaiter awaiter; try { awaiter = leftTask.GetAwaiter(); } catch (Exception ex) { core.TrySetException(ex); goto RIGHT; } if (awaiter.IsCompleted) { TryLeftInvokeContinuation(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryLeftInvokeContinuation(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } RIGHT: { GDTask.Awaiter awaiter; try { awaiter = rightTask.GetAwaiter(); } catch (Exception ex) { core.TrySetException(ex); return; } if (awaiter.IsCompleted) { TryRightInvokeContinuation(this, awaiter); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter>)state) { TryRightInvokeContinuation(t.Item1, t.Item2); } }, StateTuple.Create(this, awaiter)); } } } static void TryLeftInvokeContinuation(WhenAnyLRPromise self, in GDTask.Awaiter awaiter) { T result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((true, result)); } } static void TryRightInvokeContinuation(WhenAnyLRPromise self, in GDTask.Awaiter awaiter) { try { awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((false, default)); } } public (bool, T) GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } void IGDTaskSource.GetResult(short token) { GetResult(token); } } sealed class WhenAnyPromise : IGDTaskSource<(int, T)> { int completedCount; GDTaskCompletionSourceCore<(int, T)> core; public WhenAnyPromise(GDTask[] tasks, int tasksLength) { if (tasksLength == 0) { throw new ArgumentException("The tasks argument contains no tasks."); } TaskTracker.TrackActiveTask(this, 3); for (int i = 0; i < tasksLength; i++) { GDTask.Awaiter awaiter; try { awaiter = tasks[i].GetAwaiter(); } catch (Exception ex) { core.TrySetException(ex); continue; // consume others. } if (awaiter.IsCompleted) { TryInvokeContinuation(this, awaiter, i); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple, GDTask.Awaiter, int>)state) { TryInvokeContinuation(t.Item1, t.Item2, t.Item3); } }, StateTuple.Create(this, awaiter, i)); } } } static void TryInvokeContinuation(WhenAnyPromise self, in GDTask.Awaiter awaiter, int i) { T result; try { result = awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult((i, result)); } } public (int, T) GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } void IGDTaskSource.GetResult(short token) { GetResult(token); } } sealed class WhenAnyPromise : IGDTaskSource { int completedCount; GDTaskCompletionSourceCore core; public WhenAnyPromise(GDTask[] tasks, int tasksLength) { if (tasksLength == 0) { throw new ArgumentException("The tasks argument contains no tasks."); } TaskTracker.TrackActiveTask(this, 3); for (int i = 0; i < tasksLength; i++) { GDTask.Awaiter awaiter; try { awaiter = tasks[i].GetAwaiter(); } catch (Exception ex) { core.TrySetException(ex); continue; // consume others. } if (awaiter.IsCompleted) { TryInvokeContinuation(this, awaiter, i); } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple)state) { TryInvokeContinuation(t.Item1, t.Item2, t.Item3); } }, StateTuple.Create(this, awaiter, i)); } } } static void TryInvokeContinuation(WhenAnyPromise self, in GDTask.Awaiter awaiter, int i) { try { awaiter.GetResult(); } catch (Exception ex) { self.core.TrySetException(ex); return; } if (Interlocked.Increment(ref self.completedCount) == 1) { self.core.TrySetResult(i); } } public int GetResult(short token) { TaskTracker.RemoveTracking(this); GC.SuppressFinalize(this); return core.GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } void IGDTaskSource.GetResult(short token) { GetResult(token); } } } } ================================================ FILE: addons/GDTask/GDTask.WhenAny.cs.uid ================================================ uid://uleke6fyl60 ================================================ FILE: addons/GDTask/GDTask.cs ================================================ using Fractural.Tasks.CompilerServices; using System; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; using System.Runtime.InteropServices; using System.Threading; namespace Fractural.Tasks { internal static class AwaiterActions { internal static readonly Action InvokeContinuationDelegate = Continuation; [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] static void Continuation(object state) { ((Action)state).Invoke(); } } /// /// Lightweight Godot specific task-like object with a void return value. /// [AsyncMethodBuilder(typeof(AsyncGDTaskMethodBuilder))] [StructLayout(LayoutKind.Auto)] public readonly partial struct GDTask { readonly IGDTaskSource source; readonly short token; [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public GDTask(IGDTaskSource source, short token) { this.source = source; this.token = token; } public GDTaskStatus Status { [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] get { if (source == null) return GDTaskStatus.Succeeded; return source.GetStatus(token); } } [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public Awaiter GetAwaiter() { return new Awaiter(this); } /// /// returns (bool IsCanceled) instead of throws OperationCanceledException. /// public GDTask SuppressCancellationThrow() { var status = Status; if (status == GDTaskStatus.Succeeded) return CompletedTasks.False; if (status == GDTaskStatus.Canceled) return CompletedTasks.True; return new GDTask(new IsCanceledSource(source), token); } public override string ToString() { if (source == null) return "()"; return "(" + source.UnsafeGetStatus() + ")"; } /// /// Memoizing inner IValueTaskSource. The result GDTask can await multiple. /// public GDTask Preserve() { if (source == null) { return this; } else { return new GDTask(new MemoizeSource(source), token); } } public GDTask AsAsyncUnitGDTask() { if (this.source == null) return CompletedTasks.AsyncUnit; var status = this.source.GetStatus(this.token); if (status.IsCompletedSuccessfully()) { this.source.GetResult(this.token); return CompletedTasks.AsyncUnit; } else if (this.source is IGDTaskSource asyncUnitSource) { return new GDTask(asyncUnitSource, this.token); } return new GDTask(new AsyncUnitSource(this.source), this.token); } sealed class AsyncUnitSource : IGDTaskSource { readonly IGDTaskSource source; public AsyncUnitSource(IGDTaskSource source) { this.source = source; } public AsyncUnit GetResult(short token) { source.GetResult(token); return AsyncUnit.Default; } public GDTaskStatus GetStatus(short token) { return source.GetStatus(token); } public void OnCompleted(Action continuation, object state, short token) { source.OnCompleted(continuation, state, token); } public GDTaskStatus UnsafeGetStatus() { return source.UnsafeGetStatus(); } void IGDTaskSource.GetResult(short token) { GetResult(token); } } sealed class IsCanceledSource : IGDTaskSource { readonly IGDTaskSource source; public IsCanceledSource(IGDTaskSource source) { this.source = source; } public bool GetResult(short token) { if (source.GetStatus(token) == GDTaskStatus.Canceled) { return true; } source.GetResult(token); return false; } void IGDTaskSource.GetResult(short token) { GetResult(token); } public GDTaskStatus GetStatus(short token) { return source.GetStatus(token); } public GDTaskStatus UnsafeGetStatus() { return source.UnsafeGetStatus(); } public void OnCompleted(Action continuation, object state, short token) { source.OnCompleted(continuation, state, token); } } sealed class MemoizeSource : IGDTaskSource { IGDTaskSource source; ExceptionDispatchInfo exception; GDTaskStatus status; public MemoizeSource(IGDTaskSource source) { this.source = source; } public void GetResult(short token) { if (source == null) { if (exception != null) { exception.Throw(); } } else { try { source.GetResult(token); status = GDTaskStatus.Succeeded; } catch (Exception ex) { exception = ExceptionDispatchInfo.Capture(ex); if (ex is OperationCanceledException) { status = GDTaskStatus.Canceled; } else { status = GDTaskStatus.Faulted; } throw; } finally { source = null; } } } public GDTaskStatus GetStatus(short token) { if (source == null) { return status; } return source.GetStatus(token); } public void OnCompleted(Action continuation, object state, short token) { if (source == null) { continuation(state); } else { source.OnCompleted(continuation, state, token); } } public GDTaskStatus UnsafeGetStatus() { if (source == null) { return status; } return source.UnsafeGetStatus(); } } public readonly struct Awaiter : ICriticalNotifyCompletion { readonly GDTask task; [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public Awaiter(in GDTask task) { this.task = task; } public bool IsCompleted { [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return task.Status.IsCompleted(); } } [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public void GetResult() { if (task.source == null) return; task.source.GetResult(task.token); } [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public void OnCompleted(Action continuation) { if (task.source == null) { continuation(); } else { task.source.OnCompleted(AwaiterActions.InvokeContinuationDelegate, continuation, task.token); } } [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public void UnsafeOnCompleted(Action continuation) { if (task.source == null) { continuation(); } else { task.source.OnCompleted(AwaiterActions.InvokeContinuationDelegate, continuation, task.token); } } /// /// If register manually continuation, you can use it instead of for compiler OnCompleted methods. /// [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public void SourceOnCompleted(Action continuation, object state) { if (task.source == null) { continuation(state); } else { task.source.OnCompleted(continuation, state, task.token); } } } } /// /// Lightweight Godot specified task-like object with a return value. /// /// Return value of the task [AsyncMethodBuilder(typeof(AsyncGDTaskMethodBuilder<>))] [StructLayout(LayoutKind.Auto)] public readonly struct GDTask { readonly IGDTaskSource source; readonly T result; readonly short token; [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public GDTask(T result) { this.source = default; this.token = default; this.result = result; } [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public GDTask(IGDTaskSource source, short token) { this.source = source; this.token = token; this.result = default; } public GDTaskStatus Status { [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return (source == null) ? GDTaskStatus.Succeeded : source.GetStatus(token); } } [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public Awaiter GetAwaiter() { return new Awaiter(this); } /// /// Memoizing inner IValueTaskSource. The result GDTask can await multiple. /// public GDTask Preserve() { if (source == null) { return this; } else { return new GDTask(new MemoizeSource(source), token); } } public GDTask AsGDTask() { if (this.source == null) return GDTask.CompletedTask; var status = this.source.GetStatus(this.token); if (status.IsCompletedSuccessfully()) { this.source.GetResult(this.token); return GDTask.CompletedTask; } // Converting GDTask -> GDTask is zero overhead. return new GDTask(this.source, this.token); } public static implicit operator GDTask(GDTask self) { return self.AsGDTask(); } /// /// returns (bool IsCanceled, T Result) instead of throws OperationCanceledException. /// public GDTask<(bool IsCanceled, T Result)> SuppressCancellationThrow() { if (source == null) { return new GDTask<(bool IsCanceled, T Result)>((false, result)); } return new GDTask<(bool, T)>(new IsCanceledSource(source), token); } public override string ToString() { return (this.source == null) ? result?.ToString() : "(" + this.source.UnsafeGetStatus() + ")"; } sealed class IsCanceledSource : IGDTaskSource<(bool, T)> { readonly IGDTaskSource source; [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public IsCanceledSource(IGDTaskSource source) { this.source = source; } [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public (bool, T) GetResult(short token) { if (source.GetStatus(token) == GDTaskStatus.Canceled) { return (true, default); } var result = source.GetResult(token); return (false, result); } [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] void IGDTaskSource.GetResult(short token) { GetResult(token); } [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public GDTaskStatus GetStatus(short token) { return source.GetStatus(token); } [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public GDTaskStatus UnsafeGetStatus() { return source.UnsafeGetStatus(); } [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public void OnCompleted(Action continuation, object state, short token) { source.OnCompleted(continuation, state, token); } } sealed class MemoizeSource : IGDTaskSource { IGDTaskSource source; T result; ExceptionDispatchInfo exception; GDTaskStatus status; public MemoizeSource(IGDTaskSource source) { this.source = source; } public T GetResult(short token) { if (source == null) { if (exception != null) { exception.Throw(); } return result; } else { try { result = source.GetResult(token); status = GDTaskStatus.Succeeded; return result; } catch (Exception ex) { exception = ExceptionDispatchInfo.Capture(ex); if (ex is OperationCanceledException) { status = GDTaskStatus.Canceled; } else { status = GDTaskStatus.Faulted; } throw; } finally { source = null; } } } void IGDTaskSource.GetResult(short token) { GetResult(token); } public GDTaskStatus GetStatus(short token) { if (source == null) { return status; } return source.GetStatus(token); } public void OnCompleted(Action continuation, object state, short token) { if (source == null) { continuation(state); } else { source.OnCompleted(continuation, state, token); } } public GDTaskStatus UnsafeGetStatus() { if (source == null) { return status; } return source.UnsafeGetStatus(); } } public readonly struct Awaiter : ICriticalNotifyCompletion { readonly GDTask task; [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public Awaiter(in GDTask task) { this.task = task; } public bool IsCompleted { [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return task.Status.IsCompleted(); } } [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public T GetResult() { var s = task.source; if (s == null) { return task.result; } else { return s.GetResult(task.token); } } [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public void OnCompleted(Action continuation) { var s = task.source; if (s == null) { continuation(); } else { s.OnCompleted(AwaiterActions.InvokeContinuationDelegate, continuation, task.token); } } [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public void UnsafeOnCompleted(Action continuation) { var s = task.source; if (s == null) { continuation(); } else { s.OnCompleted(AwaiterActions.InvokeContinuationDelegate, continuation, task.token); } } /// /// If register manually continuation, you can use it instead of for compiler OnCompleted methods. /// [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public void SourceOnCompleted(Action continuation, object state) { var s = task.source; if (s == null) { continuation(state); } else { s.OnCompleted(continuation, state, task.token); } } } } } ================================================ FILE: addons/GDTask/GDTask.cs.uid ================================================ uid://c8flrnm5gs57i ================================================ FILE: addons/GDTask/GDTaskCompletionSource.cs ================================================ using System; using System.Collections.Generic; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; using System.Runtime.InteropServices; using System.Threading; using Fractural.Tasks.Internal; namespace Fractural.Tasks { public interface IResolvePromise { bool TrySetResult(); } public interface IResolvePromise { bool TrySetResult(T value); } public interface IRejectPromise { bool TrySetException(Exception exception); } public interface ICancelPromise { bool TrySetCanceled(CancellationToken cancellationToken = default); } public interface IPromise : IResolvePromise, IRejectPromise, ICancelPromise { } public interface IPromise : IResolvePromise, IRejectPromise, ICancelPromise { } internal class ExceptionHolder { ExceptionDispatchInfo exception; bool calledGet = false; public ExceptionHolder(ExceptionDispatchInfo exception) { this.exception = exception; } public ExceptionDispatchInfo GetException() { if (!calledGet) { calledGet = true; GC.SuppressFinalize(this); } return exception; } ~ExceptionHolder() { if (!calledGet) { GDTaskScheduler.PublishUnobservedTaskException(exception.SourceException); } } } [StructLayout(LayoutKind.Auto)] public struct GDTaskCompletionSourceCore { // Struct Size: TResult + (8 + 2 + 1 + 1 + 8 + 8) TResult result; object error; // ExceptionHolder or OperationCanceledException short version; bool hasUnhandledError; int completedCount; // 0: completed == false Action continuation; object continuationState; [DebuggerHidden] public void Reset() { ReportUnhandledError(); unchecked { version += 1; // incr version. } completedCount = 0; result = default; error = null; hasUnhandledError = false; continuation = null; continuationState = null; } void ReportUnhandledError() { if (hasUnhandledError) { try { if (error is OperationCanceledException oc) { GDTaskScheduler.PublishUnobservedTaskException(oc); } else if (error is ExceptionHolder e) { GDTaskScheduler.PublishUnobservedTaskException(e.GetException().SourceException); } } catch { } } } internal void MarkHandled() { hasUnhandledError = false; } /// Completes with a successful result. /// The result. [DebuggerHidden] public bool TrySetResult(TResult result) { if (Interlocked.Increment(ref completedCount) == 1) { // setup result this.result = result; if (continuation != null || Interlocked.CompareExchange(ref this.continuation, GDTaskCompletionSourceCoreShared.s_sentinel, null) != null) { continuation(continuationState); return true; } } return false; } /// Completes with an error. /// The exception. [DebuggerHidden] public bool TrySetException(Exception error) { if (Interlocked.Increment(ref completedCount) == 1) { // setup result this.hasUnhandledError = true; if (error is OperationCanceledException) { this.error = error; } else { this.error = new ExceptionHolder(ExceptionDispatchInfo.Capture(error)); } if (continuation != null || Interlocked.CompareExchange(ref this.continuation, GDTaskCompletionSourceCoreShared.s_sentinel, null) != null) { continuation(continuationState); return true; } } return false; } [DebuggerHidden] public bool TrySetCanceled(CancellationToken cancellationToken = default) { if (Interlocked.Increment(ref completedCount) == 1) { // setup result this.hasUnhandledError = true; this.error = new OperationCanceledException(cancellationToken); if (continuation != null || Interlocked.CompareExchange(ref this.continuation, GDTaskCompletionSourceCoreShared.s_sentinel, null) != null) { continuation(continuationState); return true; } } return false; } /// Gets the operation version. [DebuggerHidden] public short Version => version; /// Gets the status of the operation. /// Opaque value that was provided to the 's constructor. [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public GDTaskStatus GetStatus(short token) { ValidateToken(token); return (continuation == null || (completedCount == 0)) ? GDTaskStatus.Pending : (error == null) ? GDTaskStatus.Succeeded : (error is OperationCanceledException) ? GDTaskStatus.Canceled : GDTaskStatus.Faulted; } /// Gets the status of the operation without token validation. [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public GDTaskStatus UnsafeGetStatus() { return (continuation == null || (completedCount == 0)) ? GDTaskStatus.Pending : (error == null) ? GDTaskStatus.Succeeded : (error is OperationCanceledException) ? GDTaskStatus.Canceled : GDTaskStatus.Faulted; } /// Gets the result of the operation. /// Opaque value that was provided to the 's constructor. // [StackTraceHidden] [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public TResult GetResult(short token) { ValidateToken(token); if (completedCount == 0) { throw new InvalidOperationException("Not yet completed, GDTask only allow to use await."); } if (error != null) { hasUnhandledError = false; if (error is OperationCanceledException oce) { throw oce; } else if (error is ExceptionHolder eh) { eh.GetException().Throw(); } throw new InvalidOperationException("Critical: invalid exception type was held."); } return result; } /// Schedules the continuation action for this operation. /// The continuation to invoke when the operation has completed. /// The state object to pass to when it's invoked. /// Opaque value that was provided to the 's constructor. [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] public void OnCompleted(Action continuation, object state, short token /*, ValueTaskSourceOnCompletedFlags flags */) { if (continuation == null) { throw new ArgumentNullException(nameof(continuation)); } ValidateToken(token); /* no use ValueTaskSourceOnCOmpletedFlags, always no capture ExecutionContext and SynchronizationContext. */ /* PatternA: GetStatus=Pending => OnCompleted => TrySet*** => GetResult PatternB: TrySet*** => GetStatus=!Pending => GetResult PatternC: GetStatus=Pending => TrySet/OnCompleted(race condition) => GetResult C.1: win OnCompleted -> TrySet invoke saved continuation C.2: win TrySet -> should invoke continuation here. */ // not set continuation yet. object oldContinuation = this.continuation; if (oldContinuation == null) { continuationState = state; oldContinuation = Interlocked.CompareExchange(ref this.continuation, continuation, null); } if (oldContinuation != null) { // already running continuation in TrySet. // It will cause call OnCompleted multiple time, invalid. if (!ReferenceEquals(oldContinuation, GDTaskCompletionSourceCoreShared.s_sentinel)) { throw new InvalidOperationException("Already continuation registered, can not await twice or get Status after await."); } continuation(state); } } [DebuggerHidden] [MethodImpl(MethodImplOptions.AggressiveInlining)] private void ValidateToken(short token) { if (token != version) { throw new InvalidOperationException("Token version is not matched, can not await twice or get Status after await."); } } } internal static class GDTaskCompletionSourceCoreShared // separated out of generic to avoid unnecessary duplication { internal static readonly Action s_sentinel = CompletionSentinel; private static void CompletionSentinel(object _) // named method to aid debugging { throw new InvalidOperationException("The sentinel delegate should never be invoked."); } } public partial class AutoResetGDTaskCompletionSource : IGDTaskSource, ITaskPoolNode, IPromise { static TaskPool pool; AutoResetGDTaskCompletionSource nextNode; public ref AutoResetGDTaskCompletionSource NextNode => ref nextNode; static AutoResetGDTaskCompletionSource() { TaskPool.RegisterSizeGetter(typeof(AutoResetGDTaskCompletionSource), () => pool.Size); } GDTaskCompletionSourceCore core; AutoResetGDTaskCompletionSource() { } [DebuggerHidden] public static AutoResetGDTaskCompletionSource Create() { if (!pool.TryPop(out var result)) { result = new AutoResetGDTaskCompletionSource(); } TaskTracker.TrackActiveTask(result, 2); return result; } [DebuggerHidden] public static AutoResetGDTaskCompletionSource CreateFromCanceled(CancellationToken cancellationToken, out short token) { var source = Create(); source.TrySetCanceled(cancellationToken); token = source.core.Version; return source; } [DebuggerHidden] public static AutoResetGDTaskCompletionSource CreateFromException(Exception exception, out short token) { var source = Create(); source.TrySetException(exception); token = source.core.Version; return source; } [DebuggerHidden] public static AutoResetGDTaskCompletionSource CreateCompleted(out short token) { var source = Create(); source.TrySetResult(); token = source.core.Version; return source; } public GDTask Task { [DebuggerHidden] get { return new GDTask(this, core.Version); } } [DebuggerHidden] public bool TrySetResult() { return core.TrySetResult(AsyncUnit.Default); } [DebuggerHidden] public bool TrySetCanceled(CancellationToken cancellationToken = default) { return core.TrySetCanceled(cancellationToken); } [DebuggerHidden] public bool TrySetException(Exception exception) { return core.TrySetException(exception); } [DebuggerHidden] public void GetResult(short token) { try { core.GetResult(token); } finally { TryReturn(); } } [DebuggerHidden] public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } [DebuggerHidden] public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } [DebuggerHidden] public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } [DebuggerHidden] bool TryReturn() { TaskTracker.RemoveTracking(this); core.Reset(); return pool.TryPush(this); } } public partial class AutoResetGDTaskCompletionSource : IGDTaskSource, ITaskPoolNode>, IPromise { static TaskPool> pool; AutoResetGDTaskCompletionSource nextNode; public ref AutoResetGDTaskCompletionSource NextNode => ref nextNode; static AutoResetGDTaskCompletionSource() { TaskPool.RegisterSizeGetter(typeof(AutoResetGDTaskCompletionSource), () => pool.Size); } GDTaskCompletionSourceCore core; AutoResetGDTaskCompletionSource() { } [DebuggerHidden] public static AutoResetGDTaskCompletionSource Create() { if (!pool.TryPop(out var result)) { result = new AutoResetGDTaskCompletionSource(); } TaskTracker.TrackActiveTask(result, 2); return result; } [DebuggerHidden] public static AutoResetGDTaskCompletionSource CreateFromCanceled(CancellationToken cancellationToken, out short token) { var source = Create(); source.TrySetCanceled(cancellationToken); token = source.core.Version; return source; } [DebuggerHidden] public static AutoResetGDTaskCompletionSource CreateFromException(Exception exception, out short token) { var source = Create(); source.TrySetException(exception); token = source.core.Version; return source; } [DebuggerHidden] public static AutoResetGDTaskCompletionSource CreateFromResult(T result, out short token) { var source = Create(); source.TrySetResult(result); token = source.core.Version; return source; } public GDTask Task { [DebuggerHidden] get { return new GDTask(this, core.Version); } } [DebuggerHidden] public bool TrySetResult(T result) { return core.TrySetResult(result); } [DebuggerHidden] public bool TrySetCanceled(CancellationToken cancellationToken = default) { return core.TrySetCanceled(cancellationToken); } [DebuggerHidden] public bool TrySetException(Exception exception) { return core.TrySetException(exception); } [DebuggerHidden] public T GetResult(short token) { try { return core.GetResult(token); } finally { TryReturn(); } } [DebuggerHidden] void IGDTaskSource.GetResult(short token) { GetResult(token); } [DebuggerHidden] public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } [DebuggerHidden] public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } [DebuggerHidden] public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } [DebuggerHidden] bool TryReturn() { TaskTracker.RemoveTracking(this); core.Reset(); return pool.TryPush(this); } } public partial class GDTaskCompletionSource : IGDTaskSource, IPromise { CancellationToken cancellationToken; ExceptionHolder exception; object gate; Action singleContinuation; object singleState; List<(Action, object)> secondaryContinuationList; int intStatus; // GDTaskStatus bool handled = false; public GDTaskCompletionSource() { TaskTracker.TrackActiveTask(this, 2); } [DebuggerHidden] internal void MarkHandled() { if (!handled) { handled = true; TaskTracker.RemoveTracking(this); } } public GDTask Task { [DebuggerHidden] get { return new GDTask(this, 0); } } [DebuggerHidden] public bool TrySetResult() { return TrySignalCompletion(GDTaskStatus.Succeeded); } [DebuggerHidden] public bool TrySetCanceled(CancellationToken cancellationToken = default) { if (UnsafeGetStatus() != GDTaskStatus.Pending) return false; this.cancellationToken = cancellationToken; return TrySignalCompletion(GDTaskStatus.Canceled); } [DebuggerHidden] public bool TrySetException(Exception exception) { if (exception is OperationCanceledException oce) { return TrySetCanceled(oce.CancellationToken); } if (UnsafeGetStatus() != GDTaskStatus.Pending) return false; this.exception = new ExceptionHolder(ExceptionDispatchInfo.Capture(exception)); return TrySignalCompletion(GDTaskStatus.Faulted); } [DebuggerHidden] public void GetResult(short token) { MarkHandled(); var status = (GDTaskStatus)intStatus; switch (status) { case GDTaskStatus.Succeeded: return; case GDTaskStatus.Faulted: exception.GetException().Throw(); return; case GDTaskStatus.Canceled: throw new OperationCanceledException(cancellationToken); default: case GDTaskStatus.Pending: throw new InvalidOperationException("not yet completed."); } } [DebuggerHidden] public GDTaskStatus GetStatus(short token) { return (GDTaskStatus)intStatus; } [DebuggerHidden] public GDTaskStatus UnsafeGetStatus() { return (GDTaskStatus)intStatus; } [DebuggerHidden] public void OnCompleted(Action continuation, object state, short token) { if (gate == null) { Interlocked.CompareExchange(ref gate, new object(), null); } var lockGate = Thread.VolatileRead(ref gate); lock (lockGate) // wait TrySignalCompletion, after status is not pending. { if ((GDTaskStatus)intStatus != GDTaskStatus.Pending) { continuation(state); return; } if (singleContinuation == null) { singleContinuation = continuation; singleState = state; } else { if (secondaryContinuationList == null) { secondaryContinuationList = new List<(Action, object)>(); } secondaryContinuationList.Add((continuation, state)); } } } [DebuggerHidden] bool TrySignalCompletion(GDTaskStatus status) { if (Interlocked.CompareExchange(ref intStatus, (int)status, (int)GDTaskStatus.Pending) == (int)GDTaskStatus.Pending) { if (gate == null) { Interlocked.CompareExchange(ref gate, new object(), null); } var lockGate = Thread.VolatileRead(ref gate); lock (lockGate) // wait OnCompleted. { if (singleContinuation != null) { try { singleContinuation(singleState); } catch (Exception ex) { GDTaskScheduler.PublishUnobservedTaskException(ex); } } if (secondaryContinuationList != null) { foreach (var (c, state) in secondaryContinuationList) { try { c(state); } catch (Exception ex) { GDTaskScheduler.PublishUnobservedTaskException(ex); } } } singleContinuation = null; singleState = null; secondaryContinuationList = null; } return true; } return false; } } public partial class GDTaskCompletionSource : IGDTaskSource, IPromise { CancellationToken cancellationToken; T result; ExceptionHolder exception; object gate; Action singleContinuation; object singleState; List<(Action, object)> secondaryContinuationList; int intStatus; // GDTaskStatus bool handled = false; public GDTaskCompletionSource() { TaskTracker.TrackActiveTask(this, 2); } [DebuggerHidden] internal void MarkHandled() { if (!handled) { handled = true; TaskTracker.RemoveTracking(this); } } public GDTask Task { [DebuggerHidden] get { return new GDTask(this, 0); } } [DebuggerHidden] public bool TrySetResult(T result) { if (UnsafeGetStatus() != GDTaskStatus.Pending) return false; this.result = result; return TrySignalCompletion(GDTaskStatus.Succeeded); } [DebuggerHidden] public bool TrySetCanceled(CancellationToken cancellationToken = default) { if (UnsafeGetStatus() != GDTaskStatus.Pending) return false; this.cancellationToken = cancellationToken; return TrySignalCompletion(GDTaskStatus.Canceled); } [DebuggerHidden] public bool TrySetException(Exception exception) { if (exception is OperationCanceledException oce) { return TrySetCanceled(oce.CancellationToken); } if (UnsafeGetStatus() != GDTaskStatus.Pending) return false; this.exception = new ExceptionHolder(ExceptionDispatchInfo.Capture(exception)); return TrySignalCompletion(GDTaskStatus.Faulted); } [DebuggerHidden] public T GetResult(short token) { MarkHandled(); var status = (GDTaskStatus)intStatus; switch (status) { case GDTaskStatus.Succeeded: return result; case GDTaskStatus.Faulted: exception.GetException().Throw(); return default; case GDTaskStatus.Canceled: throw new OperationCanceledException(cancellationToken); default: case GDTaskStatus.Pending: throw new InvalidOperationException("not yet completed."); } } [DebuggerHidden] void IGDTaskSource.GetResult(short token) { GetResult(token); } [DebuggerHidden] public GDTaskStatus GetStatus(short token) { return (GDTaskStatus)intStatus; } [DebuggerHidden] public GDTaskStatus UnsafeGetStatus() { return (GDTaskStatus)intStatus; } [DebuggerHidden] public void OnCompleted(Action continuation, object state, short token) { if (gate == null) { Interlocked.CompareExchange(ref gate, new object(), null); } var lockGate = Thread.VolatileRead(ref gate); lock (lockGate) // wait TrySignalCompletion, after status is not pending. { if ((GDTaskStatus)intStatus != GDTaskStatus.Pending) { continuation(state); return; } if (singleContinuation == null) { singleContinuation = continuation; singleState = state; } else { if (secondaryContinuationList == null) { secondaryContinuationList = new List<(Action, object)>(); } secondaryContinuationList.Add((continuation, state)); } } } [DebuggerHidden] bool TrySignalCompletion(GDTaskStatus status) { if (Interlocked.CompareExchange(ref intStatus, (int)status, (int)GDTaskStatus.Pending) == (int)GDTaskStatus.Pending) { if (gate == null) { Interlocked.CompareExchange(ref gate, new object(), null); } var lockGate = Thread.VolatileRead(ref gate); lock (lockGate) // wait OnCompleted. { if (singleContinuation != null) { try { singleContinuation(singleState); } catch (Exception ex) { GDTaskScheduler.PublishUnobservedTaskException(ex); } } if (secondaryContinuationList != null) { foreach (var (c, state) in secondaryContinuationList) { try { c(state); } catch (Exception ex) { GDTaskScheduler.PublishUnobservedTaskException(ex); } } } singleContinuation = null; singleState = null; secondaryContinuationList = null; } return true; } return false; } } } ================================================ FILE: addons/GDTask/GDTaskCompletionSource.cs.uid ================================================ uid://lh2yoqrvk0fp ================================================ FILE: addons/GDTask/GDTaskExtensions.Shorthand.cs ================================================ using System.Collections.Generic; namespace Fractural.Tasks { public static partial class GDTaskExtensions { // shorthand of WhenAll public static GDTask.Awaiter GetAwaiter(this GDTask[] tasks) { return GDTask.WhenAll(tasks).GetAwaiter(); } public static GDTask.Awaiter GetAwaiter(this IEnumerable tasks) { return GDTask.WhenAll(tasks).GetAwaiter(); } public static GDTask.Awaiter GetAwaiter(this GDTask[] tasks) { return GDTask.WhenAll(tasks).GetAwaiter(); } public static GDTask.Awaiter GetAwaiter(this IEnumerable> tasks) { return GDTask.WhenAll(tasks).GetAwaiter(); } public static GDTask<(T1, T2)>.Awaiter GetAwaiter(this (GDTask task1, GDTask task2) tasks) { return GDTask.WhenAll(tasks.Item1, tasks.Item2).GetAwaiter(); } public static GDTask<(T1, T2, T3)>.Awaiter GetAwaiter(this (GDTask task1, GDTask task2, GDTask task3) tasks) { return GDTask.WhenAll(tasks.Item1, tasks.Item2, tasks.Item3).GetAwaiter(); } public static GDTask<(T1, T2, T3, T4)>.Awaiter GetAwaiter(this (GDTask task1, GDTask task2, GDTask task3, GDTask task4) tasks) { return GDTask.WhenAll(tasks.Item1, tasks.Item2, tasks.Item3, tasks.Item4).GetAwaiter(); } public static GDTask<(T1, T2, T3, T4, T5)>.Awaiter GetAwaiter(this (GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5) tasks) { return GDTask.WhenAll(tasks.Item1, tasks.Item2, tasks.Item3, tasks.Item4, tasks.Item5).GetAwaiter(); } public static GDTask<(T1, T2, T3, T4, T5, T6)>.Awaiter GetAwaiter(this (GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6) tasks) { return GDTask.WhenAll(tasks.Item1, tasks.Item2, tasks.Item3, tasks.Item4, tasks.Item5, tasks.Item6).GetAwaiter(); } public static GDTask<(T1, T2, T3, T4, T5, T6, T7)>.Awaiter GetAwaiter(this (GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7) tasks) { return GDTask.WhenAll(tasks.Item1, tasks.Item2, tasks.Item3, tasks.Item4, tasks.Item5, tasks.Item6, tasks.Item7).GetAwaiter(); } public static GDTask<(T1, T2, T3, T4, T5, T6, T7, T8)>.Awaiter GetAwaiter(this (GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8) tasks) { return GDTask.WhenAll(tasks.Item1, tasks.Item2, tasks.Item3, tasks.Item4, tasks.Item5, tasks.Item6, tasks.Item7, tasks.Item8).GetAwaiter(); } public static GDTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9)>.Awaiter GetAwaiter(this (GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9) tasks) { return GDTask.WhenAll(tasks.Item1, tasks.Item2, tasks.Item3, tasks.Item4, tasks.Item5, tasks.Item6, tasks.Item7, tasks.Item8, tasks.Item9).GetAwaiter(); } public static GDTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)>.Awaiter GetAwaiter(this (GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10) tasks) { return GDTask.WhenAll(tasks.Item1, tasks.Item2, tasks.Item3, tasks.Item4, tasks.Item5, tasks.Item6, tasks.Item7, tasks.Item8, tasks.Item9, tasks.Item10).GetAwaiter(); } public static GDTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11)>.Awaiter GetAwaiter(this (GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10, GDTask task11) tasks) { return GDTask.WhenAll(tasks.Item1, tasks.Item2, tasks.Item3, tasks.Item4, tasks.Item5, tasks.Item6, tasks.Item7, tasks.Item8, tasks.Item9, tasks.Item10, tasks.Item11).GetAwaiter(); } public static GDTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12)>.Awaiter GetAwaiter(this (GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10, GDTask task11, GDTask task12) tasks) { return GDTask.WhenAll(tasks.Item1, tasks.Item2, tasks.Item3, tasks.Item4, tasks.Item5, tasks.Item6, tasks.Item7, tasks.Item8, tasks.Item9, tasks.Item10, tasks.Item11, tasks.Item12).GetAwaiter(); } public static GDTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13)>.Awaiter GetAwaiter(this (GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10, GDTask task11, GDTask task12, GDTask task13) tasks) { return GDTask.WhenAll(tasks.Item1, tasks.Item2, tasks.Item3, tasks.Item4, tasks.Item5, tasks.Item6, tasks.Item7, tasks.Item8, tasks.Item9, tasks.Item10, tasks.Item11, tasks.Item12, tasks.Item13).GetAwaiter(); } public static GDTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14)>.Awaiter GetAwaiter(this (GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10, GDTask task11, GDTask task12, GDTask task13, GDTask task14) tasks) { return GDTask.WhenAll(tasks.Item1, tasks.Item2, tasks.Item3, tasks.Item4, tasks.Item5, tasks.Item6, tasks.Item7, tasks.Item8, tasks.Item9, tasks.Item10, tasks.Item11, tasks.Item12, tasks.Item13, tasks.Item14).GetAwaiter(); } public static GDTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15)>.Awaiter GetAwaiter(this (GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10, GDTask task11, GDTask task12, GDTask task13, GDTask task14, GDTask task15) tasks) { return GDTask.WhenAll(tasks.Item1, tasks.Item2, tasks.Item3, tasks.Item4, tasks.Item5, tasks.Item6, tasks.Item7, tasks.Item8, tasks.Item9, tasks.Item10, tasks.Item11, tasks.Item12, tasks.Item13, tasks.Item14, tasks.Item15).GetAwaiter(); } public static GDTask.Awaiter GetAwaiter(this (GDTask task1, GDTask task2) tasks) { return GDTask.WhenAll(tasks.Item1, tasks.Item2).GetAwaiter(); } public static GDTask.Awaiter GetAwaiter(this (GDTask task1, GDTask task2, GDTask task3) tasks) { return GDTask.WhenAll(tasks.Item1, tasks.Item2, tasks.Item3).GetAwaiter(); } public static GDTask.Awaiter GetAwaiter(this (GDTask task1, GDTask task2, GDTask task3, GDTask task4) tasks) { return GDTask.WhenAll(tasks.Item1, tasks.Item2, tasks.Item3, tasks.Item4).GetAwaiter(); } public static GDTask.Awaiter GetAwaiter(this (GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5) tasks) { return GDTask.WhenAll(tasks.Item1, tasks.Item2, tasks.Item3, tasks.Item4, tasks.Item5).GetAwaiter(); } public static GDTask.Awaiter GetAwaiter(this (GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6) tasks) { return GDTask.WhenAll(tasks.Item1, tasks.Item2, tasks.Item3, tasks.Item4, tasks.Item5, tasks.Item6).GetAwaiter(); } public static GDTask.Awaiter GetAwaiter(this (GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7) tasks) { return GDTask.WhenAll(tasks.Item1, tasks.Item2, tasks.Item3, tasks.Item4, tasks.Item5, tasks.Item6, tasks.Item7).GetAwaiter(); } public static GDTask.Awaiter GetAwaiter(this (GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8) tasks) { return GDTask.WhenAll(tasks.Item1, tasks.Item2, tasks.Item3, tasks.Item4, tasks.Item5, tasks.Item6, tasks.Item7, tasks.Item8).GetAwaiter(); } public static GDTask.Awaiter GetAwaiter(this (GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9) tasks) { return GDTask.WhenAll(tasks.Item1, tasks.Item2, tasks.Item3, tasks.Item4, tasks.Item5, tasks.Item6, tasks.Item7, tasks.Item8, tasks.Item9).GetAwaiter(); } public static GDTask.Awaiter GetAwaiter(this (GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10) tasks) { return GDTask.WhenAll(tasks.Item1, tasks.Item2, tasks.Item3, tasks.Item4, tasks.Item5, tasks.Item6, tasks.Item7, tasks.Item8, tasks.Item9, tasks.Item10).GetAwaiter(); } public static GDTask.Awaiter GetAwaiter(this (GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10, GDTask task11) tasks) { return GDTask.WhenAll(tasks.Item1, tasks.Item2, tasks.Item3, tasks.Item4, tasks.Item5, tasks.Item6, tasks.Item7, tasks.Item8, tasks.Item9, tasks.Item10, tasks.Item11).GetAwaiter(); } public static GDTask.Awaiter GetAwaiter(this (GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10, GDTask task11, GDTask task12) tasks) { return GDTask.WhenAll(tasks.Item1, tasks.Item2, tasks.Item3, tasks.Item4, tasks.Item5, tasks.Item6, tasks.Item7, tasks.Item8, tasks.Item9, tasks.Item10, tasks.Item11, tasks.Item12).GetAwaiter(); } public static GDTask.Awaiter GetAwaiter(this (GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10, GDTask task11, GDTask task12, GDTask task13) tasks) { return GDTask.WhenAll(tasks.Item1, tasks.Item2, tasks.Item3, tasks.Item4, tasks.Item5, tasks.Item6, tasks.Item7, tasks.Item8, tasks.Item9, tasks.Item10, tasks.Item11, tasks.Item12, tasks.Item13).GetAwaiter(); } public static GDTask.Awaiter GetAwaiter(this (GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10, GDTask task11, GDTask task12, GDTask task13, GDTask task14) tasks) { return GDTask.WhenAll(tasks.Item1, tasks.Item2, tasks.Item3, tasks.Item4, tasks.Item5, tasks.Item6, tasks.Item7, tasks.Item8, tasks.Item9, tasks.Item10, tasks.Item11, tasks.Item12, tasks.Item13, tasks.Item14).GetAwaiter(); } public static GDTask.Awaiter GetAwaiter(this (GDTask task1, GDTask task2, GDTask task3, GDTask task4, GDTask task5, GDTask task6, GDTask task7, GDTask task8, GDTask task9, GDTask task10, GDTask task11, GDTask task12, GDTask task13, GDTask task14, GDTask task15) tasks) { return GDTask.WhenAll(tasks.Item1, tasks.Item2, tasks.Item3, tasks.Item4, tasks.Item5, tasks.Item6, tasks.Item7, tasks.Item8, tasks.Item9, tasks.Item10, tasks.Item11, tasks.Item12, tasks.Item13, tasks.Item14, tasks.Item15).GetAwaiter(); } } } ================================================ FILE: addons/GDTask/GDTaskExtensions.Shorthand.cs.uid ================================================ uid://3sn3amfk43em ================================================ FILE: addons/GDTask/GDTaskExtensions.cs ================================================ using System; using System.Threading; using System.Threading.Tasks; using Fractural.Tasks.Internal; namespace Fractural.Tasks { public static partial class GDTaskExtensions { /// /// Convert Task[T] -> GDTask[T]. /// public static GDTask AsGDTask(this Task task, bool useCurrentSynchronizationContext = true) { var promise = new GDTaskCompletionSource(); task.ContinueWith((x, state) => { var p = (GDTaskCompletionSource)state; switch (x.Status) { case TaskStatus.Canceled: p.TrySetCanceled(); break; case TaskStatus.Faulted: p.TrySetException(x.Exception); break; case TaskStatus.RanToCompletion: p.TrySetResult(x.Result); break; default: throw new NotSupportedException(); } }, promise, useCurrentSynchronizationContext ? TaskScheduler.FromCurrentSynchronizationContext() : TaskScheduler.Current); return promise.Task; } /// /// Convert Task -> GDTask. /// public static GDTask AsGDTask(this Task task, bool useCurrentSynchronizationContext = true) { var promise = new GDTaskCompletionSource(); task.ContinueWith((x, state) => { var p = (GDTaskCompletionSource)state; switch (x.Status) { case TaskStatus.Canceled: p.TrySetCanceled(); break; case TaskStatus.Faulted: p.TrySetException(x.Exception); break; case TaskStatus.RanToCompletion: p.TrySetResult(); break; default: throw new NotSupportedException(); } }, promise, useCurrentSynchronizationContext ? TaskScheduler.FromCurrentSynchronizationContext() : TaskScheduler.Current); return promise.Task; } public static Task AsTask(this GDTask task) { try { GDTask.Awaiter awaiter; try { awaiter = task.GetAwaiter(); } catch (Exception ex) { return Task.FromException(ex); } if (awaiter.IsCompleted) { try { var result = awaiter.GetResult(); return Task.FromResult(result); } catch (Exception ex) { return Task.FromException(ex); } } var tcs = new TaskCompletionSource(); awaiter.SourceOnCompleted(state => { using (var tuple = (StateTuple, GDTask.Awaiter>)state) { var (inTcs, inAwaiter) = tuple; try { var result = inAwaiter.GetResult(); inTcs.SetResult(result); } catch (Exception ex) { inTcs.SetException(ex); } } }, StateTuple.Create(tcs, awaiter)); return tcs.Task; } catch (Exception ex) { return Task.FromException(ex); } } public static Task AsTask(this GDTask task) { try { GDTask.Awaiter awaiter; try { awaiter = task.GetAwaiter(); } catch (Exception ex) { return Task.FromException(ex); } if (awaiter.IsCompleted) { try { awaiter.GetResult(); // check token valid on Succeeded return Task.CompletedTask; } catch (Exception ex) { return Task.FromException(ex); } } var tcs = new TaskCompletionSource(); awaiter.SourceOnCompleted(state => { using (var tuple = (StateTuple, GDTask.Awaiter>)state) { var (inTcs, inAwaiter) = tuple; try { inAwaiter.GetResult(); inTcs.SetResult(null); } catch (Exception ex) { inTcs.SetException(ex); } } }, StateTuple.Create(tcs, awaiter)); return tcs.Task; } catch (Exception ex) { return Task.FromException(ex); } } public static AsyncLazy ToAsyncLazy(this GDTask task) { return new AsyncLazy(task); } public static AsyncLazy ToAsyncLazy(this GDTask task) { return new AsyncLazy(task); } /// /// Ignore task result when cancel raised first. /// public static GDTask AttachExternalCancellation(this GDTask task, CancellationToken cancellationToken) { if (!cancellationToken.CanBeCanceled) { return task; } if (cancellationToken.IsCancellationRequested) { return GDTask.FromCanceled(cancellationToken); } if (task.Status.IsCompleted()) { return task; } return new GDTask(new AttachExternalCancellationSource(task, cancellationToken), 0); } /// /// Ignore task result when cancel raised first. /// public static GDTask AttachExternalCancellation(this GDTask task, CancellationToken cancellationToken) { if (!cancellationToken.CanBeCanceled) { return task; } if (cancellationToken.IsCancellationRequested) { return GDTask.FromCanceled(cancellationToken); } if (task.Status.IsCompleted()) { return task; } return new GDTask(new AttachExternalCancellationSource(task, cancellationToken), 0); } sealed class AttachExternalCancellationSource : IGDTaskSource { static readonly Action cancellationCallbackDelegate = CancellationCallback; CancellationToken cancellationToken; CancellationTokenRegistration tokenRegistration; GDTaskCompletionSourceCore core; public AttachExternalCancellationSource(GDTask task, CancellationToken cancellationToken) { this.cancellationToken = cancellationToken; this.tokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallbackDelegate, this); RunTask(task).Forget(); } async GDTaskVoid RunTask(GDTask task) { try { await task; core.TrySetResult(AsyncUnit.Default); } catch (Exception ex) { core.TrySetException(ex); } finally { tokenRegistration.Dispose(); } } static void CancellationCallback(object state) { var self = (AttachExternalCancellationSource)state; self.core.TrySetCanceled(self.cancellationToken); } public void GetResult(short token) { core.GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } } sealed class AttachExternalCancellationSource : IGDTaskSource { static readonly Action cancellationCallbackDelegate = CancellationCallback; CancellationToken cancellationToken; CancellationTokenRegistration tokenRegistration; GDTaskCompletionSourceCore core; public AttachExternalCancellationSource(GDTask task, CancellationToken cancellationToken) { this.cancellationToken = cancellationToken; this.tokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallbackDelegate, this); RunTask(task).Forget(); } async GDTaskVoid RunTask(GDTask task) { try { core.TrySetResult(await task); } catch (Exception ex) { core.TrySetException(ex); } finally { tokenRegistration.Dispose(); } } static void CancellationCallback(object state) { var self = (AttachExternalCancellationSource)state; self.core.TrySetCanceled(self.cancellationToken); } void IGDTaskSource.GetResult(short token) { core.GetResult(token); } public T GetResult(short token) { return core.GetResult(token); } public GDTaskStatus GetStatus(short token) { return core.GetStatus(token); } public void OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } public GDTaskStatus UnsafeGetStatus() { return core.UnsafeGetStatus(); } } public static async GDTask Timeout(this GDTask task, TimeSpan timeout, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming timeoutCheckTiming = PlayerLoopTiming.Process, CancellationTokenSource taskCancellationTokenSource = null) { var delayCancellationTokenSource = new CancellationTokenSource(); var timeoutTask = GDTask.Delay(timeout, delayType, timeoutCheckTiming, delayCancellationTokenSource.Token).SuppressCancellationThrow(); int winArgIndex; bool taskResultIsCanceled; try { (winArgIndex, taskResultIsCanceled, _) = await GDTask.WhenAny(task.SuppressCancellationThrow(), timeoutTask); } catch { delayCancellationTokenSource.Cancel(); delayCancellationTokenSource.Dispose(); throw; } // timeout if (winArgIndex == 1) { if (taskCancellationTokenSource != null) { taskCancellationTokenSource.Cancel(); taskCancellationTokenSource.Dispose(); } throw new TimeoutException("Exceed Timeout:" + timeout); } else { delayCancellationTokenSource.Cancel(); delayCancellationTokenSource.Dispose(); } if (taskResultIsCanceled) { Error.ThrowOperationCanceledException(); } } public static async GDTask Timeout(this GDTask task, TimeSpan timeout, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming timeoutCheckTiming = PlayerLoopTiming.Process, CancellationTokenSource taskCancellationTokenSource = null) { var delayCancellationTokenSource = new CancellationTokenSource(); var timeoutTask = GDTask.Delay(timeout, delayType, timeoutCheckTiming, delayCancellationTokenSource.Token).SuppressCancellationThrow(); int winArgIndex; (bool IsCanceled, T Result) taskResult; try { (winArgIndex, taskResult, _) = await GDTask.WhenAny(task.SuppressCancellationThrow(), timeoutTask); } catch { delayCancellationTokenSource.Cancel(); delayCancellationTokenSource.Dispose(); throw; } // timeout if (winArgIndex == 1) { if (taskCancellationTokenSource != null) { taskCancellationTokenSource.Cancel(); taskCancellationTokenSource.Dispose(); } throw new TimeoutException("Exceed Timeout:" + timeout); } else { delayCancellationTokenSource.Cancel(); delayCancellationTokenSource.Dispose(); } if (taskResult.IsCanceled) { Error.ThrowOperationCanceledException(); } return taskResult.Result; } /// /// Timeout with suppress OperationCanceledException. Returns (bool, IsCacneled). /// public static async GDTask TimeoutWithoutException(this GDTask task, TimeSpan timeout, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming timeoutCheckTiming = PlayerLoopTiming.Process, CancellationTokenSource taskCancellationTokenSource = null) { var delayCancellationTokenSource = new CancellationTokenSource(); var timeoutTask = GDTask.Delay(timeout, delayType, timeoutCheckTiming, delayCancellationTokenSource.Token).SuppressCancellationThrow(); int winArgIndex; bool taskResultIsCanceled; try { (winArgIndex, taskResultIsCanceled, _) = await GDTask.WhenAny(task.SuppressCancellationThrow(), timeoutTask); } catch { delayCancellationTokenSource.Cancel(); delayCancellationTokenSource.Dispose(); return true; } // timeout if (winArgIndex == 1) { if (taskCancellationTokenSource != null) { taskCancellationTokenSource.Cancel(); taskCancellationTokenSource.Dispose(); } return true; } else { delayCancellationTokenSource.Cancel(); delayCancellationTokenSource.Dispose(); } if (taskResultIsCanceled) { return true; } return false; } /// /// Timeout with suppress OperationCanceledException. Returns (bool IsTimeout, T Result). /// public static async GDTask<(bool IsTimeout, T Result)> TimeoutWithoutException(this GDTask task, TimeSpan timeout, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming timeoutCheckTiming = PlayerLoopTiming.Process, CancellationTokenSource taskCancellationTokenSource = null) { var delayCancellationTokenSource = new CancellationTokenSource(); var timeoutTask = GDTask.Delay(timeout, delayType, timeoutCheckTiming, delayCancellationTokenSource.Token).SuppressCancellationThrow(); int winArgIndex; (bool IsCanceled, T Result) taskResult; try { (winArgIndex, taskResult, _) = await GDTask.WhenAny(task.SuppressCancellationThrow(), timeoutTask); } catch { delayCancellationTokenSource.Cancel(); delayCancellationTokenSource.Dispose(); return (true, default); } // timeout if (winArgIndex == 1) { if (taskCancellationTokenSource != null) { taskCancellationTokenSource.Cancel(); taskCancellationTokenSource.Dispose(); } return (true, default); } else { delayCancellationTokenSource.Cancel(); delayCancellationTokenSource.Dispose(); } if (taskResult.IsCanceled) { return (true, default); } return (false, taskResult.Result); } public static void Forget(this GDTask task) { var awaiter = task.GetAwaiter(); if (awaiter.IsCompleted) { try { awaiter.GetResult(); } catch (Exception ex) { GDTaskScheduler.PublishUnobservedTaskException(ex); } } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple)state) { try { t.Item1.GetResult(); } catch (Exception ex) { GDTaskScheduler.PublishUnobservedTaskException(ex); } } }, StateTuple.Create(awaiter)); } } public static void Forget(this GDTask task, Action exceptionHandler, bool handleExceptionOnMainThread = true) { if (exceptionHandler == null) { Forget(task); } else { ForgetCoreWithCatch(task, exceptionHandler, handleExceptionOnMainThread).Forget(); } } static async GDTaskVoid ForgetCoreWithCatch(GDTask task, Action exceptionHandler, bool handleExceptionOnMainThread) { try { await task; } catch (Exception ex) { try { if (handleExceptionOnMainThread) { await GDTask.SwitchToMainThread(); } exceptionHandler(ex); } catch (Exception ex2) { GDTaskScheduler.PublishUnobservedTaskException(ex2); } } } public static void Forget(this GDTask task) { var awaiter = task.GetAwaiter(); if (awaiter.IsCompleted) { try { awaiter.GetResult(); } catch (Exception ex) { GDTaskScheduler.PublishUnobservedTaskException(ex); } } else { awaiter.SourceOnCompleted(state => { using (var t = (StateTuple.Awaiter>)state) { try { t.Item1.GetResult(); } catch (Exception ex) { GDTaskScheduler.PublishUnobservedTaskException(ex); } } }, StateTuple.Create(awaiter)); } } public static void Forget(this GDTask task, Action exceptionHandler, bool handleExceptionOnMainThread = true) { if (exceptionHandler == null) { task.Forget(); } else { ForgetCoreWithCatch(task, exceptionHandler, handleExceptionOnMainThread).Forget(); } } static async GDTaskVoid ForgetCoreWithCatch(GDTask task, Action exceptionHandler, bool handleExceptionOnMainThread) { try { await task; } catch (Exception ex) { try { if (handleExceptionOnMainThread) { await GDTask.SwitchToMainThread(); } exceptionHandler(ex); } catch (Exception ex2) { GDTaskScheduler.PublishUnobservedTaskException(ex2); } } } public static async GDTask ContinueWith(this GDTask task, Action continuationFunction) { continuationFunction(await task); } public static async GDTask ContinueWith(this GDTask task, Func continuationFunction) { await continuationFunction(await task); } public static async GDTask ContinueWith(this GDTask task, Func continuationFunction) { return continuationFunction(await task); } public static async GDTask ContinueWith(this GDTask task, Func> continuationFunction) { return await continuationFunction(await task); } public static async GDTask ContinueWith(this GDTask task, Action continuationFunction) { await task; continuationFunction(); } public static async GDTask ContinueWith(this GDTask task, Func continuationFunction) { await task; await continuationFunction(); } public static async GDTask ContinueWith(this GDTask task, Func continuationFunction) { await task; return continuationFunction(); } public static async GDTask ContinueWith(this GDTask task, Func> continuationFunction) { await task; return await continuationFunction(); } public static async GDTask ContinueWith(this GDTask task, Action continuationFunction) { await task; continuationFunction(); } public static async GDTask ContinueWith(this GDTask task, Func continuationFunction) { await task; await continuationFunction(); } public static async GDTask ContinueWith(this GDTask task, Func continuationFunction) { await task; return continuationFunction(); } public static async GDTask ContinueWith(this GDTask task, Func> continuationFunction) { await task; return await continuationFunction(); } public static async GDTask Unwrap(this GDTask> task) { return await await task; } public static async GDTask Unwrap(this GDTask task) { await await task; } public static async GDTask Unwrap(this Task> task) { return await await task; } public static async GDTask Unwrap(this Task> task, bool continueOnCapturedContext) { return await await task.ConfigureAwait(continueOnCapturedContext); } public static async GDTask Unwrap(this Task task) { await await task; } public static async GDTask Unwrap(this Task task, bool continueOnCapturedContext) { await await task.ConfigureAwait(continueOnCapturedContext); } public static async GDTask Unwrap(this GDTask> task) { return await await task; } public static async GDTask Unwrap(this GDTask> task, bool continueOnCapturedContext) { return await (await task).ConfigureAwait(continueOnCapturedContext); } public static async GDTask Unwrap(this GDTask task) { await await task; } public static async GDTask Unwrap(this GDTask task, bool continueOnCapturedContext) { await (await task).ConfigureAwait(continueOnCapturedContext); } } } ================================================ FILE: addons/GDTask/GDTaskExtensions.cs.uid ================================================ uid://cqppdk8mlk6t2 ================================================ FILE: addons/GDTask/GDTaskObservableExtensions.cs ================================================ using System; using System.Runtime.ExceptionServices; using System.Threading; using Fractural.Tasks.Internal; namespace Fractural.Tasks { public static class GDTaskObservableExtensions { public static GDTask ToGDTask(this IObservable source, bool useFirstValue = false, CancellationToken cancellationToken = default) { var promise = new GDTaskCompletionSource(); var disposable = new SingleAssignmentDisposable(); var observer = useFirstValue ? (IObserver)new FirstValueToGDTaskObserver(promise, disposable, cancellationToken) : (IObserver)new ToGDTaskObserver(promise, disposable, cancellationToken); try { disposable.Disposable = source.Subscribe(observer); } catch (Exception ex) { promise.TrySetException(ex); } return promise.Task; } public static IObservable ToObservable(this GDTask task) { if (task.Status.IsCompleted()) { try { return new ReturnObservable(task.GetAwaiter().GetResult()); } catch (Exception ex) { return new ThrowObservable(ex); } } var subject = new AsyncSubject(); Fire(subject, task).Forget(); return subject; } /// /// Ideally returns IObservabl[Unit] is best but GDTask does not have Unit so return AsyncUnit instead. /// public static IObservable ToObservable(this GDTask task) { if (task.Status.IsCompleted()) { try { task.GetAwaiter().GetResult(); return new ReturnObservable(AsyncUnit.Default); } catch (Exception ex) { return new ThrowObservable(ex); } } var subject = new AsyncSubject(); Fire(subject, task).Forget(); return subject; } static async GDTaskVoid Fire(AsyncSubject subject, GDTask task) { T value; try { value = await task; } catch (Exception ex) { subject.OnError(ex); return; } subject.OnNext(value); subject.OnCompleted(); } static async GDTaskVoid Fire(AsyncSubject subject, GDTask task) { try { await task; } catch (Exception ex) { subject.OnError(ex); return; } subject.OnNext(AsyncUnit.Default); subject.OnCompleted(); } class ToGDTaskObserver : IObserver { static readonly Action callback = OnCanceled; readonly GDTaskCompletionSource promise; readonly SingleAssignmentDisposable disposable; readonly CancellationToken cancellationToken; readonly CancellationTokenRegistration registration; bool hasValue; T latestValue; public ToGDTaskObserver(GDTaskCompletionSource promise, SingleAssignmentDisposable disposable, CancellationToken cancellationToken) { this.promise = promise; this.disposable = disposable; this.cancellationToken = cancellationToken; if (this.cancellationToken.CanBeCanceled) { this.registration = this.cancellationToken.RegisterWithoutCaptureExecutionContext(callback, this); } } static void OnCanceled(object state) { var self = (ToGDTaskObserver)state; self.disposable.Dispose(); self.promise.TrySetCanceled(self.cancellationToken); } public void OnNext(T value) { hasValue = true; latestValue = value; } public void OnError(Exception error) { try { promise.TrySetException(error); } finally { registration.Dispose(); disposable.Dispose(); } } public void OnCompleted() { try { if (hasValue) { promise.TrySetResult(latestValue); } else { promise.TrySetException(new InvalidOperationException("Sequence has no elements")); } } finally { registration.Dispose(); disposable.Dispose(); } } } class FirstValueToGDTaskObserver : IObserver { static readonly Action callback = OnCanceled; readonly GDTaskCompletionSource promise; readonly SingleAssignmentDisposable disposable; readonly CancellationToken cancellationToken; readonly CancellationTokenRegistration registration; bool hasValue; public FirstValueToGDTaskObserver(GDTaskCompletionSource promise, SingleAssignmentDisposable disposable, CancellationToken cancellationToken) { this.promise = promise; this.disposable = disposable; this.cancellationToken = cancellationToken; if (this.cancellationToken.CanBeCanceled) { this.registration = this.cancellationToken.RegisterWithoutCaptureExecutionContext(callback, this); } } static void OnCanceled(object state) { var self = (FirstValueToGDTaskObserver)state; self.disposable.Dispose(); self.promise.TrySetCanceled(self.cancellationToken); } public void OnNext(T value) { hasValue = true; try { promise.TrySetResult(value); } finally { registration.Dispose(); disposable.Dispose(); } } public void OnError(Exception error) { try { promise.TrySetException(error); } finally { registration.Dispose(); disposable.Dispose(); } } public void OnCompleted() { try { if (!hasValue) { promise.TrySetException(new InvalidOperationException("Sequence has no elements")); } } finally { registration.Dispose(); disposable.Dispose(); } } } class ReturnObservable : IObservable { readonly T value; public ReturnObservable(T value) { this.value = value; } public IDisposable Subscribe(IObserver observer) { observer.OnNext(value); observer.OnCompleted(); return EmptyDisposable.Instance; } } class ThrowObservable : IObservable { readonly Exception value; public ThrowObservable(Exception value) { this.value = value; } public IDisposable Subscribe(IObserver observer) { observer.OnError(value); return EmptyDisposable.Instance; } } } } namespace Fractural.Tasks.Internal { // Bridges for Rx. internal class EmptyDisposable : IDisposable { public static EmptyDisposable Instance = new EmptyDisposable(); EmptyDisposable() { } public void Dispose() { } } internal sealed class SingleAssignmentDisposable : IDisposable { readonly object gate = new object(); IDisposable current; bool disposed; public bool IsDisposed { get { lock (gate) { return disposed; } } } public IDisposable Disposable { get { return current; } set { var old = default(IDisposable); bool alreadyDisposed; lock (gate) { alreadyDisposed = disposed; old = current; if (!alreadyDisposed) { if (value == null) return; current = value; } } if (alreadyDisposed && value != null) { value.Dispose(); return; } if (old != null) throw new InvalidOperationException("Disposable is already set"); } } public void Dispose() { IDisposable old = null; lock (gate) { if (!disposed) { disposed = true; old = current; current = null; } } if (old != null) old.Dispose(); } } internal sealed class AsyncSubject : IObservable, IObserver { object observerLock = new object(); T lastValue; bool hasValue; bool isStopped; bool isDisposed; Exception lastError; IObserver outObserver = EmptyObserver.Instance; public T Value { get { ThrowIfDisposed(); if (!isStopped) throw new InvalidOperationException("AsyncSubject is not completed yet"); if (lastError != null) ExceptionDispatchInfo.Capture(lastError).Throw(); return lastValue; } } public bool HasObservers { get { return !(outObserver is EmptyObserver) && !isStopped && !isDisposed; } } public bool IsCompleted { get { return isStopped; } } public void OnCompleted() { IObserver old; T v; bool hv; lock (observerLock) { ThrowIfDisposed(); if (isStopped) return; old = outObserver; outObserver = EmptyObserver.Instance; isStopped = true; v = lastValue; hv = hasValue; } if (hv) { old.OnNext(v); old.OnCompleted(); } else { old.OnCompleted(); } } public void OnError(Exception error) { if (error == null) throw new ArgumentNullException("error"); IObserver old; lock (observerLock) { ThrowIfDisposed(); if (isStopped) return; old = outObserver; outObserver = EmptyObserver.Instance; isStopped = true; lastError = error; } old.OnError(error); } public void OnNext(T value) { lock (observerLock) { ThrowIfDisposed(); if (isStopped) return; this.hasValue = true; this.lastValue = value; } } public IDisposable Subscribe(IObserver observer) { if (observer == null) throw new ArgumentNullException("observer"); var ex = default(Exception); var v = default(T); var hv = false; lock (observerLock) { ThrowIfDisposed(); if (!isStopped) { var listObserver = outObserver as ListObserver; if (listObserver != null) { outObserver = listObserver.Add(observer); } else { var current = outObserver; if (current is EmptyObserver) { outObserver = observer; } else { outObserver = new ListObserver(new ImmutableList>(new[] { current, observer })); } } return new Subscription(this, observer); } ex = lastError; v = lastValue; hv = hasValue; } if (ex != null) { observer.OnError(ex); } else if (hv) { observer.OnNext(v); observer.OnCompleted(); } else { observer.OnCompleted(); } return EmptyDisposable.Instance; } public void Dispose() { lock (observerLock) { isDisposed = true; outObserver = DisposedObserver.Instance; lastError = null; lastValue = default(T); } } void ThrowIfDisposed() { if (isDisposed) throw new ObjectDisposedException(""); } class Subscription : IDisposable { readonly object gate = new object(); AsyncSubject parent; IObserver unsubscribeTarget; public Subscription(AsyncSubject parent, IObserver unsubscribeTarget) { this.parent = parent; this.unsubscribeTarget = unsubscribeTarget; } public void Dispose() { lock (gate) { if (parent != null) { lock (parent.observerLock) { var listObserver = parent.outObserver as ListObserver; if (listObserver != null) { parent.outObserver = listObserver.Remove(unsubscribeTarget); } else { parent.outObserver = EmptyObserver.Instance; } unsubscribeTarget = null; parent = null; } } } } } } internal class ListObserver : IObserver { private readonly ImmutableList> _observers; public ListObserver(ImmutableList> observers) { _observers = observers; } public void OnCompleted() { var targetObservers = _observers.Data; for (int i = 0; i < targetObservers.Length; i++) { targetObservers[i].OnCompleted(); } } public void OnError(Exception error) { var targetObservers = _observers.Data; for (int i = 0; i < targetObservers.Length; i++) { targetObservers[i].OnError(error); } } public void OnNext(T value) { var targetObservers = _observers.Data; for (int i = 0; i < targetObservers.Length; i++) { targetObservers[i].OnNext(value); } } internal IObserver Add(IObserver observer) { return new ListObserver(_observers.Add(observer)); } internal IObserver Remove(IObserver observer) { var i = Array.IndexOf(_observers.Data, observer); if (i < 0) return this; if (_observers.Data.Length == 2) { return _observers.Data[1 - i]; } else { return new ListObserver(_observers.Remove(observer)); } } } internal class EmptyObserver : IObserver { public static readonly EmptyObserver Instance = new EmptyObserver(); EmptyObserver() { } public void OnCompleted() { } public void OnError(Exception error) { } public void OnNext(T value) { } } internal class ThrowObserver : IObserver { public static readonly ThrowObserver Instance = new ThrowObserver(); ThrowObserver() { } public void OnCompleted() { } public void OnError(Exception error) { ExceptionDispatchInfo.Capture(error).Throw(); } public void OnNext(T value) { } } internal class DisposedObserver : IObserver { public static readonly DisposedObserver Instance = new DisposedObserver(); DisposedObserver() { } public void OnCompleted() { throw new ObjectDisposedException(""); } public void OnError(Exception error) { throw new ObjectDisposedException(""); } public void OnNext(T value) { throw new ObjectDisposedException(""); } } internal class ImmutableList { public static readonly ImmutableList Empty = new ImmutableList(); T[] data; public T[] Data { get { return data; } } ImmutableList() { data = new T[0]; } public ImmutableList(T[] data) { this.data = data; } public ImmutableList Add(T value) { var newData = new T[data.Length + 1]; Array.Copy(data, newData, data.Length); newData[data.Length] = value; return new ImmutableList(newData); } public ImmutableList Remove(T value) { var i = IndexOf(value); if (i < 0) return this; var length = data.Length; if (length == 1) return Empty; var newData = new T[length - 1]; Array.Copy(data, 0, newData, 0, i); Array.Copy(data, i + 1, newData, i, length - i - 1); return new ImmutableList(newData); } public int IndexOf(T value) { for (var i = 0; i < data.Length; ++i) { // ImmutableList only use for IObserver(no worry for boxed) if (object.Equals(data[i], value)) return i; } return -1; } } } ================================================ FILE: addons/GDTask/GDTaskObservableExtensions.cs.uid ================================================ uid://bkg2p8poqeue2 ================================================ FILE: addons/GDTask/GDTaskScheduler.cs ================================================ using System; using System.Threading; using Godot; namespace Fractural.Tasks { // GDTask has no scheduler like TaskScheduler. // Only handle unobserved exception. public static class GDTaskScheduler { public static event Action UnobservedTaskException; /// /// Propagate OperationCanceledException to UnobservedTaskException when true. Default is false. /// public static bool PropagateOperationCanceledException = false; internal static void PublishUnobservedTaskException(Exception ex) { if (ex != null) { if (!PropagateOperationCanceledException && ex is OperationCanceledException) { return; } if (UnobservedTaskException != null) { UnobservedTaskException.Invoke(ex); } else { GD.PrintErr("UnobservedTaskException: " + ex.ToString()); } } } } } ================================================ FILE: addons/GDTask/GDTaskScheduler.cs.uid ================================================ uid://caqlg0dx35lpq ================================================ FILE: addons/GDTask/GDTaskSynchronizationContext.cs ================================================ using Godot; using System; using System.Runtime.InteropServices; using System.Threading; namespace Fractural.Tasks { public partial class GDTaskSynchronizationContext : SynchronizationContext { const int MaxArrayLength = 0X7FEFFFFF; const int InitialSize = 16; static SpinLock gate = new SpinLock(false); static bool dequing = false; static int actionListCount = 0; static Callback[] actionList = new Callback[InitialSize]; static int waitingListCount = 0; static Callback[] waitingList = new Callback[InitialSize]; static int opCount; public override void Send(SendOrPostCallback d, object state) { d(state); } public override void Post(SendOrPostCallback d, object state) { bool lockTaken = false; try { gate.Enter(ref lockTaken); if (dequing) { // Ensure Capacity if (waitingList.Length == waitingListCount) { var newLength = waitingListCount * 2; if ((uint)newLength > MaxArrayLength) newLength = MaxArrayLength; var newArray = new Callback[newLength]; Array.Copy(waitingList, newArray, waitingListCount); waitingList = newArray; } waitingList[waitingListCount] = new Callback(d, state); waitingListCount++; } else { // Ensure Capacity if (actionList.Length == actionListCount) { var newLength = actionListCount * 2; if ((uint)newLength > MaxArrayLength) newLength = MaxArrayLength; var newArray = new Callback[newLength]; Array.Copy(actionList, newArray, actionListCount); actionList = newArray; } actionList[actionListCount] = new Callback(d, state); actionListCount++; } } finally { if (lockTaken) gate.Exit(false); } } public override void OperationStarted() { Interlocked.Increment(ref opCount); } public override void OperationCompleted() { Interlocked.Decrement(ref opCount); } public override SynchronizationContext CreateCopy() { return this; } // delegate entrypoint. internal static void Run() { { bool lockTaken = false; try { gate.Enter(ref lockTaken); if (actionListCount == 0) return; dequing = true; } finally { if (lockTaken) gate.Exit(false); } } for (int i = 0; i < actionListCount; i++) { var action = actionList[i]; actionList[i] = default; action.Invoke(); } { bool lockTaken = false; try { gate.Enter(ref lockTaken); dequing = false; var swapTempActionList = actionList; actionListCount = waitingListCount; actionList = waitingList; waitingListCount = 0; waitingList = swapTempActionList; } finally { if (lockTaken) gate.Exit(false); } } } [StructLayout(LayoutKind.Auto)] readonly struct Callback { readonly SendOrPostCallback callback; readonly object state; public Callback(SendOrPostCallback callback, object state) { this.callback = callback; this.state = state; } public void Invoke() { try { callback(state); } catch (Exception ex) { GD.PrintErr(ex); } } } } } ================================================ FILE: addons/GDTask/GDTaskSynchronizationContext.cs.uid ================================================ uid://blaimw6ec387c ================================================ FILE: addons/GDTask/GDTaskVoid.cs ================================================ #pragma warning disable CS1591 #pragma warning disable CS0436 using System; using System.Diagnostics; using System.Runtime.CompilerServices; using Fractural.Tasks.CompilerServices; namespace Fractural.Tasks { [AsyncMethodBuilder(typeof(AsyncGDTaskVoidMethodBuilder))] public readonly struct GDTaskVoid { public void Forget() { } } } ================================================ FILE: addons/GDTask/GDTaskVoid.cs.uid ================================================ uid://dcq6np6u58ldd ================================================ FILE: addons/GDTask/IGDTaskSource.cs ================================================ using System; using System.Runtime.CompilerServices; namespace Fractural.Tasks { public enum GDTaskStatus { /// The operation has not yet completed. Pending = 0, /// The operation completed successfully. Succeeded = 1, /// The operation completed with an error. Faulted = 2, /// The operation completed due to cancellation. Canceled = 3 } // General architecture: // Each GDTask holds a IGDTaskSource, which determines how the GDTask will run. This is basically a strategy pattern. // GDTask is a struct, so will be allocated on stack with no garbage collection. All IGDTaskSources will be pooled using // TaskPool, so again, no garabage will be generated. // // Hence we achieve 0 memory allocation, making our tasks run really fast. /// /// GDTaskSource that has a void return (returns nothing). /// public interface IGDTaskSource { GDTaskStatus GetStatus(short token); void OnCompleted(Action continuation, object state, short token); void GetResult(short token); GDTaskStatus UnsafeGetStatus(); // only for debug use. } /// /// GDTaskSource that has a return value of /// /// Return value of the task source public interface IGDTaskSource : IGDTaskSource { // Hide the original void GetResult method new T GetResult(short token); } // Extensions are all aggressive inlined so all calls are substituted with raw code for greatest performance. public static class GDTaskStatusExtensions { /// status != Pending. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsCompleted(this GDTaskStatus status) { return status != GDTaskStatus.Pending; } /// status == Succeeded. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsCompletedSuccessfully(this GDTaskStatus status) { return status == GDTaskStatus.Succeeded; } /// status == Canceled. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsCanceled(this GDTaskStatus status) { return status == GDTaskStatus.Canceled; } /// status == Faulted. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsFaulted(this GDTaskStatus status) { return status == GDTaskStatus.Faulted; } } } ================================================ FILE: addons/GDTask/IGDTaskSource.cs.uid ================================================ uid://c342n7et0cbxw ================================================ FILE: addons/GDTask/Internal/ArrayPool.cs ================================================ using System; using System.Threading; namespace Fractural.Tasks.Internal { // Same interface as System.Buffers.ArrayPool but only provides Shared. internal sealed class ArrayPool { // Same size as System.Buffers.DefaultArrayPool const int DefaultMaxNumberOfArraysPerBucket = 50; static readonly T[] EmptyArray = new T[0]; public static readonly ArrayPool Shared = new ArrayPool(); readonly MinimumQueue[] buckets; readonly SpinLock[] locks; ArrayPool() { // see: GetQueueIndex buckets = new MinimumQueue[18]; locks = new SpinLock[18]; for (int i = 0; i < buckets.Length; i++) { buckets[i] = new MinimumQueue(4); locks[i] = new SpinLock(false); } } public T[] Rent(int minimumLength) { if (minimumLength < 0) { throw new ArgumentOutOfRangeException("minimumLength"); } else if (minimumLength == 0) { return EmptyArray; } var size = CalculateSize(minimumLength); var index = GetQueueIndex(size); if (index != -1) { var q = buckets[index]; var lockTaken = false; try { locks[index].Enter(ref lockTaken); if (q.Count != 0) { return q.Dequeue(); } } finally { if (lockTaken) locks[index].Exit(false); } } return new T[size]; } public void Return(T[] array, bool clearArray = false) { if (array == null || array.Length == 0) { return; } var index = GetQueueIndex(array.Length); if (index != -1) { if (clearArray) { Array.Clear(array, 0, array.Length); } var q = buckets[index]; var lockTaken = false; try { locks[index].Enter(ref lockTaken); if (q.Count > DefaultMaxNumberOfArraysPerBucket) { return; } q.Enqueue(array); } finally { if (lockTaken) locks[index].Exit(false); } } } static int CalculateSize(int size) { size--; size |= size >> 1; size |= size >> 2; size |= size >> 4; size |= size >> 8; size |= size >> 16; size += 1; if (size < 8) { size = 8; } return size; } static int GetQueueIndex(int size) { switch (size) { case 8: return 0; case 16: return 1; case 32: return 2; case 64: return 3; case 128: return 4; case 256: return 5; case 512: return 6; case 1024: return 7; case 2048: return 8; case 4096: return 9; case 8192: return 10; case 16384: return 11; case 32768: return 12; case 65536: return 13; case 131072: return 14; case 262144: return 15; case 524288: return 16; case 1048576: return 17; // max array length default: return -1; } } } } ================================================ FILE: addons/GDTask/Internal/ArrayPool.cs.uid ================================================ uid://bt5k6u0r44m4f ================================================ FILE: addons/GDTask/Internal/ArrayPoolUtil.cs ================================================ using System; using System.Collections.Generic; using System.Runtime.CompilerServices; namespace Fractural.Tasks.Internal { internal static class ArrayPoolUtil { [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void EnsureCapacity(ref T[] array, int index, ArrayPool pool) { if (array.Length <= index) { EnsureCapacityCore(ref array, index, pool); } } [MethodImpl(MethodImplOptions.NoInlining)] static void EnsureCapacityCore(ref T[] array, int index, ArrayPool pool) { if (array.Length <= index) { var newSize = array.Length * 2; var newArray = pool.Rent((index < newSize) ? newSize : (index * 2)); Array.Copy(array, 0, newArray, 0, array.Length); pool.Return(array, clearArray: !RuntimeHelpersAbstraction.IsWellKnownNoReferenceContainsType()); array = newArray; } } public static RentArray Materialize(IEnumerable source) { if (source is T[] array) { return new RentArray(array, array.Length, null); } var defaultCount = 32; if (source is ICollection coll) { if (coll.Count == 0) { return new RentArray(Array.Empty(), 0, null); } defaultCount = coll.Count; var pool = ArrayPool.Shared; var buffer = pool.Rent(defaultCount); coll.CopyTo(buffer, 0); return new RentArray(buffer, coll.Count, pool); } else if (source is IReadOnlyCollection rcoll) { defaultCount = rcoll.Count; } if (defaultCount == 0) { return new RentArray(Array.Empty(), 0, null); } { var pool = ArrayPool.Shared; var index = 0; var buffer = pool.Rent(defaultCount); foreach (var item in source) { EnsureCapacity(ref buffer, index, pool); buffer[index++] = item; } return new RentArray(buffer, index, pool); } } public struct RentArray : IDisposable { public readonly T[] Array; public readonly int Length; ArrayPool pool; public RentArray(T[] array, int length, ArrayPool pool) { this.Array = array; this.Length = length; this.pool = pool; } public void Dispose() { DisposeManually(!RuntimeHelpersAbstraction.IsWellKnownNoReferenceContainsType()); } public void DisposeManually(bool clearArray) { if (pool != null) { if (clearArray) { System.Array.Clear(Array, 0, Length); } pool.Return(Array, clearArray: false); pool = null; } } } } } ================================================ FILE: addons/GDTask/Internal/ArrayPoolUtil.cs.uid ================================================ uid://b73uh74arc3l7 ================================================ FILE: addons/GDTask/Internal/ArrayUtil.cs ================================================ using System; using System.Collections.Generic; using System.Runtime.CompilerServices; namespace Fractural.Tasks.Internal { internal static class ArrayUtil { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void EnsureCapacity(ref T[] array, int index) { if (array.Length <= index) { EnsureCore(ref array, index); } } // rare case, no inlining. [MethodImpl(MethodImplOptions.NoInlining)] static void EnsureCore(ref T[] array, int index) { var newSize = array.Length * 2; var newArray = new T[(index < newSize) ? newSize : (index * 2)]; Array.Copy(array, 0, newArray, 0, array.Length); array = newArray; } /// /// Optimizing utility to avoid .ToArray() that creates buffer copy(cut to just size). /// public static (T[] array, int length) Materialize(IEnumerable source) { if (source is T[] array) { return (array, array.Length); } var defaultCount = 4; if (source is ICollection coll) { defaultCount = coll.Count; var buffer = new T[defaultCount]; coll.CopyTo(buffer, 0); return (buffer, defaultCount); } else if (source is IReadOnlyCollection rcoll) { defaultCount = rcoll.Count; } if (defaultCount == 0) { return (Array.Empty(), 0); } { var index = 0; var buffer = new T[defaultCount]; foreach (var item in source) { EnsureCapacity(ref buffer, index); buffer[index++] = item; } return (buffer, index); } } } } ================================================ FILE: addons/GDTask/Internal/ArrayUtil.cs.uid ================================================ uid://crnaoo8cq7ssj ================================================ FILE: addons/GDTask/Internal/ContinuationQueue.cs ================================================ using Godot; using System; using System.Threading; namespace Fractural.Tasks.Internal { internal sealed class ContinuationQueue { const int MaxArrayLength = 0X7FEFFFFF; const int InitialSize = 16; readonly PlayerLoopTiming timing; SpinLock gate = new SpinLock(false); bool dequing = false; int actionListCount = 0; Action[] actionList = new Action[InitialSize]; int waitingListCount = 0; Action[] waitingList = new Action[InitialSize]; public ContinuationQueue(PlayerLoopTiming timing) { this.timing = timing; } public void Enqueue(Action continuation) { bool lockTaken = false; try { gate.Enter(ref lockTaken); if (dequing) { // Ensure Capacity if (waitingList.Length == waitingListCount) { var newLength = waitingListCount * 2; if ((uint)newLength > MaxArrayLength) newLength = MaxArrayLength; var newArray = new Action[newLength]; Array.Copy(waitingList, newArray, waitingListCount); waitingList = newArray; } waitingList[waitingListCount] = continuation; waitingListCount++; } else { // Ensure Capacity if (actionList.Length == actionListCount) { var newLength = actionListCount * 2; if ((uint)newLength > MaxArrayLength) newLength = MaxArrayLength; var newArray = new Action[newLength]; Array.Copy(actionList, newArray, actionListCount); actionList = newArray; } actionList[actionListCount] = continuation; actionListCount++; } } finally { if (lockTaken) gate.Exit(false); } } public int Clear() { var rest = actionListCount + waitingListCount; actionListCount = 0; actionList = new Action[InitialSize]; waitingListCount = 0; waitingList = new Action[InitialSize]; return rest; } // delegate entrypoint. public void Run() { // for debugging, create named stacktrace. #if DEBUG switch (timing) { case PlayerLoopTiming.PhysicsProcess: PhysicsProcess(); break; case PlayerLoopTiming.Process: Process(); break; case PlayerLoopTiming.PausePhysicsProcess: PausePhysicsProcess(); break; case PlayerLoopTiming.PauseProcess: PauseProcess(); break; } #else RunCore(); #endif } void PhysicsProcess() => RunCore(); void Process() => RunCore(); void PausePhysicsProcess() => RunCore(); void PauseProcess() => RunCore(); [System.Diagnostics.DebuggerHidden] void RunCore() { { bool lockTaken = false; try { gate.Enter(ref lockTaken); if (actionListCount == 0) return; dequing = true; } finally { if (lockTaken) gate.Exit(false); } } for (int i = 0; i < actionListCount; i++) { var action = actionList[i]; actionList[i] = null; try { action(); } catch (Exception ex) { GD.PrintErr(ex); } } { bool lockTaken = false; try { gate.Enter(ref lockTaken); dequing = false; var swapTempActionList = actionList; actionListCount = waitingListCount; actionList = waitingList; waitingListCount = 0; waitingList = swapTempActionList; } finally { if (lockTaken) gate.Exit(false); } } } } } ================================================ FILE: addons/GDTask/Internal/ContinuationQueue.cs.uid ================================================ uid://3dipskse2ivi ================================================ FILE: addons/GDTask/Internal/DiagnosticsExtensions.cs ================================================ using Godot; using System; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Security; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; namespace Fractural.Tasks.Internal { internal static class DiagnosticsExtensions { static bool displayFilenames = true; static readonly Regex typeBeautifyRegex = new Regex("`.+$", RegexOptions.Compiled); static readonly Dictionary builtInTypeNames = new Dictionary { { typeof(void), "void" }, { typeof(bool), "bool" }, { typeof(byte), "byte" }, { typeof(char), "char" }, { typeof(decimal), "decimal" }, { typeof(double), "double" }, { typeof(float), "float" }, { typeof(int), "int" }, { typeof(long), "long" }, { typeof(object), "object" }, { typeof(sbyte), "sbyte" }, { typeof(short), "short" }, { typeof(string), "string" }, { typeof(uint), "uint" }, { typeof(ulong), "ulong" }, { typeof(ushort), "ushort" }, { typeof(Task), "Task" }, { typeof(GDTask), "GDTask" }, { typeof(GDTaskVoid), "GDTaskVoid" } }; [RequiresUnreferencedCode("Calls System.Diagnostics.StackFrame.GetMethod()")] public static string CleanupAsyncStackTrace(this StackTrace stackTrace) { if (stackTrace == null) return ""; var sb = new StringBuilder(); for (int i = 0; i < stackTrace.FrameCount; i++) { var sf = stackTrace.GetFrame(i); var mb = sf.GetMethod(); if (IgnoreLine(mb)) continue; if (IsAsync(mb)) { sb.Append("async "); TryResolveStateMachineMethod(ref mb, out var decType); } // return type if (mb is MethodInfo mi) { sb.Append(BeautifyType(mi.ReturnType, false)); sb.Append(" "); } // method name sb.Append(BeautifyType(mb.DeclaringType, false)); if (!mb.IsConstructor) { sb.Append("."); } sb.Append(mb.Name); if (mb.IsGenericMethod) { sb.Append("<"); foreach (var item in mb.GetGenericArguments()) { sb.Append(BeautifyType(item, true)); } sb.Append(">"); } // parameter sb.Append("("); sb.Append(string.Join(", ", mb.GetParameters().Select(p => BeautifyType(p.ParameterType, true) + " " + p.Name))); sb.Append(")"); // file name if (displayFilenames && (sf.GetILOffset() != -1)) { String fileName = null; try { fileName = sf.GetFileName(); } catch (NotSupportedException) { displayFilenames = false; } catch (SecurityException) { displayFilenames = false; } if (fileName != null) { sb.Append(' '); sb.AppendFormat(CultureInfo.InvariantCulture, "(at {0})", AppendHyperLink(fileName, sf.GetFileLineNumber().ToString())); } } sb.AppendLine(); } return sb.ToString(); } static bool IsAsync(MethodBase methodInfo) { var declareType = methodInfo.DeclaringType; return typeof(IAsyncStateMachine).IsAssignableFrom(declareType); } // code from Ben.Demystifier/EnhancedStackTrace.Frame.cs [RequiresUnreferencedCode("Calls System.Type.GetMethods()")] static bool TryResolveStateMachineMethod(ref MethodBase method, out Type declaringType) { declaringType = method.DeclaringType; var parentType = declaringType.DeclaringType; if (parentType == null) { return false; } var methods = parentType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly); if (methods == null) { return false; } foreach (var candidateMethod in methods) { var attributes = candidateMethod.GetCustomAttributes(false); if (attributes == null) { continue; } foreach (var asma in attributes) { if (asma.StateMachineType == declaringType) { method = candidateMethod; declaringType = candidateMethod.DeclaringType; // Mark the iterator as changed; so it gets the + annotation of the original method // async statemachines resolve directly to their builder methods so aren't marked as changed return asma is IteratorStateMachineAttribute; } } } return false; } static string BeautifyType(Type t, bool shortName) { if (builtInTypeNames.TryGetValue(t, out var builtin)) { return builtin; } if (t.IsGenericParameter) return t.Name; if (t.IsArray) return BeautifyType(t.GetElementType(), shortName) + "[]"; if (t.FullName?.StartsWith("System.ValueTuple") ?? false) { return "(" + string.Join(", ", t.GetGenericArguments().Select(x => BeautifyType(x, true))) + ")"; } if (!t.IsGenericType) return shortName ? t.Name : t.FullName.Replace("GDTask.Triggers.", "").Replace("GDTask.Internal.", "").Replace("GDTask.", "") ?? t.Name; var innerFormat = string.Join(", ", t.GetGenericArguments().Select(x => BeautifyType(x, true))); var genericType = t.GetGenericTypeDefinition().FullName; if (genericType == "System.Threading.Tasks.Task`1") { genericType = "Task"; } return typeBeautifyRegex.Replace(genericType, "").Replace("GDTask.Triggers.", "").Replace("GDTask.Internal.", "").Replace("GDTask.", "") + "<" + innerFormat + ">"; } static bool IgnoreLine(MethodBase methodInfo) { var declareType = methodInfo.DeclaringType.FullName; if (declareType == "System.Threading.ExecutionContext") { return true; } else if (declareType.StartsWith("System.Runtime.CompilerServices")) { return true; } else if (declareType.StartsWith("GDTask.CompilerServices")) { return true; } else if (declareType == "System.Threading.Tasks.AwaitTaskContinuation") { return true; } else if (declareType.StartsWith("System.Threading.Tasks.Task")) { return true; } else if (declareType.StartsWith("GDTask.GDTaskCompletionSourceCore")) { return true; } else if (declareType.StartsWith("GDTask.AwaiterActions")) { return true; } return false; } static string AppendHyperLink(string path, string line) { var fi = new FileInfo(path); if (fi.Directory == null) { return fi.Name; } else { var fname = fi.FullName.Replace(System.IO.Path.DirectorySeparatorChar, '/').Replace(ProjectSettings.GlobalizePath("res://"), ""); var withAssetsPath = "Assets/" + fname; return "" + withAssetsPath + ":" + line + ""; } } } } ================================================ FILE: addons/GDTask/Internal/DiagnosticsExtensions.cs.uid ================================================ uid://bjkfwkr6c8kvc ================================================ FILE: addons/GDTask/Internal/Error.cs ================================================ using System; using System.Runtime.CompilerServices; namespace Fractural.Tasks.Internal { internal static class Error { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ThrowArgumentNullException(T value, string paramName) where T : class { if (value == null) ThrowArgumentNullExceptionCore(paramName); } [MethodImpl(MethodImplOptions.NoInlining)] static void ThrowArgumentNullExceptionCore(string paramName) { throw new ArgumentNullException(paramName); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Exception ArgumentOutOfRange(string paramName) { return new ArgumentOutOfRangeException(paramName); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Exception NoElements() { return new InvalidOperationException("Source sequence doesn't contain any elements."); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Exception MoreThanOneElement() { return new InvalidOperationException("Source sequence contains more than one element."); } [MethodImpl(MethodImplOptions.NoInlining)] public static void ThrowArgumentException(string message) { throw new ArgumentException(message); } [MethodImpl(MethodImplOptions.NoInlining)] public static void ThrowNotYetCompleted() { throw new InvalidOperationException("Not yet completed."); } [MethodImpl(MethodImplOptions.NoInlining)] public static T ThrowNotYetCompleted() { throw new InvalidOperationException("Not yet completed."); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ThrowWhenContinuationIsAlreadyRegistered(T continuationField) where T : class { if (continuationField != null) ThrowInvalidOperationExceptionCore("continuation is already registered."); } [MethodImpl(MethodImplOptions.NoInlining)] static void ThrowInvalidOperationExceptionCore(string message) { throw new InvalidOperationException(message); } [MethodImpl(MethodImplOptions.NoInlining)] public static void ThrowOperationCanceledException() { throw new OperationCanceledException(); } } } ================================================ FILE: addons/GDTask/Internal/Error.cs.uid ================================================ uid://bjtes4ac5jptq ================================================ FILE: addons/GDTask/Internal/GodotEqualityComparer.cs ================================================ using System; using System.Collections.Generic; using Godot; namespace Fractural.Tasks.Internal { internal static class GodotEqualityComparer { public static readonly IEqualityComparer Vector2 = new Vector2EqualityComparer(); public static readonly IEqualityComparer Vector3 = new Vector3EqualityComparer(); public static readonly IEqualityComparer Color = new ColorEqualityComparer(); public static readonly IEqualityComparer Rect2 = new Rect2EqualityComparer(); public static readonly IEqualityComparer AABB = new AABBEqualityComparer(); public static readonly IEqualityComparer Quaternion = new QuatEqualityComparer(); static readonly RuntimeTypeHandle vector2Type = typeof(Vector2).TypeHandle; static readonly RuntimeTypeHandle vector3Type = typeof(Vector3).TypeHandle; static readonly RuntimeTypeHandle colorType = typeof(Color).TypeHandle; static readonly RuntimeTypeHandle rectType = typeof(Rect2).TypeHandle; static readonly RuntimeTypeHandle AABBType = typeof(Aabb).TypeHandle; static readonly RuntimeTypeHandle quaternionType = typeof(Quaternion).TypeHandle; static class Cache { public static readonly IEqualityComparer Comparer; static Cache() { var comparer = GetDefaultHelper(typeof(T)); if (comparer == null) { Comparer = EqualityComparer.Default; } else { Comparer = (IEqualityComparer)comparer; } } } public static IEqualityComparer GetDefault() { return Cache.Comparer; } static object GetDefaultHelper(Type type) { var t = type.TypeHandle; if (t.Equals(vector2Type)) return (object)GodotEqualityComparer.Vector2; if (t.Equals(vector3Type)) return (object)GodotEqualityComparer.Vector3; if (t.Equals(colorType)) return (object)GodotEqualityComparer.Color; if (t.Equals(rectType)) return (object)GodotEqualityComparer.Rect2; if (t.Equals(AABBType)) return (object)GodotEqualityComparer.AABB; if (t.Equals(quaternionType)) return (object)GodotEqualityComparer.Quaternion; return null; } sealed class Vector2EqualityComparer : IEqualityComparer { public bool Equals(Vector2 self, Vector2 vector) { return self.X.Equals(vector.X) && self.Y.Equals(vector.Y); } public int GetHashCode(Vector2 obj) { return obj.X.GetHashCode() ^ obj.Y.GetHashCode() << 2; } } sealed class Vector3EqualityComparer : IEqualityComparer { public bool Equals(Vector3 self, Vector3 vector) { return self.X.Equals(vector.X) && self.Y.Equals(vector.Y) && self.Z.Equals(vector.Z); } public int GetHashCode(Vector3 obj) { return obj.X.GetHashCode() ^ obj.Y.GetHashCode() << 2 ^ obj.Z.GetHashCode() >> 2; } } sealed class ColorEqualityComparer : IEqualityComparer { public bool Equals(Color self, Color other) { return self.R.Equals(other.R) && self.G.Equals(other.G) && self.B.Equals(other.B) && self.A.Equals(other.A); } public int GetHashCode(Color obj) { return obj.R.GetHashCode() ^ obj.G.GetHashCode() << 2 ^ obj.B.GetHashCode() >> 2 ^ obj.A.GetHashCode() >> 1; } } sealed class Rect2EqualityComparer : IEqualityComparer { public bool Equals(Rect2 self, Rect2 other) { return self.Size.Equals(other.Size) && self.Position.Equals(other.Position); } public int GetHashCode(Rect2 obj) { return obj.Size.GetHashCode() ^ obj.Position.GetHashCode() << 2; } } sealed class AABBEqualityComparer : IEqualityComparer { public bool Equals(Aabb self, Aabb vector) { return self.Position.Equals(vector.Position) && self.Size.Equals(vector.Size); } public int GetHashCode(Aabb obj) { return obj.Position.GetHashCode() ^ obj.Size.GetHashCode() << 2; } } sealed class QuatEqualityComparer : IEqualityComparer { public bool Equals(Quaternion self, Quaternion vector) { return self.X.Equals(vector.X) && self.Y.Equals(vector.Y) && self.Z.Equals(vector.Z) && self.W.Equals(vector.W); } public int GetHashCode(Quaternion obj) { return obj.X.GetHashCode() ^ obj.Y.GetHashCode() << 2 ^ obj.Z.GetHashCode() >> 2 ^ obj.W.GetHashCode() >> 1; } } } } ================================================ FILE: addons/GDTask/Internal/GodotEqualityComparer.cs.uid ================================================ uid://d21iluoiyuuhs ================================================ FILE: addons/GDTask/Internal/MinimumQueue.cs ================================================ using System; using System.Runtime.CompilerServices; namespace Fractural.Tasks.Internal { // optimized version of Standard Queue. internal class MinimumQueue { const int MinimumGrow = 4; const int GrowFactor = 200; T[] array; int head; int tail; int size; public MinimumQueue(int capacity) { if (capacity < 0) throw new ArgumentOutOfRangeException("capacity"); array = new T[capacity]; head = tail = size = 0; } public int Count { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return size; } } public T Peek() { if (size == 0) ThrowForEmptyQueue(); return array[head]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Enqueue(T item) { if (size == array.Length) { Grow(); } array[tail] = item; MoveNext(ref tail); size++; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public T Dequeue() { if (size == 0) ThrowForEmptyQueue(); int head = this.head; T[] array = this.array; T removed = array[head]; array[head] = default(T); MoveNext(ref this.head); size--; return removed; } void Grow() { int newcapacity = (int)((long)array.Length * (long)GrowFactor / 100); if (newcapacity < array.Length + MinimumGrow) { newcapacity = array.Length + MinimumGrow; } SetCapacity(newcapacity); } void SetCapacity(int capacity) { T[] newarray = new T[capacity]; if (size > 0) { if (head < tail) { Array.Copy(array, head, newarray, 0, size); } else { Array.Copy(array, head, newarray, 0, array.Length - head); Array.Copy(array, 0, newarray, array.Length - head, tail); } } array = newarray; head = 0; tail = (size == capacity) ? 0 : size; } [MethodImpl(MethodImplOptions.AggressiveInlining)] void MoveNext(ref int index) { int tmp = index + 1; if (tmp == array.Length) { tmp = 0; } index = tmp; } void ThrowForEmptyQueue() { throw new InvalidOperationException("EmptyQueue"); } } } ================================================ FILE: addons/GDTask/Internal/MinimumQueue.cs.uid ================================================ uid://rnqnl3ljpcwf ================================================ FILE: addons/GDTask/Internal/PlayerLoopRunner.cs ================================================  using Godot; using System; namespace Fractural.Tasks.Internal { internal sealed class PlayerLoopRunner { const int InitialSize = 16; readonly PlayerLoopTiming timing; readonly object runningAndQueueLock = new object(); readonly object arrayLock = new object(); readonly Action unhandledExceptionCallback; int tail = 0; bool running = false; IPlayerLoopItem[] loopItems = new IPlayerLoopItem[InitialSize]; MinimumQueue waitQueue = new MinimumQueue(InitialSize); public PlayerLoopRunner(PlayerLoopTiming timing) { this.unhandledExceptionCallback = ex => GD.PrintErr(ex); this.timing = timing; } public void AddAction(IPlayerLoopItem item) { lock (runningAndQueueLock) { if (running) { waitQueue.Enqueue(item); return; } } lock (arrayLock) { // Ensure Capacity if (loopItems.Length == tail) { Array.Resize(ref loopItems, checked(tail * 2)); } loopItems[tail++] = item; } } public int Clear() { lock (arrayLock) { var rest = 0; for (var index = 0; index < loopItems.Length; index++) { if (loopItems[index] != null) { rest++; } loopItems[index] = null; } tail = 0; return rest; } } // delegate entrypoint. public void Run() { // for debugging, create named stacktrace. #if DEBUG switch (timing) { case PlayerLoopTiming.PhysicsProcess: PhysicsProcess(); break; case PlayerLoopTiming.Process: Process(); break; case PlayerLoopTiming.PausePhysicsProcess: PausePhysicsProcess(); break; case PlayerLoopTiming.PauseProcess: PauseProcess(); break; } #else RunCore(); #endif } void PhysicsProcess() => RunCore(); void Process() => RunCore(); void PausePhysicsProcess() => RunCore(); void PauseProcess() => RunCore(); [System.Diagnostics.DebuggerHidden] void RunCore() { lock (runningAndQueueLock) { running = true; } lock (arrayLock) { var j = tail - 1; for (int i = 0; i < loopItems.Length; i++) { var action = loopItems[i]; if (action != null) { try { if (!action.MoveNext()) { loopItems[i] = null; } else { continue; // next i } } catch (Exception ex) { loopItems[i] = null; try { unhandledExceptionCallback(ex); } catch { } } } // find null, loop from tail while (i < j) { var fromTail = loopItems[j]; if (fromTail != null) { try { if (!fromTail.MoveNext()) { loopItems[j] = null; j--; continue; // next j } else { // swap loopItems[i] = fromTail; loopItems[j] = null; j--; goto NEXT_LOOP; // next i } } catch (Exception ex) { loopItems[j] = null; j--; try { unhandledExceptionCallback(ex); } catch { } continue; // next j } } else { j--; } } tail = i; // loop end break; // LOOP END NEXT_LOOP: continue; } lock (runningAndQueueLock) { running = false; while (waitQueue.Count != 0) { if (loopItems.Length == tail) { Array.Resize(ref loopItems, checked(tail * 2)); } loopItems[tail++] = waitQueue.Dequeue(); } } } } } } ================================================ FILE: addons/GDTask/Internal/PlayerLoopRunner.cs.uid ================================================ uid://bdt7g64ag4g80 ================================================ FILE: addons/GDTask/Internal/PooledDelegate.cs ================================================ using System; using System.Runtime.CompilerServices; namespace Fractural.Tasks.Internal { internal sealed class PooledDelegate : ITaskPoolNode> { static TaskPool> pool; PooledDelegate nextNode; public ref PooledDelegate NextNode => ref nextNode; static PooledDelegate() { TaskPool.RegisterSizeGetter(typeof(PooledDelegate), () => pool.Size); } readonly Action runDelegate; Action continuation; PooledDelegate() { runDelegate = Run; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Action Create(Action continuation) { if (!pool.TryPop(out var item)) { item = new PooledDelegate(); } item.continuation = continuation; return item.runDelegate; } [MethodImpl(MethodImplOptions.AggressiveInlining)] void Run(T _) { var call = continuation; continuation = null; if (call != null) { pool.TryPush(this); call.Invoke(); } } } } ================================================ FILE: addons/GDTask/Internal/PooledDelegate.cs.uid ================================================ uid://3cwmhk0uegmf ================================================ FILE: addons/GDTask/Internal/RuntimeHelpersAbstraction.cs ================================================ using Godot; using System; namespace Fractural.Tasks.Internal { internal static class RuntimeHelpersAbstraction { // If we can use RuntimeHelpers.IsReferenceOrContainsReferences(.NET Core 2.0), use it. public static bool IsWellKnownNoReferenceContainsType() { return WellKnownNoReferenceContainsType.IsWellKnownType; } static bool WellKnownNoReferenceContainsTypeInitialize(Type t) { // The primitive types are Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, IntPtr, UIntPtr, Char, Double, and Single. if (t.IsPrimitive) return true; if (t.IsEnum) return true; if (t == typeof(DateTime)) return true; if (t == typeof(DateTimeOffset)) return true; if (t == typeof(Guid)) return true; if (t == typeof(decimal)) return true; // unwrap nullable if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>)) { return WellKnownNoReferenceContainsTypeInitialize(t.GetGenericArguments()[0]); } // or add other wellknown types(Vector, etc...) here if (t == typeof(Vector2)) return true; if (t == typeof(Vector3)) return true; if (t == typeof(Color)) return true; if (t == typeof(Rect2)) return true; if (t == typeof(Aabb)) return true; if (t == typeof(Quaternion)) return true; return false; } static class WellKnownNoReferenceContainsType { public static readonly bool IsWellKnownType; static WellKnownNoReferenceContainsType() { IsWellKnownType = WellKnownNoReferenceContainsTypeInitialize(typeof(T)); } } } } ================================================ FILE: addons/GDTask/Internal/RuntimeHelpersAbstraction.cs.uid ================================================ uid://bgae6k48sphuc ================================================ FILE: addons/GDTask/Internal/StatePool.cs ================================================ using System; using System.Collections.Concurrent; using System.Runtime.CompilerServices; namespace Fractural.Tasks.Internal { internal static class StateTuple { public static StateTuple Create(T1 item1) { return StatePool.Create(item1); } public static StateTuple Create(T1 item1, T2 item2) { return StatePool.Create(item1, item2); } public static StateTuple Create(T1 item1, T2 item2, T3 item3) { return StatePool.Create(item1, item2, item3); } } internal class StateTuple : IDisposable { public T1 Item1; public void Deconstruct(out T1 item1) { item1 = this.Item1; } public void Dispose() { StatePool.Return(this); } } internal static class StatePool { static readonly ConcurrentQueue> queue = new ConcurrentQueue>(); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static StateTuple Create(T1 item1) { if (queue.TryDequeue(out var value)) { value.Item1 = item1; return value; } return new StateTuple { Item1 = item1 }; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Return(StateTuple tuple) { tuple.Item1 = default; queue.Enqueue(tuple); } } internal class StateTuple : IDisposable { public T1 Item1; public T2 Item2; public void Deconstruct(out T1 item1, out T2 item2) { item1 = this.Item1; item2 = this.Item2; } public void Dispose() { StatePool.Return(this); } } internal static class StatePool { static readonly ConcurrentQueue> queue = new ConcurrentQueue>(); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static StateTuple Create(T1 item1, T2 item2) { if (queue.TryDequeue(out var value)) { value.Item1 = item1; value.Item2 = item2; return value; } return new StateTuple { Item1 = item1, Item2 = item2 }; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Return(StateTuple tuple) { tuple.Item1 = default; tuple.Item2 = default; queue.Enqueue(tuple); } } internal class StateTuple : IDisposable { public T1 Item1; public T2 Item2; public T3 Item3; public void Deconstruct(out T1 item1, out T2 item2, out T3 item3) { item1 = this.Item1; item2 = this.Item2; item3 = this.Item3; } public void Dispose() { StatePool.Return(this); } } internal static class StatePool { static readonly ConcurrentQueue> queue = new ConcurrentQueue>(); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static StateTuple Create(T1 item1, T2 item2, T3 item3) { if (queue.TryDequeue(out var value)) { value.Item1 = item1; value.Item2 = item2; value.Item3 = item3; return value; } return new StateTuple { Item1 = item1, Item2 = item2, Item3 = item3 }; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Return(StateTuple tuple) { tuple.Item1 = default; tuple.Item2 = default; tuple.Item3 = default; queue.Enqueue(tuple); } } } ================================================ FILE: addons/GDTask/Internal/StatePool.cs.uid ================================================ uid://b78klpwf2ukw8 ================================================ FILE: addons/GDTask/Internal/TaskTracker.cs ================================================ using System; using System.Collections.Generic; using System.Diagnostics; using System.Text; using System.Threading; using Fractural.Tasks.Internal; namespace Fractural.Tasks { // public for add user custom. public static class TaskTracker { // TODO: Work on task tracker after getting tasks functioning #if DEBUG static int trackingId = 0; public const string EnableAutoReloadKey = "GDTaskTrackerWindow_EnableAutoReloadKey"; public const string EnableTrackingKey = "GDTaskTrackerWindow_EnableTrackingKey"; public const string EnableStackTraceKey = "GDTaskTrackerWindow_EnableStackTraceKey"; public static class EditorEnableState { static bool enableAutoReload; public static bool EnableAutoReload { get { return enableAutoReload; } set { enableAutoReload = value; //UnityEditor.EditorPrefs.SetBool(EnableAutoReloadKey, value); } } static bool enableTracking; public static bool EnableTracking { get { return enableTracking; } set { enableTracking = value; //UnityEditor.EditorPrefs.SetBool(EnableTrackingKey, value); } } static bool enableStackTrace; public static bool EnableStackTrace { get { return enableStackTrace; } set { enableStackTrace = value; //UnityEditor.EditorPrefs.SetBool(EnableStackTraceKey, value); } } } #endif static List> listPool = new List>(); static readonly WeakDictionary tracking = new WeakDictionary(); [Conditional("DEBUG")] public static void TrackActiveTask(IGDTaskSource task, int skipFrame) { #if DEBUG dirty = true; if (!EditorEnableState.EnableTracking) return; var stackTrace = EditorEnableState.EnableStackTrace ? new StackTrace(skipFrame, true).CleanupAsyncStackTrace() : ""; string typeName; if (EditorEnableState.EnableStackTrace) { var sb = new StringBuilder(); TypeBeautify(task.GetType(), sb); typeName = sb.ToString(); } else { typeName = task.GetType().Name; } tracking.TryAdd(task, (typeName, Interlocked.Increment(ref trackingId), DateTime.UtcNow, stackTrace)); #endif } [Conditional("DEBUG")] public static void RemoveTracking(IGDTaskSource task) { #if DEBUG dirty = true; if (!EditorEnableState.EnableTracking) return; var success = tracking.TryRemove(task); #endif } static bool dirty; public static bool CheckAndResetDirty() { var current = dirty; dirty = false; return current; } /// (trackingId, awaiterType, awaiterStatus, createdTime, stackTrace) public static void ForEachActiveTask(Action action) { lock (listPool) { var count = tracking.ToList(ref listPool, clear: false); try { for (int i = 0; i < count; i++) { action(listPool[i].Value.trackingId, listPool[i].Value.formattedType, listPool[i].Key.UnsafeGetStatus(), listPool[i].Value.addTime, listPool[i].Value.stackTrace); listPool[i] = default; } } catch { listPool.Clear(); throw; } } } static void TypeBeautify(Type type, StringBuilder sb) { if (type.IsNested) { // TypeBeautify(type.DeclaringType, sb); sb.Append(type.DeclaringType.Name.ToString()); sb.Append("."); } if (type.IsGenericType) { var genericsStart = type.Name.IndexOf("`"); if (genericsStart != -1) { sb.Append(type.Name.Substring(0, genericsStart)); } else { sb.Append(type.Name); } sb.Append("<"); var first = true; foreach (var item in type.GetGenericArguments()) { if (!first) { sb.Append(", "); } first = false; TypeBeautify(item, sb); } sb.Append(">"); } else { sb.Append(type.Name); } } } } ================================================ FILE: addons/GDTask/Internal/TaskTracker.cs.uid ================================================ uid://bh1b5djnsdg4a ================================================ FILE: addons/GDTask/Internal/ValueStopwatch.cs ================================================ using System; using System.Diagnostics; namespace Fractural.Tasks.Internal { internal readonly struct ValueStopwatch { static readonly double TimestampToTicks = TimeSpan.TicksPerSecond / (double)Stopwatch.Frequency; readonly long startTimestamp; public static ValueStopwatch StartNew() => new ValueStopwatch(Stopwatch.GetTimestamp()); ValueStopwatch(long startTimestamp) { this.startTimestamp = startTimestamp; } public TimeSpan Elapsed => TimeSpan.FromTicks(this.ElapsedTicks); public bool IsInvalid => startTimestamp == 0; public long ElapsedTicks { get { if (startTimestamp == 0) { throw new InvalidOperationException("Detected invalid initialization(use 'default'), only to create from StartNew()."); } var delta = Stopwatch.GetTimestamp() - startTimestamp; return (long)(delta * TimestampToTicks); } } } } ================================================ FILE: addons/GDTask/Internal/ValueStopwatch.cs.uid ================================================ uid://d00mtr4i7w6iy ================================================ FILE: addons/GDTask/Internal/WeakDictionary.cs ================================================ using System; using System.Collections.Generic; using System.Threading; namespace Fractural.Tasks.Internal { // Add, Remove, Enumerate with sweep. All operations are thread safe(in spinlock). internal class WeakDictionary where TKey : class { Entry[] buckets; int size; SpinLock gate; // mutable struct(not readonly) readonly float loadFactor; readonly IEqualityComparer keyEqualityComparer; public WeakDictionary(int capacity = 4, float loadFactor = 0.75f, IEqualityComparer keyComparer = null) { var tableSize = CalculateCapacity(capacity, loadFactor); this.buckets = new Entry[tableSize]; this.loadFactor = loadFactor; this.gate = new SpinLock(false); this.keyEqualityComparer = keyComparer ?? EqualityComparer.Default; } public bool TryAdd(TKey key, TValue value) { bool lockTaken = false; try { gate.Enter(ref lockTaken); return TryAddInternal(key, value); } finally { if (lockTaken) gate.Exit(false); } } public bool TryGetValue(TKey key, out TValue value) { bool lockTaken = false; try { gate.Enter(ref lockTaken); if (TryGetEntry(key, out _, out var entry)) { value = entry.Value; return true; } value = default(TValue); return false; } finally { if (lockTaken) gate.Exit(false); } } public bool TryRemove(TKey key) { bool lockTaken = false; try { gate.Enter(ref lockTaken); if (TryGetEntry(key, out var hashIndex, out var entry)) { Remove(hashIndex, entry); return true; } return false; } finally { if (lockTaken) gate.Exit(false); } } bool TryAddInternal(TKey key, TValue value) { var nextCapacity = CalculateCapacity(size + 1, loadFactor); TRY_ADD_AGAIN: if (buckets.Length < nextCapacity) { // rehash var nextBucket = new Entry[nextCapacity]; for (int i = 0; i < buckets.Length; i++) { var e = buckets[i]; while (e != null) { AddToBuckets(nextBucket, key, e.Value, e.Hash); e = e.Next; } } buckets = nextBucket; goto TRY_ADD_AGAIN; } else { // add entry var successAdd = AddToBuckets(buckets, key, value, keyEqualityComparer.GetHashCode(key)); if (successAdd) size++; return successAdd; } } bool AddToBuckets(Entry[] targetBuckets, TKey newKey, TValue value, int keyHash) { var h = keyHash; var hashIndex = h & (targetBuckets.Length - 1); TRY_ADD_AGAIN: if (targetBuckets[hashIndex] == null) { targetBuckets[hashIndex] = new Entry { Key = new WeakReference(newKey, false), Value = value, Hash = h }; return true; } else { // add to last. var entry = targetBuckets[hashIndex]; while (entry != null) { if (entry.Key.TryGetTarget(out var target)) { if (keyEqualityComparer.Equals(newKey, target)) { return false; // duplicate } } else { Remove(hashIndex, entry); if (targetBuckets[hashIndex] == null) goto TRY_ADD_AGAIN; // add new entry } if (entry.Next != null) { entry = entry.Next; } else { // found last entry.Next = new Entry { Key = new WeakReference(newKey, false), Value = value, Hash = h }; entry.Next.Prev = entry; } } return false; } } bool TryGetEntry(TKey key, out int hashIndex, out Entry entry) { var table = buckets; var hash = keyEqualityComparer.GetHashCode(key); hashIndex = hash & table.Length - 1; entry = table[hashIndex]; while (entry != null) { if (entry.Key.TryGetTarget(out var target)) { if (keyEqualityComparer.Equals(key, target)) { return true; } } else { // sweap Remove(hashIndex, entry); } entry = entry.Next; } return false; } void Remove(int hashIndex, Entry entry) { if (entry.Prev == null && entry.Next == null) { buckets[hashIndex] = null; } else { if (entry.Prev == null) { buckets[hashIndex] = entry.Next; } if (entry.Prev != null) { entry.Prev.Next = entry.Next; } if (entry.Next != null) { entry.Next.Prev = entry.Prev; } } size--; } public List> ToList() { var list = new List>(size); ToList(ref list, false); return list; } // avoid allocate everytime. public int ToList(ref List> list, bool clear = true) { if (clear) { list.Clear(); } var listIndex = 0; bool lockTaken = false; try { for (int i = 0; i < buckets.Length; i++) { var entry = buckets[i]; while (entry != null) { if (entry.Key.TryGetTarget(out var target)) { var item = new KeyValuePair(target, entry.Value); if (listIndex < list.Count) { list[listIndex++] = item; } else { list.Add(item); listIndex++; } } else { // sweap Remove(i, entry); } entry = entry.Next; } } } finally { if (lockTaken) gate.Exit(false); } return listIndex; } static int CalculateCapacity(int collectionSize, float loadFactor) { var size = (int)(((float)collectionSize) / loadFactor); size--; size |= size >> 1; size |= size >> 2; size |= size >> 4; size |= size >> 8; size |= size >> 16; size += 1; if (size < 8) { size = 8; } return size; } class Entry { public WeakReference Key; public TValue Value; public int Hash; public Entry Prev; public Entry Next; // debug only public override string ToString() { if (Key.TryGetTarget(out var target)) { return target + "(" + Count() + ")"; } else { return "(Dead)"; } } int Count() { var count = 1; var n = this; while (n.Next != null) { count++; n = n.Next; } return count; } } } } ================================================ FILE: addons/GDTask/Internal/WeakDictionary.cs.uid ================================================ uid://lxeiwcolu8kh ================================================ FILE: addons/GDTask/MoveNextSource.cs ================================================ using System; namespace Fractural.Tasks { public abstract class MoveNextSource : IGDTaskSource { protected GDTaskCompletionSourceCore completionSource; public bool GetResult(short token) { return completionSource.GetResult(token); } public GDTaskStatus GetStatus(short token) { return completionSource.GetStatus(token); } public void OnCompleted(Action continuation, object state, short token) { completionSource.OnCompleted(continuation, state, token); } public GDTaskStatus UnsafeGetStatus() { return completionSource.UnsafeGetStatus(); } void IGDTaskSource.GetResult(short token) { completionSource.GetResult(token); } protected bool TryGetResult(GDTask.Awaiter awaiter, out T result) { try { result = awaiter.GetResult(); return true; } catch (Exception ex) { completionSource.TrySetException(ex); result = default; return false; } } protected bool TryGetResult(GDTask.Awaiter awaiter) { try { awaiter.GetResult(); return true; } catch (Exception ex) { completionSource.TrySetException(ex); return false; } } } } ================================================ FILE: addons/GDTask/MoveNextSource.cs.uid ================================================ uid://cgp3ccsb34h84 ================================================ FILE: addons/GDTask/PlayerLoopTimer.cs ================================================ using System.Threading; using System; using Fractural.Tasks.Internal; using Godot; namespace Fractural.Tasks { public abstract class PlayerLoopTimer : IDisposable, IPlayerLoopItem { readonly CancellationToken cancellationToken; readonly Action timerCallback; readonly object state; readonly PlayerLoopTiming playerLoopTiming; readonly bool periodic; bool isRunning; bool tryStop; bool isDisposed; protected PlayerLoopTimer(bool periodic, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action timerCallback, object state) { this.periodic = periodic; this.playerLoopTiming = playerLoopTiming; this.cancellationToken = cancellationToken; this.timerCallback = timerCallback; this.state = state; } public static PlayerLoopTimer Create(TimeSpan interval, bool periodic, DelayType delayType, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action timerCallback, object state) { #if DEBUG // force use Realtime. if (GDTaskPlayerLoopAutoload.IsMainThread && Engine.IsEditorHint()) { delayType = DelayType.Realtime; } #endif switch (delayType) { case DelayType.Realtime: return new RealtimePlayerLoopTimer(interval, periodic, playerLoopTiming, cancellationToken, timerCallback, state); case DelayType.DeltaTime: default: return new DeltaTimePlayerLoopTimer(interval, periodic, playerLoopTiming, cancellationToken, timerCallback, state); } } public static PlayerLoopTimer StartNew(TimeSpan interval, bool periodic, DelayType delayType, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action timerCallback, object state) { var timer = Create(interval, periodic, delayType, playerLoopTiming, cancellationToken, timerCallback, state); timer.Restart(); return timer; } /// /// Restart(Reset and Start) timer. /// public void Restart() { if (isDisposed) throw new ObjectDisposedException(null); ResetCore(null); // init state if (!isRunning) { isRunning = true; GDTaskPlayerLoopAutoload.AddAction(playerLoopTiming, this); } tryStop = false; } /// /// Restart(Reset and Start) and change interval. /// public void Restart(TimeSpan interval) { if (isDisposed) throw new ObjectDisposedException(null); ResetCore(interval); // init state if (!isRunning) { isRunning = true; GDTaskPlayerLoopAutoload.AddAction(playerLoopTiming, this); } tryStop = false; } /// /// Stop timer. /// public void Stop() { tryStop = true; } protected abstract void ResetCore(TimeSpan? newInterval); public void Dispose() { isDisposed = true; } bool IPlayerLoopItem.MoveNext() { if (isDisposed) { isRunning = false; return false; } if (tryStop) { isRunning = false; return false; } if (cancellationToken.IsCancellationRequested) { isRunning = false; return false; } if (!MoveNextCore()) { timerCallback(state); if (periodic) { ResetCore(null); return true; } else { isRunning = false; return false; } } return true; } protected abstract bool MoveNextCore(); } sealed class DeltaTimePlayerLoopTimer : PlayerLoopTimer { bool isMainThread; ulong initialFrame; double elapsed; double interval; public DeltaTimePlayerLoopTimer(TimeSpan interval, bool periodic, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action timerCallback, object state) : base(periodic, playerLoopTiming, cancellationToken, timerCallback, state) { ResetCore(interval); } protected override bool MoveNextCore() { if (elapsed == 0.0) { if (isMainThread && initialFrame == Engine.GetProcessFrames()) { return true; } } elapsed += GDTaskPlayerLoopAutoload.Global.DeltaTime; if (elapsed >= interval) { return false; } return true; } protected override void ResetCore(TimeSpan? interval) { this.elapsed = 0.0; this.isMainThread = GDTaskPlayerLoopAutoload.IsMainThread; if (this.isMainThread) this.initialFrame = Engine.GetProcessFrames(); if (interval != null) { this.interval = (float)interval.Value.TotalSeconds; } } } sealed class RealtimePlayerLoopTimer : PlayerLoopTimer { ValueStopwatch stopwatch; long intervalTicks; public RealtimePlayerLoopTimer(TimeSpan interval, bool periodic, PlayerLoopTiming playerLoopTiming, CancellationToken cancellationToken, Action timerCallback, object state) : base(periodic, playerLoopTiming, cancellationToken, timerCallback, state) { ResetCore(interval); } protected override bool MoveNextCore() { if (stopwatch.ElapsedTicks >= intervalTicks) { return false; } return true; } protected override void ResetCore(TimeSpan? interval) { this.stopwatch = ValueStopwatch.StartNew(); if (interval != null) { this.intervalTicks = interval.Value.Ticks; } } } } ================================================ FILE: addons/GDTask/PlayerLoopTimer.cs.uid ================================================ uid://b4eesv08kira4 ================================================ FILE: addons/GDTask/Progress.cs ================================================ using System; using System.Collections.Generic; using Fractural.Tasks.Internal; namespace Fractural.Tasks { /// /// Lightweight IProgress[T] factory. /// public static class Progress { public static IProgress Create(Action handler) { if (handler == null) return NullProgress.Instance; return new AnonymousProgress(handler); } public static IProgress CreateOnlyValueChanged(Action handler, IEqualityComparer comparer = null) { if (handler == null) return NullProgress.Instance; return new OnlyValueChangedProgress(handler, comparer ?? GodotEqualityComparer.GetDefault()); } sealed class NullProgress : IProgress { public static readonly IProgress Instance = new NullProgress(); NullProgress() { } public void Report(T value) { } } sealed class AnonymousProgress : IProgress { readonly Action action; public AnonymousProgress(Action action) { this.action = action; } public void Report(T value) { action(value); } } sealed class OnlyValueChangedProgress : IProgress { readonly Action action; readonly IEqualityComparer comparer; bool isFirstCall; T latestValue; public OnlyValueChangedProgress(Action action, IEqualityComparer comparer) { this.action = action; this.comparer = comparer; this.isFirstCall = true; } public void Report(T value) { if (isFirstCall) { isFirstCall = false; } else if (comparer.Equals(value, latestValue)) { return; } latestValue = value; action(value); } } } } ================================================ FILE: addons/GDTask/Progress.cs.uid ================================================ uid://bfx26j01offgd ================================================ FILE: addons/GDTask/TaskPool.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Fractural.Tasks { // Taken from GDTask library // Holds static data about all task pools. Right now this is just the size of each pool. public static class TaskPool { internal static int MaxPoolSize; // Avoid to use ConcurrentDictionary for safety of WebGL build. static Dictionary> sizes = new Dictionary>(); static TaskPool() { try { // Pulls from environment, although Godot doesn't support passing env vars, // so maybe delete this? var value = Environment.GetEnvironmentVariable("GDTASK_MAX_POOLSIZE"); if (value != null) { if (int.TryParse(value, out var size)) { MaxPoolSize = size; return; } } } catch { } MaxPoolSize = int.MaxValue; } public static void SetMaxPoolSize(int maxPoolSize) { MaxPoolSize = maxPoolSize; } public static IEnumerable<(Type, int)> GetCacheSizeInfo() { // Making calls thread safe lock (sizes) { foreach (var item in sizes) { yield return (item.Key, item.Value()); } } } public static void RegisterSizeGetter(Type type, Func getSize) { // Making calls thread safe lock (sizes) { sizes[type] = getSize; } } } /// /// Acts as a linked list for TaskSources. /// /// Same type as the class that implements this public interface ITaskPoolNode { // Because interfaces cannot have fields, we store a reference to the field as a getter. // This is so we can directly set and get the field rather than using a property getter/setter, which might have more overhead. // // Disgusting, but efficient. ref T NextNode { get; } } // Mutable struct, don't mark readonly. /// /// Holds a linked list of . Serves as a stack with push and pop operations. /// /// [StructLayout(LayoutKind.Auto)] public struct TaskPool where T : class, ITaskPoolNode { // gate is basically a lock, which controls both popping and pushing to the TaskPool int gate; int size; // Linked list points backwards: // root <-- node2 <-- node3 <-- node4 T root; public int Size => size; // Methods are inlined, meaning the method body replaces all calls of the method, making the // method run fast, but taking up more memory. [MethodImpl(MethodImplOptions.AggressiveInlining)] // Tries to pop. // If another thread is already popping/pushing to this pool, then return false (failure). // Otherwise, pop and return true. public bool TryPop(out T result) { // Interlocked class can perform single operations atomically (thread-safe) // Note that sequentialk Interlocked calls are not guaranteed to be thread-safe. // // CompareExchange: // if gate == 0: // gate = 1; // return 0; // Original value of gate // return gate; // Original value of gate if (Interlocked.CompareExchange(ref gate, 1, 0) == 0) { // If Interlocked.CompareExchange(ref gate, 1, 0) == 0, then the exchange worked! // Basically if the gate was 0, then the pool is free to be used, so we set it to 1 // and start popping. var v = root; if (!(v is null)) { // Our pool is not empty, so we can pop. // Pop from start of linked list O(1) time ref var nextNode = ref v.NextNode; root = nextNode; nextNode = null; size--; result = v; // Volatile writes ensure writes are thread safe? Volatile.Write(ref gate, 0); return true; } // Our pool is empty, so we can't pop. Volatile.Write(ref gate, 0); } result = default; return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] // Tries to push. // If another thread is already popping/pushing to this pool, then return false (failure). // Otherwise, pop and return true. public bool TryPush(T item) { if (Interlocked.CompareExchange(ref gate, 1, 0) == 0) { if (size < TaskPool.MaxPoolSize) { // Push to start of linked list O(1) time item.NextNode = root; root = item; size++; Volatile.Write(ref gate, 0); return true; } else { Volatile.Write(ref gate, 0); } } return false; } } } ================================================ FILE: addons/GDTask/TaskPool.cs.uid ================================================ uid://blbfg64ek0cj4 ================================================ FILE: addons/GDTask/TimeoutController.cs ================================================ using System; using System.Threading; namespace Fractural.Tasks { // CancellationTokenSource itself can not reuse but CancelAfter(Timeout.InfiniteTimeSpan) allows reuse if did not reach timeout. // Similar discussion: // https://github.com/dotnet/runtime/issues/4694 // https://github.com/dotnet/runtime/issues/48492 // This TimeoutController emulate similar implementation, using CancelAfterSlim; to achieve zero allocation timeout. public sealed class TimeoutController : IDisposable { readonly static Action CancelCancellationTokenSourceStateDelegate = new Action(CancelCancellationTokenSourceState); static void CancelCancellationTokenSourceState(object state) { var cts = (CancellationTokenSource)state; cts.Cancel(); } CancellationTokenSource timeoutSource; CancellationTokenSource linkedSource; PlayerLoopTimer timer; bool isDisposed; readonly DelayType delayType; readonly PlayerLoopTiming delayTiming; readonly CancellationTokenSource originalLinkCancellationTokenSource; public TimeoutController(DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming delayTiming = PlayerLoopTiming.Process) { this.timeoutSource = new CancellationTokenSource(); this.originalLinkCancellationTokenSource = null; this.linkedSource = null; this.delayType = delayType; this.delayTiming = delayTiming; } public TimeoutController(CancellationTokenSource linkCancellationTokenSource, DelayType delayType = DelayType.DeltaTime, PlayerLoopTiming delayTiming = PlayerLoopTiming.Process) { this.timeoutSource = new CancellationTokenSource(); this.originalLinkCancellationTokenSource = linkCancellationTokenSource; this.linkedSource = CancellationTokenSource.CreateLinkedTokenSource(timeoutSource.Token, linkCancellationTokenSource.Token); this.delayType = delayType; this.delayTiming = delayTiming; } public CancellationToken Timeout(int millisecondsTimeout) { return Timeout(TimeSpan.FromMilliseconds(millisecondsTimeout)); } public CancellationToken Timeout(TimeSpan timeout) { if (originalLinkCancellationTokenSource != null && originalLinkCancellationTokenSource.IsCancellationRequested) { return originalLinkCancellationTokenSource.Token; } // Timeouted, create new source and timer. if (timeoutSource.IsCancellationRequested) { timeoutSource.Dispose(); timeoutSource = new CancellationTokenSource(); if (linkedSource != null) { this.linkedSource.Cancel(); this.linkedSource.Dispose(); this.linkedSource = CancellationTokenSource.CreateLinkedTokenSource(timeoutSource.Token, originalLinkCancellationTokenSource.Token); } timer?.Dispose(); timer = null; } var useSource = (linkedSource != null) ? linkedSource : timeoutSource; var token = useSource.Token; if (timer == null) { // Timer complete => timeoutSource.Cancel() -> linkedSource will be canceled. // (linked)token is canceled => stop timer timer = PlayerLoopTimer.StartNew(timeout, false, delayType, delayTiming, token, CancelCancellationTokenSourceStateDelegate, timeoutSource); } else { timer.Restart(timeout); } return token; } public bool IsTimeout() { return timeoutSource.IsCancellationRequested; } public void Reset() { timer?.Stop(); } public void Dispose() { if (isDisposed) return; try { // stop timer. timer?.Dispose(); // cancel and dispose. timeoutSource.Cancel(); timeoutSource.Dispose(); if (linkedSource != null) { linkedSource.Cancel(); linkedSource.Dispose(); } } finally { isDisposed = true; } } } } ================================================ FILE: addons/GDTask/TimeoutController.cs.uid ================================================ uid://dyr8ynfd5afi5 ================================================ FILE: addons/GDTask/TriggerEvent.cs ================================================ using System; using System.Threading; using Godot; namespace Fractural.Tasks { public interface ITriggerHandler { void OnNext(T value); void OnError(Exception ex); void OnCompleted(); void OnCanceled(CancellationToken cancellationToken); // set/get from TriggerEvent ITriggerHandler Prev { get; set; } ITriggerHandler Next { get; set; } } // be careful to use, itself is struct. public struct TriggerEvent { ITriggerHandler head; // head.prev is last ITriggerHandler iteratingHead; bool preserveRemoveSelf; ITriggerHandler iteratingNode; void LogError(Exception ex) { GD.PrintErr(ex); } public void SetResult(T value) { if (iteratingNode != null) { throw new InvalidOperationException("Can not trigger itself in iterating."); } var h = head; while (h != null) { iteratingNode = h; try { h.OnNext(value); } catch (Exception ex) { LogError(ex); Remove(h); } if (preserveRemoveSelf) { preserveRemoveSelf = false; iteratingNode = null; var next = h.Next; Remove(h); h = next; } else { h = h.Next; } } iteratingNode = null; if (iteratingHead != null) { Add(iteratingHead); iteratingHead = null; } } public void SetCanceled(CancellationToken cancellationToken) { if (iteratingNode != null) { throw new InvalidOperationException("Can not trigger itself in iterating."); } var h = head; while (h != null) { iteratingNode = h; try { h.OnCanceled(cancellationToken); } catch (Exception ex) { LogError(ex); } preserveRemoveSelf = false; iteratingNode = null; var next = h.Next; Remove(h); h = next; } iteratingNode = null; if (iteratingHead != null) { Add(iteratingHead); iteratingHead = null; } } public void SetCompleted() { if (iteratingNode != null) { throw new InvalidOperationException("Can not trigger itself in iterating."); } var h = head; while (h != null) { iteratingNode = h; try { h.OnCompleted(); } catch (Exception ex) { LogError(ex); } preserveRemoveSelf = false; iteratingNode = null; var next = h.Next; Remove(h); h = next; } iteratingNode = null; if (iteratingHead != null) { Add(iteratingHead); iteratingHead = null; } } public void SetError(Exception exception) { if (iteratingNode != null) { throw new InvalidOperationException("Can not trigger itself in iterating."); } var h = head; while (h != null) { iteratingNode = h; try { h.OnError(exception); } catch (Exception ex) { LogError(ex); } preserveRemoveSelf = false; iteratingNode = null; var next = h.Next; Remove(h); h = next; } iteratingNode = null; if (iteratingHead != null) { Add(iteratingHead); iteratingHead = null; } } public void Add(ITriggerHandler handler) { if (handler == null) throw new ArgumentNullException(nameof(handler)); // zero node. if (head == null) { head = handler; return; } if (iteratingNode != null) { if (iteratingHead == null) { iteratingHead = handler; return; } var last = iteratingHead.Prev; if (last == null) { // single node. iteratingHead.Prev = handler; iteratingHead.Next = handler; handler.Prev = iteratingHead; } else { // multi node iteratingHead.Prev = handler; last.Next = handler; handler.Prev = last; } } else { var last = head.Prev; if (last == null) { // single node. head.Prev = handler; head.Next = handler; handler.Prev = head; } else { // multi node head.Prev = handler; last.Next = handler; handler.Prev = last; } } } public void Remove(ITriggerHandler handler) { if (handler == null) throw new ArgumentNullException(nameof(handler)); if (iteratingNode != null && iteratingNode == handler) { // if remove self, reserve remove self after invoke completed. preserveRemoveSelf = true; } else { var prev = handler.Prev; var next = handler.Next; if (next != null) { next.Prev = prev; } if (handler == head) { head = next; } else if (handler == iteratingHead) { iteratingHead = next; } else { // when handler is head, prev indicate last so don't use it. if (prev != null) { prev.Next = next; } } if (head != null) { if (head.Prev == handler) { if (prev != head) { head.Prev = prev; } else { head.Prev = null; } } } if (iteratingHead != null) { if (iteratingHead.Prev == handler) { if (prev != iteratingHead.Prev) { iteratingHead.Prev = prev; } else { iteratingHead.Prev = null; } } } handler.Prev = null; handler.Next = null; } } } } ================================================ FILE: addons/GDTask/TriggerEvent.cs.uid ================================================ uid://bjmtjd4skljyj ================================================ FILE: addons/GDTask/Triggers/AsyncDestroyTrigger.cs ================================================ using Godot; using System.Threading; namespace Fractural.Tasks.Triggers { public static partial class AsyncTriggerExtensions { public static AsyncDestroyTrigger GetAsyncDestroyTrigger(this Node node) { return node.GetOrAddImmediateChild(); } } public sealed partial class AsyncDestroyTrigger : Node { bool enterTreeCalled = false; bool called = false; CancellationTokenSource cancellationTokenSource; public CancellationToken CancellationToken { get { if (cancellationTokenSource == null) { cancellationTokenSource = new CancellationTokenSource(); } return cancellationTokenSource.Token; } } public override void _EnterTree() { enterTreeCalled = true; } public override void _Notification(int what) { if (what == NotificationPredelete) OnDestroy(); } void OnDestroy() { called = true; cancellationTokenSource?.Cancel(); cancellationTokenSource?.Dispose(); } public GDTask OnDestroyAsync() { if (called) return GDTask.CompletedTask; var tcs = new GDTaskCompletionSource(); // OnDestroy = Called Cancel. CancellationToken.RegisterWithoutCaptureExecutionContext(state => { var tcs2 = (GDTaskCompletionSource)state; tcs2.TrySetResult(); }, tcs); return tcs.Task; } } } ================================================ FILE: addons/GDTask/Triggers/AsyncDestroyTrigger.cs.uid ================================================ uid://bpi1wdhu3nmr0 ================================================ FILE: addons/GDTask/Triggers/AsyncEnterTreeTrigger.cs ================================================ using Godot; namespace Fractural.Tasks.Triggers { public static partial class AsyncTriggerExtensions { public static AsyncEnterTreeTrigger GetAsyncEnterTreeTrigger(this Node node) { return node.GetOrAddImmediateChild(); } } public sealed partial class AsyncEnterTreeTrigger : AsyncTriggerBase { public override void _EnterTree() { base._EnterTree(); RaiseEvent(AsyncUnit.Default); } public GDTask EnterTreeAsync() { if (calledEnterTree) return GDTask.CompletedTask; return ((IAsyncOneShotTrigger)new AsyncTriggerHandler(this, true)).OneShotAsync(); } } } ================================================ FILE: addons/GDTask/Triggers/AsyncEnterTreeTrigger.cs.uid ================================================ uid://djb4yph4o81j0 ================================================ FILE: addons/GDTask/Triggers/AsyncReadyTrigger.cs ================================================ using Godot; namespace Fractural.Tasks.Triggers { public static partial class AsyncTriggerExtensions { public static AsyncReadyTrigger GetAsyncReadyTrigger(this Node node) { return node.GetOrAddImmediateChild(); } } public sealed partial class AsyncReadyTrigger : AsyncTriggerBase { bool called; public override void _Ready() { base._Ready(); called = true; RaiseEvent(AsyncUnit.Default); } public GDTask ReadyAsync() { if (called) return GDTask.CompletedTask; return ((IAsyncOneShotTrigger)new AsyncTriggerHandler(this, true)).OneShotAsync(); } } } ================================================ FILE: addons/GDTask/Triggers/AsyncReadyTrigger.cs.uid ================================================ uid://dmmi2y2xgqpqx ================================================ FILE: addons/GDTask/Triggers/AsyncTriggerBase.cs ================================================ using Godot; using System; using System.Threading; namespace Fractural.Tasks.Triggers { public abstract partial class AsyncTriggerBase : Node { TriggerEvent triggerEvent; internal protected bool calledEnterTree; internal protected bool calledDestroy; public override void _EnterTree() { calledEnterTree = true; } public override void _Notification(int what) { if (what == NotificationPredelete) OnDestroy(); } void OnDestroy() { if (calledDestroy) return; calledDestroy = true; triggerEvent.SetCompleted(); } internal void AddHandler(ITriggerHandler handler) { triggerEvent.Add(handler); } internal void RemoveHandler(ITriggerHandler handler) { triggerEvent.Remove(handler); } protected void RaiseEvent(T value) { triggerEvent.SetResult(value); } } public interface IAsyncOneShotTrigger { GDTask OneShotAsync(); } public partial class AsyncTriggerHandler : IAsyncOneShotTrigger { GDTask IAsyncOneShotTrigger.OneShotAsync() { core.Reset(); return new GDTask((IGDTaskSource)this, core.Version); } } public sealed partial class AsyncTriggerHandler : IGDTaskSource, ITriggerHandler, IDisposable { static Action cancellationCallback = CancellationCallback; readonly AsyncTriggerBase trigger; CancellationToken cancellationToken; CancellationTokenRegistration registration; bool isDisposed; bool callOnce; GDTaskCompletionSourceCore core; internal CancellationToken CancellationToken => cancellationToken; ITriggerHandler ITriggerHandler.Prev { get; set; } ITriggerHandler ITriggerHandler.Next { get; set; } internal AsyncTriggerHandler(AsyncTriggerBase trigger, bool callOnce) { if (cancellationToken.IsCancellationRequested) { isDisposed = true; return; } this.trigger = trigger; this.cancellationToken = default; this.registration = default; this.callOnce = callOnce; trigger.AddHandler(this); TaskTracker.TrackActiveTask(this, 3); } internal AsyncTriggerHandler(AsyncTriggerBase trigger, CancellationToken cancellationToken, bool callOnce) { if (cancellationToken.IsCancellationRequested) { isDisposed = true; return; } this.trigger = trigger; this.cancellationToken = cancellationToken; this.callOnce = callOnce; trigger.AddHandler(this); if (cancellationToken.CanBeCanceled) { registration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, this); } TaskTracker.TrackActiveTask(this, 3); } static void CancellationCallback(object state) { var self = (AsyncTriggerHandler)state; self.Dispose(); self.core.TrySetCanceled(self.cancellationToken); } public void Dispose() { if (!isDisposed) { isDisposed = true; TaskTracker.RemoveTracking(this); registration.Dispose(); trigger.RemoveHandler(this); } } T IGDTaskSource.GetResult(short token) { try { return core.GetResult(token); } finally { if (callOnce) { Dispose(); } } } void ITriggerHandler.OnNext(T value) { core.TrySetResult(value); } void ITriggerHandler.OnCanceled(CancellationToken cancellationToken) { core.TrySetCanceled(cancellationToken); } void ITriggerHandler.OnCompleted() { core.TrySetCanceled(CancellationToken.None); } void ITriggerHandler.OnError(Exception ex) { core.TrySetException(ex); } void IGDTaskSource.GetResult(short token) { ((IGDTaskSource)this).GetResult(token); } GDTaskStatus IGDTaskSource.GetStatus(short token) { return core.GetStatus(token); } GDTaskStatus IGDTaskSource.UnsafeGetStatus() { return core.UnsafeGetStatus(); } void IGDTaskSource.OnCompleted(Action continuation, object state, short token) { core.OnCompleted(continuation, state, token); } } } ================================================ FILE: addons/GDTask/Triggers/AsyncTriggerBase.cs.uid ================================================ uid://bml87u46mci66 ================================================ FILE: addons/GDTask/Triggers/AsyncTriggerExtensions.cs ================================================ using Fractural.Tasks.Triggers; using Godot; using System; using System.Threading; namespace Fractural.Tasks { public static class GDTaskCancellationExtensions { /// This CancellationToken is canceled when the Node will be destroyed. public static CancellationToken GetCancellationTokenOnDestroy(this Node node) { return node.GetAsyncDestroyTrigger().CancellationToken; } } } namespace Fractural.Tasks.Triggers { public static partial class AsyncTriggerExtensions { // Special for single operation. public static T GetImmediateChild(this Node node, bool includeRoot = true) { if (node == null) throw new ArgumentNullException(nameof(node)); if (includeRoot && node is T castedRoot) return castedRoot; else { foreach (Node child in node.GetChildren()) if (child is T castedChild) return castedChild; } return default(T); } public static T AddImmediateChild(this Node node) where T : Node, new() { T child = new T(); node.AddChild(child); return child; } public static T GetOrAddImmediateChild(this Node node) where T : Node, new() { T child = GetImmediateChild(node); if (child == null) child = AddImmediateChild(node); return child; } /// This function is called when the Node will be destroyed. public static GDTask OnDestroyAsync(this Node node) { return node.GetAsyncDestroyTrigger().OnDestroyAsync(); } public static GDTask ReadyAsync(this Node node) { return node.GetAsyncReadyTrigger().ReadyAsync(); } public static GDTask EnterTreeAsync(this Node node) { return node.GetAsyncEnterTreeTrigger().EnterTreeAsync(); } } } ================================================ FILE: addons/GDTask/Triggers/AsyncTriggerExtensions.cs.uid ================================================ uid://b5kf26jr530q0 ================================================ FILE: addons/GDTask/Triggers/NodeMessagesTriggers.cs ================================================ using System.Threading; using Godot; namespace Fractural.Tasks.Triggers { #region PhysicsProcess public interface IAsyncPhysicsProcessHandler { GDTask PhysicsProcessAsync(); } public partial class AsyncTriggerHandler : IAsyncPhysicsProcessHandler { GDTask IAsyncPhysicsProcessHandler.PhysicsProcessAsync() { core.Reset(); return new GDTask((IGDTaskSource)(object)this, core.Version); } } public static partial class AsyncTriggerExtensions { public static AsyncPhysicsProcessTrigger GetAsyncPhysicsProcessTrigger(this Node node) { return node.GetOrAddImmediateChild(); } } public sealed partial class AsyncPhysicsProcessTrigger : AsyncTriggerBase { public override void _PhysicsProcess(double delta) { RaiseEvent(AsyncUnit.Default); } public IAsyncPhysicsProcessHandler GetPhysicsProcessAsyncHandler() { return new AsyncTriggerHandler(this, false); } public IAsyncPhysicsProcessHandler GetPhysicsProcessAsyncHandler(CancellationToken cancellationToken) { return new AsyncTriggerHandler(this, cancellationToken, false); } public GDTask PhysicsProcessAsync() { return ((IAsyncPhysicsProcessHandler)new AsyncTriggerHandler(this, true)).PhysicsProcessAsync(); } public GDTask PhysicsProcessAsync(CancellationToken cancellationToken) { return ((IAsyncPhysicsProcessHandler)new AsyncTriggerHandler(this, cancellationToken, true)).PhysicsProcessAsync(); } } #endregion #region Process public interface IAsyncProcessHandler { GDTask ProcessAsync(); } public partial class AsyncTriggerHandler : IAsyncProcessHandler { GDTask IAsyncProcessHandler.ProcessAsync() { core.Reset(); return new GDTask((IGDTaskSource)(object)this, core.Version); } } public static partial class AsyncTriggerExtensions { public static AsyncProcessTrigger GetAsyncProcessTrigger(this Node node) { return node.GetOrAddImmediateChild(); } } public sealed partial class AsyncProcessTrigger : AsyncTriggerBase { public override void _Process(double delta) { RaiseEvent(AsyncUnit.Default); } public IAsyncProcessHandler GetProcessAsyncHandler() { return new AsyncTriggerHandler(this, false); } public IAsyncProcessHandler GetProcessAsyncHandler(CancellationToken cancellationToken) { return new AsyncTriggerHandler(this, cancellationToken, false); } public GDTask ProcessAsync() { return ((IAsyncProcessHandler)new AsyncTriggerHandler(this, true)).ProcessAsync(); } public GDTask ProcessAsync(CancellationToken cancellationToken) { return ((IAsyncProcessHandler)new AsyncTriggerHandler(this, cancellationToken, true)).ProcessAsync(); } } #endregion } ================================================ FILE: addons/GDTask/Triggers/NodeMessagesTriggers.cs.uid ================================================ uid://c8yqsh24m88oo ================================================ FILE: bootsplash.png.import ================================================ [remap] importer="texture" type="CompressedTexture2D" uid="uid://xs4tet3rfluv" path="res://.godot/imported/bootsplash.png-30e2c9990faa42442c2d12c3b0f7ed9a.ctex" metadata={ "vram_texture": false } [deps] source_file="res://bootsplash.png" dest_files=["res://.godot/imported/bootsplash.png-30e2c9990faa42442c2d12c3b0f7ed9a.ctex"] [params] compress/mode=0 compress/high_quality=false compress/lossy_quality=0.7 compress/hdr_compression=1 compress/normal_map=0 compress/channel_pack=0 mipmaps/generate=false mipmaps/limit=-1 roughness/mode=0 roughness/src_normal="" process/fix_alpha_border=true process/premult_alpha=false process/normal_map_invert_y=false process/hdr_as_srgb=false process/hdr_clamp_exposure=false process/size_limit=0 detect_3d/compress_to=1 ================================================ FILE: default_env.tres ================================================ [gd_resource type="Environment" load_steps=2 format=3 uid="uid://d1jylo21mpcqw"] [sub_resource type="Sky" id="1"] [resource] background_mode = 2 sky = SubResource("1") ================================================ FILE: icon.import ================================================ [remap] importer="texture" type="StreamTexture" path="res://.import/Godot Icons_GDTask.png-aadd498320b5c6d1f2887ffda1e49a4a.stex" metadata={ "vram_texture": false } [deps] source_file="res://Godot Icons_GDTask.png" dest_files=[ "res://.import/Godot Icons_GDTask.png-aadd498320b5c6d1f2887ffda1e49a4a.stex" ] [params] compress/mode=0 compress/lossy_quality=0.7 compress/hdr_mode=0 compress/bptc_ldr=0 compress/normal_map=0 flags/repeat=0 flags/filter=true flags/mipmaps=false flags/anisotropic=false flags/srgb=2 process/fix_alpha_border=true process/premult_alpha=false process/HDR_as_SRGB=false process/invert_color=false process/normal_map_invert_y=false stream=false size_limit=0 detect_3d=true svg/scale=1.0 ================================================ FILE: icon.png.import ================================================ [remap] importer="texture" type="CompressedTexture2D" uid="uid://cw01ge0bgos8m" path="res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex" metadata={ "vram_texture": false } [deps] source_file="res://icon.png" dest_files=["res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex"] [params] compress/mode=0 compress/high_quality=false compress/lossy_quality=0.7 compress/hdr_compression=1 compress/normal_map=0 compress/channel_pack=0 mipmaps/generate=false mipmaps/limit=-1 roughness/mode=0 roughness/src_normal="" process/fix_alpha_border=true process/premult_alpha=false process/normal_map_invert_y=false process/hdr_as_srgb=false process/hdr_clamp_exposure=false process/size_limit=0 detect_3d/compress_to=1 ================================================ FILE: project.godot ================================================ ; Engine configuration file. ; It's best edited using the editor UI and not directly, ; since the parameters that go here are not all obvious. ; ; Format: ; [section] ; section goes between [] ; param=value ; assign values to parameters config_version=5 [WAT] Test_Directory="res://" Results_Directory="res://" Test_Metadata_Directory="res://" Tags=PackedStringArray() Cache_Tests=true Window_Size=Vector2(1280, 720) Minimize_Window_When_Running_Tests=false Port=6008 Display=8 [application] config/name="GDTask" run/main_scene="res://tests/manual/Test.tscn" config/features=PackedStringArray("4.4", "C#") boot_splash/bg_color=Color(0, 0, 0, 1) boot_splash/image="res://bootsplash.png" config/icon="res://icon.png" [dotnet] project/assembly_name="GDTask" [editor_plugins] enabled=PackedStringArray() [gui] common/drop_mouse_on_gui_input_disabled=true [mono] project/assembly_name="GDTask" [physics] common/enable_pause_aware_picking=true [rendering] environment/defaults/default_environment="res://default_env.tres" ================================================ FILE: tests/manual/Test.cs ================================================ using Fractural.Tasks; using Godot; using System; using System.Threading; namespace Tests.Manual { public partial class Test : Node { [Signal] public delegate void MyEmptySignalEventHandler(); [Signal] public delegate void MyArgSignalEventHandler(int number, bool boolean); [Export] private bool runTestOnReady; [Export] private NodePath spritePath; [Export] private Label pauseLabel; public Sprite2D sprite; public override void _Ready() { sprite = GetNode(spritePath); if (runTestOnReady) Run().Forget(); ProcessMode = ProcessModeEnum.Always; pauseLabel.Text = GetTree().Paused ? "Paused" : "Unpaused"; } public override void _Input(InputEvent @event) { if (@event.IsActionReleased("ui_left")) { Run().Forget(); } else if (@event.IsActionReleased("ui_right")) { RunPause().Forget(); } else if (@event.IsActionReleased("ui_up")) { GetTree().Paused = !GetTree().Paused; pauseLabel.Text = GetTree().Paused ? "Paused" : "Unpaused"; } } private async GDTaskVoid WaitAndEmitMyEmptySignal(TimeSpan delay) { await GDTask.Delay(delay); EmitSignal(nameof(MyEmptySignal)); } private async GDTaskVoid WaitAndEmitMyArgSignal(TimeSpan delay) { await GDTask.Delay(delay); EmitSignal(nameof(MyArgSignal), 10, true); } private async GDTaskVoid WaitAndCancelToken(TimeSpan delay, CancellationTokenSource cts) { await GDTask.Delay(delay); cts.Cancel(); } private async GDTaskVoid Run() { GD.Print("Run: Pre delay"); sprite.Visible = false; await GDTask.Delay(TimeSpan.FromSeconds(3)); sprite.Visible = true; GD.Print("Run: Post delay after 3 seconds"); GD.Print("Run: Await MyEmptySignal"); WaitAndEmitMyEmptySignal(TimeSpan.FromSeconds(1)).Forget(); var signalResult = await GDTask.ToSignal(this, nameof(MyEmptySignal)); GD.Print("Run: Await MyEmptySignal Complete, result: ", Json.Stringify(new Godot.Collections.Array(signalResult))); GD.Print("Run: Await MyArgSignal"); WaitAndEmitMyArgSignal(TimeSpan.FromSeconds(1)).Forget(); signalResult = await GDTask.ToSignal(this, nameof(MyArgSignal)); GD.Print("Run: Await MyArgSignal Complete, result: ", Json.Stringify(new Godot.Collections.Array(signalResult))); var cts = new CancellationTokenSource(); GD.Print("Run: Await Cancellable MyEmptySignal"); WaitAndEmitMyEmptySignal(TimeSpan.FromSeconds(3)).Forget(); WaitAndCancelToken(TimeSpan.FromSeconds(0.5), cts).Forget(); 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(); 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(); GD.Print($"Run: Post got result: {runResult}"); GD.Print("Run: LongTask started"); cts = new CancellationTokenSource(); CancellableReallyLongTask(cts.Token).Forget(); await GDTask.Delay(TimeSpan.FromSeconds(3)); cts.Cancel(); GD.Print("Run: LongTask cancelled"); await GDTask.WaitForEndOfFrame(); GD.Print("Run: WaitForEndOfFrame"); await GDTask.WaitForPhysicsProcess(); GD.Print("Run: WaitForPhysicsProcess"); await GDTask.NextFrame(); GD.Print("Run: NextFrame"); } private async GDTask RunWithResult() { await GDTask.Delay(TimeSpan.FromSeconds(2)); return "Hello"; } private async GDTaskVoid CancellableReallyLongTask(CancellationToken cancellationToken) { int seconds = 10; GD.Print($"Run: Starting long task ({seconds} seconds long)."); for (int i = 0; i < seconds; i++) { GD.Print($"Run: Working on long task for {i} seconds..."); await GDTask.Delay(TimeSpan.FromSeconds(1), cancellationToken: cancellationToken); } GD.Print("Run: Finished long task."); } private async GDTaskVoid RunPause() { GD.Print("RunPause: Pre delay"); sprite.Visible = false; await GDTask.Delay(TimeSpan.FromSeconds(3), PlayerLoopTiming.PauseProcess); sprite.Visible = true; GD.Print("RunPause: Post delay after 3 seconds"); GD.Print("RunPause: Pre RunWithResult"); string result = await RunWithResultPause(); GD.Print($"RunPause: Post got result: {result}"); GD.Print("RunPause: LongTask started"); var cts = new CancellationTokenSource(); CancellableReallyLongTaskPause(cts.Token).Forget(); await GDTask.Delay(TimeSpan.FromSeconds(3), PlayerLoopTiming.PauseProcess); cts.Cancel(); GD.Print("RunPause: LongTask cancelled"); await GDTask.Yield(PlayerLoopTiming.PauseProcess); GD.Print("RunPause: Yield(PlayerLoopTiming.PauseProcess)"); await GDTask.Yield(PlayerLoopTiming.PausePhysicsProcess); GD.Print("RunPause: Yield(PlayerLoopTiming.PausePhysicsProcess)"); await GDTask.NextFrame(PlayerLoopTiming.PauseProcess); GD.Print("RunPause: NextFrame"); } private async GDTask RunWithResultPause() { await GDTask.Delay(TimeSpan.FromSeconds(2), PlayerLoopTiming.PauseProcess); return "Hello"; } private async GDTaskVoid CancellableReallyLongTaskPause(CancellationToken cancellationToken) { int seconds = 10; GD.Print($"RunPause: Starting long task ({seconds} seconds long)."); for (int i = 0; i < seconds; i++) { GD.Print($"RunPause: Working on long task for {i} seconds..."); await GDTask.Delay(TimeSpan.FromSeconds(1), PlayerLoopTiming.PauseProcess, cancellationToken); } GD.Print("RunPause: Finished long task."); } } } ================================================ FILE: tests/manual/Test.cs.uid ================================================ uid://p7nspvioq02b ================================================ FILE: tests/manual/Test.tscn ================================================ [gd_scene load_steps=3 format=3 uid="uid://cfm0u7eao06ff"] [ext_resource type="Script" uid="uid://p7nspvioq02b" path="res://tests/manual/Test.cs" id="1"] [ext_resource type="Texture2D" uid="uid://cw01ge0bgos8m" path="res://icon.png" id="2"] [node name="Test" type="Node" node_paths=PackedStringArray("pauseLabel")] script = ExtResource("1") spritePath = NodePath("Node2D/Sprite2D") pauseLabel = NodePath("UI/Control/PauseLabel") [node name="Node2D" type="Node2D" parent="."] [node name="Sprite2D" type="Sprite2D" parent="Node2D"] texture = ExtResource("2") [node name="Camera2D" type="Camera2D" parent="Node2D"] [node name="UI" type="CanvasLayer" parent="."] [node name="Control" type="Control" parent="UI"] layout_mode = 3 anchors_preset = 15 anchor_right = 1.0 anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 [node name="PauseLabel" type="Label" parent="UI/Control"] layout_mode = 0 offset_left = 18.0 offset_top = 18.0 offset_right = 75.0 offset_bottom = 41.0 text = "Paused"