public IAsync Receive(Action <Result> handler) { IAsyncSource source = Async.NewSource(); bool flag = false; object sync = this.sync; lock (sync) { if (this.result != null) { flag = true; } else { if (this.handlers == null) { this.handlers = new List <Tuple <Action <Result>, IAsyncSource> >(1); } this.handlers.Add(Tuple.Create <Action <Result>, IAsyncSource>(handler, source)); } } if (flag) { Result result = handler.Try <Result>(this.result); source.SetResult(result); } return(source.AsReceiveOnly()); }
public IAsync Enqueue(QueueSide qSide, Action callback) { Validate.Begin().IsNotNull <Action>(callback, "callback").IsTrue(((qSide == QueueSide.Front) || (qSide == QueueSide.Back)), "qSide is not a valid member of the QueueSide enumeration").Check(); IAsyncSource source = Async.NewSource(); if (this.pleaseAbort) { source.Throw(new OperationCanceledException("The work queue has shut down.")); } else { object sync = this.Sync; lock (sync) { Action item = delegate { callback.Try().Into(source); }; Action action2 = delegate { source.Throw(new OperationCanceledException("The dispatcher has shut down.")); }; if (qSide == QueueSide.Front) { this.runFnQ.EnqueueFront(item); this.cancelFnQ.EnqueueFront(action2); } else { this.runFnQ.Enqueue(item); this.cancelFnQ.Enqueue(action2); } ThreadPool.QueueUserWorkItem(this.threadPoolCallback); } } return(source.AsReceiveOnly()); }
public IAsync BeginTry(Action callback) { base.VerifyAccess(); IAsyncSource async = Async.NewSource(); this.syncContext.Post(delegate(object _) { async.SetResult(callback.Try()); }); return(async); }
public AsyncPump( [NotNull] IAsyncSource <T> source, [NotNull] IAsyncTarget <T> target ) { if (source == null) { throw new ArgumentNullException("source"); } if (target == null) { throw new ArgumentNullException("target"); } m_source = source; m_target = target; }
/// <summary>Pump the content of a source into a list</summary> public static async Task <List <T> > PumpToListAsync <T>(this IAsyncSource <T> source, CancellationToken ct) { if (ct.IsCancellationRequested) { ct.ThrowIfCancellationRequested(); } var buffer = new Buffer <T>(); var target = CreateTarget <T>( (x, _) => buffer.Add(x) ); await PumpToAsync <T>(source, target, ct).ConfigureAwait(false); return(buffer.ToList()); }
public static IAsync <T> BeginEval <T>(this IAsyncWorkQueue queue, Func <T> f) { IAsyncSource <T> source = Async.NewSource <T>(); queue.BeginTry(delegate { try { Result <T> result = f.Eval <T>(); source.SetResult(result); } catch (Exception exception) { source.Throw <T>(new TargetInvocationException(exception)); } }); return(source.AsReceiveOnly <T>()); }
public IAsync BeginTry(Action callback) { IAsyncSource source = Async.NewSource(); this.dispatcher.BeginInvoke(delegate { try { Result @void = Result.Void; callback(); source.SetResult(@void); } catch (Exception exception1) { Result result = Result.NewError(exception1); source.SetResult(result); } }, Array.Empty <object>()); return(source.AsReceiveOnly()); }
public static async Task <List <TOutput> > TransformToListAsync <TInput, TOutput>(IAsyncSource <TInput> source, Func <TInput, CancellationToken, Task <TOutput> > transform, CancellationToken ct, int?maxConcurrency = null, TaskScheduler scheduler = null) { ct.ThrowIfCancellationRequested(); using (var queue = CreateOrderPreservingAsyncBuffer <TOutput>(maxConcurrency ?? 32)) { using (var pipe = CreateAsyncTransform <TInput, TOutput>(transform, queue, scheduler)) { // start the output pump var output = PumpToListAsync(queue, ct); // start the intput pump var input = PumpToAsync(source, pipe, ct); await Task.WhenAll(input, output).ConfigureAwait(false); return(output.Result); } } }
/// <summary>Consumes all the elements of the source, and publish them to the target, one by one and in order</summary> /// <param name="source">Source that produces elements asynchronously</param> /// <param name="target">Target that consumes elements asynchronously</param> /// <param name="ct">Cancellation token</param> /// <returns>Task that completes when all the elements of the source have been published to the target, or fails if on the first error, or the token is cancelled unexpectedly</returns> /// <remarks>The pump will only read one element at a time, and wait for it to be published to the target, before reading the next element.</remarks> public static async Task PumpToAsync <T>(this IAsyncSource <T> source, IAsyncTarget <T> target, CancellationToken ct) { ct.ThrowIfCancellationRequested(); bool notifiedCompletion = false; bool notifiedError = false; try { //LogPump("Starting pump"); while (!ct.IsCancellationRequested) { //LogPump("Waiting for next"); var current = await source.ReceiveAsync(ct).ConfigureAwait(false); //LogPump("Received " + (current.HasValue ? "value" : current.Failed ? "error" : "completion") + ", publishing... " + current); if (ct.IsCancellationRequested) { // REVIEW: should we notify the target? // REVIEW: if the item is IDisposble, who will clean up? break; } // push the data/error/completion on to the target, which will triage and update its state accordingly await target.Publish(current, ct).ConfigureAwait(false); if (current.Failed) { // bounce the error back to the caller //REVIEW: SHOULD WE? We poush the error to the target, and the SAME error to the caller... who should be responsible for handling it? // => target should know about the error (to cancel something) // => caller should maybe also know that the pump failed unexpectedly.... notifiedError = true; current.ThrowForNonSuccess(); // throws an exception right here return; // should not be reached } else if (current.IsEmpty) { // the source has completed, stop the pump //LogPump("Completed"); notifiedCompletion = true; return; } } // notify cancellation if it happend while we were pumping if (ct.IsCancellationRequested) { //LogPump("We were cancelled!"); throw new OperationCanceledException(ct); } } catch (Exception e) { //LogPump("Failed: " + e); if (!notifiedCompletion && !notifiedError) { // notify the target that we crashed while fetching the next try { //LogPump("Push error down to target: " + e.Message); target.OnError(ExceptionDispatchInfo.Capture(e)); notifiedError = true; } catch (Exception x) when(!x.IsFatalError()) { //LogPump("Failed to notify target of error: " + x.Message); } } throw; } finally { if (!notifiedCompletion) { // we must be sure to complete the target if we haven't done so yet! //LogPump("Notify target of completion due to unexpected conditions"); target.OnCompleted(); } //LogPump("Stopped pump"); } }
public static bool Into <T>(this Result <T> result, IAsyncSource <T> async) => async.SetResult(result);
public static bool Into(this Result result, IAsyncSource async) => async.SetResult(result);
public static bool ErrorInto <T, U>(this Result <T> tResult, IAsyncSource <U> source) => (tResult.IsError && source.Throw <U>(tResult.Error));
public static IAsync <T> AsReceiveOnly <T>(this IAsyncSource <T> source) => source;
public static IAsync AsReceiveOnly(this IAsyncSource source) => source;
public static bool Throw <T>(this IAsyncSource <T> source, Exception ex) => source.SetResult(Result.NewError <T>(ex));
public static bool Return <T>(this IAsyncSource <T> source, T value) => source.SetResult(Result.New <T>(value));
public static bool Return(this IAsyncSource source) => source.SetResult(Result.Void);