internal static void _cancelAndValue <T>(StreamSubscription <T> subscription, _Future future, FutureOr value) { var cancelFuture = subscription.cancel(); if (cancelFuture != null && !Equals(cancelFuture, Future._nullFuture)) { cancelFuture.whenComplete(() => future._complete(value)); } else { future._complete(value); } }
Future <string> join(string separator = "") { _Future result = new _Future(); StringBuilder buffer = new StringBuilder(); StreamSubscription <T> subscription = null; bool first = true; subscription = listen( (T element) => { if (!first) { buffer.Append(separator); } first = false; try { buffer.Append(element); } catch (Exception e) { _stream._cancelAndErrorWithReplacement(subscription, result, e); } }, onError: (e, _) => result._completeError((Exception)e), onDone: () => { result._complete(buffer.ToString()); }, cancelOnError: true); return(result.to <string>()); }
static void _chainForeignFuture(Future source, _Future target) { D.assert(!target._isComplete); D.assert(!(source is _Future)); // Mark the target as chained (and as such half-completed). target._setPendingComplete(); try { source.then((value) => { D.assert(target._isPendingComplete); // The "value" may be another future if the foreign future // implementation is mis-behaving, // so use _complete instead of _completeWithValue. target._clearPendingComplete(); // Clear this first, it's set again. target._complete(FutureOr.value(value)); return(new FutureOr()); }, onError: (Exception error) => { D.assert(target._isPendingComplete); target._completeError(error); return(new FutureOr()); }); } catch (Exception e) { // This only happens if the `then` call threw synchronously when given // valid arguments. // That requires a non-conforming implementation of the Future interface, // which should, hopefully, never happen. async_.scheduleMicrotask(() => { target._completeError(e); return(null); }); } }
public override Future timeout(TimeSpan timeLimit, Func <FutureOr> onTimeout = null) { if (_isComplete) { return(immediate(this)); } _Future result = new _Future(); Timer timer; if (onTimeout == null) { timer = Timer.create(timeLimit, () => { result._completeError( new TimeoutException("Future not completed", timeLimit)); return(null); }); } else { Zone zone = Zone.current; onTimeout = async_._registerHandler(onTimeout, zone); timer = Timer.create(timeLimit, () => { try { result._complete((FutureOr)zone.run(() => onTimeout())); } catch (Exception e) { result._completeError(e); } return(null); }); } then(v => { if (timer.isActive) { timer.cancel(); result._completeWithValue(v); } return(FutureOr.nil); }, onError: e => { if (timer.isActive) { timer.cancel(); result._completeError(e); } return(FutureOr.nil); }); return(result); }
public static Future delayed(TimeSpan duration, Func <FutureOr> computation = null) { _Future result = new _Future(); Timer.create(duration, () => { if (computation == null) { result._complete(); } else { try { result._complete(computation()); } catch (Exception e) { async_._completeWithErrorCallback(result, e); } } return(null); }); return(result); }
Future <S> fold <S>(S initialValue, Func <S, T, S> combine) { _Future result = new _Future(); S value = initialValue; StreamSubscription <T> subscription = null; subscription = listen( (T element) => { _stream._runUserCode(() => combine(value, element), (S newValue) => { value = newValue; }, e => _stream._cancelAndErrorClosure(subscription, result)(e)); }, onError: (e, s) => result._completeError((Exception)e), onDone: () => { result._complete(FutureOr.value(value)); }, cancelOnError: true); return(result.to <S>()); }
public static Future microtask(Func <FutureOr> computation) { _Future result = new _Future(); async_.scheduleMicrotask(() => { try { result._complete(computation()); } catch (Exception e) { async_._completeWithErrorCallback(result, e); } return(null); }); return(result); }
public static Future create(Func <FutureOr> computation) { _Future result = new _Future(); Timer.run(() => { try { result._complete(computation()); } catch (Exception e) { async_._completeWithErrorCallback(result, e); } return(null); }); return(result); }
public static Future doWhile(Func <FutureOr> action) { _Future doneSignal = new _Future(); ZoneUnaryCallback nextIteration = null; // Bind this callback explicitly so that each iteration isn't bound in the // context of all the previous iterations' callbacks. // This avoids, e.g., deeply nested stack traces from the stack trace // package. nextIteration = Zone.current.bindUnaryCallbackGuarded((object keepGoingObj) => { bool keepGoing = (bool)keepGoingObj; while (keepGoing) { FutureOr result; try { result = action(); } catch (Exception error) { // Cannot use _completeWithErrorCallback because it completes // the future synchronously. async_._asyncCompleteWithErrorCallback(doneSignal, error); return(null); } if (result.isFuture) { result.f.then((value) => { nextIteration((bool)value); return(FutureOr.nil); }, onError: error => { doneSignal._completeError(error); return(FutureOr.nil); }); return(null); } keepGoing = (bool)result.v; } doneSignal._complete(); return(null); }); nextIteration(true); return(doneSignal); }
Future <bool> contains(object needle) { _Future future = new _Future(); StreamSubscription <T> subscription = null; subscription = listen( (T element) => { _stream._runUserCode(() => (Equals(element, needle)), (bool isMatch) => { if (isMatch) { _stream._cancelAndValue(subscription, future, true); } }, (e) => _stream._cancelAndErrorClosure(subscription, future)(e)); }, onError: (e, _) => future._completeError((Exception)e), onDone: () => { future._complete(false); }, cancelOnError: true); return(future.to <bool>()); }
Future <T> reduce(Func <T, T, T> combine) { _Future result = new _Future(); bool seenFirst = false; T value = default; StreamSubscription <T> subscription = null; subscription = listen( (T element) => { if (seenFirst) { _stream._runUserCode(() => combine(value, element), (T newValue) => { value = newValue; }, onError: (e) => _stream._cancelAndErrorClosure(subscription, result)(e)); } else { value = element; seenFirst = true; } }, onError: (e, s) => result._completeError((Exception)e), onDone: () => { if (!seenFirst) { try { // Throw and recatch, instead of just doing // _completeWithErrorCallback, e, theError, StackTrace.current), // to ensure that the stackTrace is set on the error. throw new Exception("IterableElementError.noElement()"); } catch (Exception e) { async_._completeWithErrorCallback(result, e); } } else { // TODO: need check result._complete(FutureOr.value(value)); } }, cancelOnError: true); return(result.to <T>()); }