/// <summary> /// Creates a continuation that executes when the target <see cref="CoroutineTask" /> completes. /// </summary> /// <param name="continuationFunction"> /// An action to run when the <see cref="CoroutineTask" /> completes. When run, the delegate will be /// passed the completed task as an argument. /// </param> /// <param name="state">The parameter of the action.</param> /// <param name="continuationOptions"> /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such /// as <see cref="CoroutineTaskContinuationOptions.OnCanceled">OnCanceled</see> /// , as well as execution options, such as /// <see cref="CoroutineTaskContinuationOptions.OnCompleted">OnCompleted</see>. /// </param> /// <returns>A new continuation <see cref="CoroutineTask" />.</returns> /// <remarks> /// The returned <see cref="CoroutineTask" /> will not be scheduled for execution until the current task has /// completed. /// </remarks> public CoroutineTask <TResult> ContinueWith <TResult>(Func <CoroutineTask, object, TResult> continuationFunction, object state, CoroutineTaskContinuationOptions continuationOptions = CoroutineTaskContinuationOptions.None) { var result = new AsyncResult <TResult>(true); asyncResult.Callbackable().OnCallback(ar => { try { var executable = IsExecutable(ar, continuationOptions); if (!executable) { result.SetCancelled(); return; } TResult value = continuationFunction(this, state); result.SetResult(value); } catch (Exception e) { result.SetException(e); } }); return(new CoroutineTask <TResult>(result)); }
/// <summary> /// Creates a continuation that executes when the target <see cref="CoroutineTask" /> completes. /// </summary> /// <param name="continuationFunction"> /// An action to run when the <see cref="CoroutineTask" /> completes. When run, the delegate will be /// passed the completed task as an argument. /// </param> /// <param name="state">The parameter of the action.</param> /// <param name="continuationOptions"> /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such /// as <see cref="CoroutineTaskContinuationOptions.OnCanceled">OnCanceled</see> /// , as well as execution options, such as /// <see cref="CoroutineTaskContinuationOptions.OnCompleted">OnCompleted</see>. /// </param> /// <returns>A new continuation <see cref="CoroutineTask" />.</returns> /// <remarks> /// The returned <see cref="CoroutineTask" /> will not be scheduled for execution until the current task has /// completed. /// </remarks> public CoroutineTask <TResult> ContinueWith <TResult>( Func <CoroutineTask, object, IPromise <TResult>, IEnumerator> continuationFunction, object state, CoroutineTaskContinuationOptions continuationOptions = CoroutineTaskContinuationOptions.None) { var result = new AsyncResult <TResult>(true); asyncResult.Callbackable().OnCallback(ar => { try { var executable = IsExecutable(ar, continuationOptions); if (!executable) { result.SetCancelled(); return; } Executors.RunOnCoroutine(continuationFunction(this, state, result), result); } catch (Exception e) { result.SetException(e); } }); return(new CoroutineTask <TResult>(result)); }
/// <summary> /// Creates a continuation that executes when the target <see cref="CoroutineTask" /> completes. /// </summary> /// <param name="continuationFunction"> /// An action to run when the <see cref="CoroutineTask" /> completes. When run, the delegate will be /// passed the completed task as an argument. /// </param> /// <param name="continuationOptions"> /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such /// as <see cref="CoroutineTaskContinuationOptions.OnCanceled">OnCanceled</see> /// , as well as execution options, such as /// <see cref="CoroutineTaskContinuationOptions.OnCompleted">OnCompleted</see>. /// </param> /// <returns>A new continuation <see cref="CoroutineTask" />.</returns> /// <remarks> /// The returned <see cref="CoroutineTask" /> will not be scheduled for execution until the current task has /// completed. /// </remarks> public CoroutineTask ContinueWith(Func <CoroutineTask, IEnumerator> continuationFunction, CoroutineTaskContinuationOptions continuationOptions = CoroutineTaskContinuationOptions.None) { AsyncResult result = new AsyncResult(true); asyncResult.Callbackable().OnCallback(ar => { try { var executable = IsExecutable(ar, continuationOptions); if (!executable) { result.SetCancelled(); return; } Executors.RunOnCoroutine(continuationFunction(this), result); } catch (Exception e) { result.SetException(e); } }); return(new CoroutineTask(result)); }
/// <summary> /// Creates a continuation that executes when the target <see cref="CoroutineTask" /> completes. /// </summary> /// <param name="continuationAction"> /// An action to run when the <see cref="CoroutineTask" /> completes. When run, the delegate will be /// passed the completed task as an argument. /// </param> /// <param name="state">The parameter of the action.</param> /// <param name="continuationOptions"> /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such /// as <see cref="CoroutineTaskContinuationOptions.OnCanceled">OnCanceled</see> /// , as well as execution options, such as /// <see cref="CoroutineTaskContinuationOptions.OnCompleted">OnCompleted</see>. /// </param> /// <returns>A new continuation <see cref="CoroutineTask" />.</returns> /// <remarks> /// The returned <see cref="CoroutineTask" /> will not be scheduled for execution until the current task has /// completed. /// </remarks> public CoroutineTask ContinueWith(Action <CoroutineTask, object> continuationAction, object state, CoroutineTaskContinuationOptions continuationOptions = CoroutineTaskContinuationOptions.None) { AsyncResult result = new AsyncResult(true); asyncResult.Callbackable().OnCallback(ar => { try { var executable = IsExecutable(ar, continuationOptions); if (!executable) { result.SetCancelled(); return; } continuationAction(this, state); result.SetResult(); } catch (Exception e) { result.SetException(e); } }); return(new CoroutineTask(result)); }
/// <summary> /// Creates a task that will complete when all of the supplied tasks have completed. /// </summary> /// <param name="tasks">The tasks to wait on for completion.</param> /// <returns>A task that represents the completion of all of the supplied tasks.</returns> /// <remarks> /// <para> /// If any of the supplied tasks completes in a faulted state, the returned task will also complete in a Faulted /// state, /// where its exceptions will contain the aggregation of the set of unwrapped exceptions from each of the supplied /// tasks. /// </para> /// <para> /// If none of the supplied tasks faulted but at least one of them was canceled, the returned task will end in the /// Canceled state. /// </para> /// <para> /// If none of the tasks faulted and none of the tasks were canceled, the resulting task will end in the Completed /// state. /// </para> /// </remarks> public static CoroutineTask WhenAll(params CoroutineTask[] tasks) { AsyncResult result = new AsyncResult(true); try { if (tasks == null) { throw new ArgumentNullException("tasks"); } var count = tasks.Length; var curr = count; var isCancelled = false; var exceptions = new List <Exception>(); for (var i = 0; i < count; i++) { CoroutineTask task = tasks[i]; task.asyncResult.Callbackable().OnCallback(ar => { isCancelled |= ar.IsCancelled; if (ar.Exception != null) { exceptions.Add(ar.Exception); } if (Interlocked.Decrement(ref curr) <= 0) { if (isCancelled) { result.SetCancelled(); } else if (exceptions.Count > 0) { result.SetException(new AggregateException(exceptions)); } else { result.SetResult(); } } }); } } catch (Exception e) { result.SetException(e); } return(new CoroutineTask(result)); }
/// <summary> /// Creates a task that will complete when all of the supplied tasks have completed. /// </summary> /// <typeparam name="TResult"></typeparam> /// <param name="tasks">The tasks to wait on for completion.</param> /// <returns>A task that represents the completion of all of the supplied tasks.</returns> /// <remarks> /// <para> /// If any of the supplied tasks completes in a faulted state, the returned task will also complete in a Faulted /// state, /// where its exceptions will contain the aggregation of the set of unwrapped exceptions from each of the supplied /// tasks. /// </para> /// <para> /// If none of the supplied tasks faulted but at least one of them was canceled, the returned task will end in the /// Canceled state. /// </para> /// <para> /// If none of the tasks faulted and none of the tasks were canceled, the resulting task will end in the Completed /// state. /// The Result of the returned task will be set to an array containing all of the results of the supplied tasks in /// the /// same order as they were provided. /// </para> /// </remarks> public static CoroutineTask <TResult[]> WhenAll <TResult>(params CoroutineTask <TResult>[] tasks) { var result = new AsyncResult <TResult[]>(true); try { if (tasks == null) { throw new ArgumentNullException("tasks"); } var count = tasks.Length; var curr = count; var isCancelled = false; var exceptions = new List <Exception>(); var array = new TResult[count]; for (var i = 0; i < count; i++) { var index = i; var t = tasks[index]; t.asyncResult.Callbackable().OnCallback(ar => { try { isCancelled |= ar.IsCancelled; if (ar.Exception != null) { exceptions.Add(ar.Exception); } else { array[index] = (TResult)ar.Result; } } finally { if (Interlocked.Decrement(ref curr) <= 0) { if (isCancelled) { result.SetCancelled(); } else if (exceptions.Count > 0) { result.SetException(new AggregateException(exceptions)); } else { result.SetResult(array); } } } }); } } catch (Exception e) { result.SetException(e); } return(new CoroutineTask <TResult[]>(result)); }
protected virtual Action WrapAction(Action action) { Action wrapAction = () => { try { try { if (preCallbackOnWorkerThread != null) preCallbackOnWorkerThread(); } catch (Exception e) { if (log.IsWarnEnabled) log.WarnFormat("{0}", e); } if (result.IsCancellationRequested) { result.SetCancelled(); return; } action(); } catch (Exception e) { result.SetException(e); } finally { try { if (Exception != null) { if (errorCallbackOnMainThread != null) Executors.RunOnMainThread(() => errorCallbackOnMainThread(Exception), true); if (errorCallbackOnWorkerThread != null) errorCallbackOnWorkerThread(Exception); } else { if (postCallbackOnMainThread != null) Executors.RunOnMainThread(postCallbackOnMainThread, true); if (postCallbackOnWorkerThread != null) postCallbackOnWorkerThread(); } } catch (Exception e) { if (log.IsWarnEnabled) log.WarnFormat("{0}", e); } try { if (finishCallbackOnMainThread != null) Executors.RunOnMainThread(finishCallbackOnMainThread, true); if (finishCallbackOnWorkerThread != null) finishCallbackOnWorkerThread(); } catch (Exception e) { if (log.IsWarnEnabled) log.WarnFormat("{0}", e); } Interlocked.Exchange(ref running, 0); } }; return wrapAction; }