using Nullframes.Threading.Tasks; using System; using System.Threading; using System.Threading.Tasks; using UnityEngine; namespace Nullframes.Threading { public sealed partial class Dispatcher { #region --- Dispatch: Action --- /// /// Dispatch the execution of an to the main thread. /// Actions are by default executed during the next available
/// Update, FixedUpdate, LateUpdate or TickUpdate cycle.
/// Use /// for more control over the cycle in which the dispatched is executed. ///
/// dispatched action. /// public static void Invoke(Action action) { lock (defaultExecutionQueue) { defaultExecutionQueue.Enqueue(action); } queuedDefault = true; } /// /// Dispatch an that will be executed on the main thread and determine the exact cycle, /// during which the passed action will be executed. /// /// dispatched action. /// The execution cycle during which the passed is executed. /// public static void Invoke(Action action, ExecutionCycle cycle) { switch (cycle) { case ExecutionCycle.Update: lock (updateExecutionQueue) { updateExecutionQueue.Enqueue(action); } queuedUpdate = true; break; case ExecutionCycle.LateUpdate: lock (lateUpdateExecutionQueue) { lateUpdateExecutionQueue.Enqueue(action); } queuedLate = true; break; case ExecutionCycle.FixedUpdate: lock (fixedUpdateExecutionQueue) { fixedUpdateExecutionQueue.Enqueue(action); } queuedFixed = true; break; #if UNITY_EDITOR case ExecutionCycle.EditorUpdate: lock (editorExecutionQueue) { editorExecutionQueue.Enqueue(action); } queuedEditor = true; break; #endif default: lock (defaultExecutionQueue) { defaultExecutionQueue.Enqueue(action); } queuedDefault = true; break; } } #endregion #region --- Dispatch: Action Async --- /// /// Dispatch an that will be executed on the main thread and return a , /// that when awaited on the calling thread, returns after the /// was executed on the main thread. /// /// that will be invoked. /// Task that will complete on the calling thread after the passed action has been executed. /// public static Task InvokeAsync(Action action) { var tcs = new TaskCompletionSource(); Invoke(() => { try { action(); tcs.SetCompleted(); } catch (Exception exception) { if (!tcs.TrySetException(exception)) { Debug.LogException(exception); } } }); return tcs.Task; } /// /// Dispatch an that will be executed on the main thread and return a , /// that when awaited on the calling thread, returns after the /// was executed on the main thread. /// /// that will be invoked. /// The execution cycle during which the will be invoked. /// Task that will complete on the calling thread after the passed action has been executed. /// public static Task InvokeAsync(Action action, ExecutionCycle cycle) { var tcs = new TaskCompletionSource(); Invoke(() => { try { action(); tcs.SetCompleted(); } catch (Exception exception) { if (!tcs.TrySetException(exception)) { Debug.LogException(exception); } } }, cycle); return tcs.Task; } /// /// Dispatch an that will be executed on the main thread and return a , /// that when awaited on the calling thread, returns after the /// was executed on the main thread. /// /// that will be invoked. /// optional cancellation token that can be passed to abort the task prematurely. /// /// exception is thrown if the task is cancelled prematurely. /// Task that will complete on the calling thread after the passed action has been executed. /// public static Task InvokeAsync(Action action, CancellationToken ct, bool throwOnCancellation = true) { if (ct.IsCancellationRequested) { if (throwOnCancellation) { ct.ThrowIfCancellationRequested(); } else { return Task.CompletedTask; } } var tcs = new TaskCompletionSource(); Invoke(() => { try { ct.ThrowIfCancellationRequested(); action(); tcs.SetCompleted(); } catch (OperationCanceledException oce) { if (throwOnCancellation) { tcs.SetException(oce); } else { tcs.SetCompleted(); } } catch (Exception exception) { if (!tcs.TrySetException(exception)) { Debug.LogException(exception); } } }); return tcs.Task; } /// /// Dispatch an that will be executed on the main thread and return a , /// that when awaited on the calling thread, returns after the /// was executed on the main thread. /// /// that will be invoked. /// the execution cycle during which the passed is executed. /// optional cancellation token that can be passed to abort the task prematurely. /// optional parameter that determines if an /// is thrown if the Task is cancelled prematurely. /// exception is thrown if the task is cancelled prematurely. /// Task that will complete on the calling thread after the passed action has been executed. /// public static Task InvokeAsync(Action action, ExecutionCycle cycle, CancellationToken ct, bool throwOnCancellation = true) { var tcs = new TaskCompletionSource(); Invoke(() => { try { ct.ThrowIfCancellationRequested(); action(); tcs.SetCompleted(); } catch (OperationCanceledException oce) { if (throwOnCancellation) { tcs.SetException(oce); } else { tcs.SetCompleted(); } } catch (Exception exception) { if (!tcs.TrySetException(exception)) { Debug.LogException(exception); } } }, cycle); return tcs.Task; } #endregion //-------------------------------------------------------------------------------------------------------------- #region --- Dispatch: Func Async --- /// /// Dispatch a that wil executed on the main thread; and return a , /// that when awaited on the calling thread, returns the result of the passed /// after it was executed on the main thread. /// /// delegate that will be executed on the main thread. /// exception is thrown if the task is cancelled prematurely. /// Task that will complete on the calling thread after the delegate was executed. /// public static Task InvokeAsync(Func func) { var tcs = new TaskCompletionSource(); Invoke(() => { try { var result = func(); tcs.SetResult(result); } catch (Exception exception) { if (!tcs.TrySetException(exception)) { Debug.LogException(exception); } } }); return tcs.Task; } /// /// Dispatch a that wil executed on the main thread; and return a , /// that when awaited on the calling thread, returns the result of the passed /// after it was executed on the main thread. /// /// delegate that will be executed on the main thread. /// The execution cycle during which the passed is executed. /// Task that will complete on the calling thread after the delegate was executed. /// public static Task InvokeAsync(Func func, ExecutionCycle cycle) { var tcs = new TaskCompletionSource(); Invoke(() => { try { var result = func(); tcs.SetResult(result); } catch (Exception exception) { if (!tcs.TrySetException(exception)) { Debug.LogException(exception); } } }, cycle); return tcs.Task; } /// /// Dispatch a that wil executed on the main thread; and return a , /// that when awaited on the calling thread, returns the result of the passed /// after it was executed on the main thread. /// /// delegate that will be executed on the main thread. /// optional cancellation token that can be passed to abort the task prematurely. /// exception is thrown if the task is cancelled prematurely. /// Task that will complete on the calling thread after the delegate was executed. /// public static Task InvokeAsync(Func func, CancellationToken ct) { var tcs = new TaskCompletionSource(); Invoke(() => { try { ct.ThrowIfCancellationRequested(); var result = func(); tcs.SetResult(result); } catch (Exception exception) { if (!tcs.TrySetException(exception)) { Debug.LogException(exception); } } }); return tcs.Task; } /// /// Dispatch a that wil executed on the main thread; and return a , /// that when awaited on the calling thread, returns the result of the passed /// after it was executed on the main thread. /// /// delegate that will be executed on the main thread. /// The execution cycle during which the passed is executed. /// optional cancellation token that can be passed to abort the task prematurely. /// exception is thrown if the task is cancelled prematurely. /// Task that will complete on the calling thread after the delegate was executed. /// public static Task InvokeAsync(Func func, ExecutionCycle cycle, CancellationToken ct) { var tcs = new TaskCompletionSource(); Invoke(() => { try { ct.ThrowIfCancellationRequested(); var result = func(); tcs.SetResult(result); } catch (Exception exception) { if (!tcs.TrySetException(exception)) { Debug.LogException(exception); } } }, cycle); return tcs.Task; } #endregion } }