Пример #1
0
        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;
        }
Пример #2
0
        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;
        }
Пример #4
0
        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");
            }
        }