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
}
}