public AsyncTransform([NotNull] Func <TInput, CancellationToken, Task <TOutput> > transform, [NotNull] IAsyncTarget <Task <TOutput> > target, TaskScheduler scheduler = null) { Contract.NotNull(transform, nameof(transform)); Contract.NotNull(target, nameof(target)); m_transform = transform; m_target = target; m_scheduler = scheduler; }
public FdbAsyncIteratorPump( IFdbAsyncEnumerator <TInput> iterator, IAsyncTarget <TInput> target ) { Contract.Requires(iterator != null); Contract.Requires(target != null); m_iterator = iterator; m_target = target; }
public AsyncTransform([NotNull] Func <T, CancellationToken, Task <R> > transform, [NotNull] IAsyncTarget <Task <R> > target, TaskScheduler scheduler = null) { if (transform == null) { throw new ArgumentNullException("transform"); } if (target == null) { throw new ArgumentNullException("target"); } m_transform = transform; m_target = target; m_scheduler = scheduler; }
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>Publish a new result on this async target, by correclty handling success, termination and failure</summary> public static Task Publish <T>(this IAsyncTarget <T> target, Maybe <T> result, CancellationToken ct) { Contract.Requires(target != null); if (ct.IsCancellationRequested) { return(Task.FromCanceled(ct)); } if (result.HasValue) { // we have the next value return(target.OnNextAsync(result.Value, ct)); } if (result.Failed) { // we have failed target.OnError(result.CapturedError); return(Task.CompletedTask); } // this is the end of the stream target.OnCompleted(); return(Task.CompletedTask); }
public static AsyncTransform <TInput, TOutput> CreateAsyncTransform <TInput, TOutput>(Func <TInput, CancellationToken, Task <TOutput> > transform, IAsyncTarget <Task <TOutput> > target, TaskScheduler scheduler = null) { return(new AsyncTransform <TInput, TOutput>(transform, target, scheduler)); }
/// <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"); } }