예제 #1
0
        /// <summary>Run the pump until the inner iterator is done, an error occurs, or the cancellation token is fired</summary>
        public async Task PumpAsync(CancellationToken ct)
        {
            if (m_state != STATE_IDLE)
            {
                if (m_state >= STATE_FAILED)
                {
                    throw new InvalidOperationException("The iterator pump has already completed once");
                }
                else
                {
                    throw new InvalidOperationException("The iterator pump is already running");
                }
            }

            try
            {
                while (!ct.IsCancellationRequested)
                {
                    LogDebug("waiting for next");
                    m_state = STATE_WAITING_FOR_NEXT;
                    if (!(await m_iterator.MoveNext(ct).ConfigureAwait(false)))
                    {
                        LogDebug("completed");
                        m_state = STATE_DONE;
                        m_target.OnCompleted();
                        return;
                    }

                    LogDebug("got item, publishing...");
                    m_state = STATE_PUBLISHING_TO_TARGET;
                    await m_target.OnNextAsync(m_iterator.Current, ct).ConfigureAwait(false);
                }

                // push the cancellation on the queue
                OnError(ExceptionDispatchInfo.Capture(new OperationCanceledException(ct)));
                // and throw!
            }
            catch (Exception e)
            {
                LogDebug("failed... (" + m_state + ") : " + e.Message);
                if (m_state == STATE_FAILED)
                {                 // already signaled the target, just throw
                    throw;
                }

                // push the error on the queue, and eat the error
                OnError(ExceptionDispatchInfo.Capture(e));
            }
            finally
            {
                if (m_state != STATE_FAILED)
                {
                    m_state = STATE_DONE;
                }
                LogDebug("stopped (" + m_state + ")");
            }
        }
        public Task OnNextAsync(T value, CancellationToken cancellationToken)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return(TaskHelpers.CompletedTask);
            }

            if (m_done)
            {
                throw new InvalidOperationException("Cannot send any more values because this transform has already completed");
            }

            try
            {
                // we start the task here, but do NOT wait for its completion!
                // It is the job of the target to handle that (and ordering)
                Task <R> task;
                if (m_scheduler == null)
                {                 // execute inline
                    task = m_transform(value, cancellationToken);
                }
                else
                {                 // execute in a scheduler
                    task = Task.Factory.StartNew(
                        (state) =>
                    {
                        var prms = (Tuple <AsyncTransform <T, R>, T, CancellationToken>)state;
                        return(prms.Item1.m_transform(prms.Item2, prms.Item3));
                    },
                        Tuple.Create(this, value, cancellationToken),
                        cancellationToken,
                        TaskCreationOptions.PreferFairness,
                        m_scheduler
                        ).Unwrap();
                }

                return(m_target.OnNextAsync(task, cancellationToken));
            }
            catch (Exception e)
            {
#if NET_4_0
                m_target.OnError(e);
#else
                m_target.OnError(ExceptionDispatchInfo.Capture(e));
#endif
                return(TaskHelpers.FromException <object>(e));
            }
        }
        /// <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);
        }