/// <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); }