| Index: pkg/dev_compiler/tool/input_sdk/lib/async/future_impl.dart
|
| diff --git a/pkg/dev_compiler/tool/input_sdk/lib/async/future_impl.dart b/pkg/dev_compiler/tool/input_sdk/lib/async/future_impl.dart
|
| deleted file mode 100644
|
| index 4e6ba423446fee6bf1eebe606b319ffbc72e26c8..0000000000000000000000000000000000000000
|
| --- a/pkg/dev_compiler/tool/input_sdk/lib/async/future_impl.dart
|
| +++ /dev/null
|
| @@ -1,746 +0,0 @@
|
| -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
| -// for details. All rights reserved. Use of this source code is governed by a
|
| -// BSD-style license that can be found in the LICENSE file.
|
| -
|
| -part of dart.async;
|
| -
|
| -/** The onValue and onError handlers return either a value or a future */
|
| -typedef dynamic/*T|Future<T>*/ _FutureOnValue<S, T>(S value);
|
| -/** Test used by [Future.catchError] to handle skip some errors. */
|
| -typedef bool _FutureErrorTest(var error);
|
| -/** Used by [WhenFuture]. */
|
| -typedef _FutureAction();
|
| -
|
| -abstract class _Completer<T> implements Completer<T> {
|
| - final _Future<T> future = new _Future<T>();
|
| -
|
| - void complete([value]);
|
| -
|
| - void completeError(Object error, [StackTrace stackTrace]) {
|
| - error = _nonNullError(error);
|
| - if (!future._mayComplete) throw new StateError("Future already completed");
|
| - AsyncError replacement = Zone.current.errorCallback(error, stackTrace);
|
| - if (replacement != null) {
|
| - error = _nonNullError(replacement.error);
|
| - stackTrace = replacement.stackTrace;
|
| - }
|
| - _completeError(error, stackTrace);
|
| - }
|
| -
|
| - void _completeError(Object error, StackTrace stackTrace);
|
| -
|
| - // The future's _isComplete doesn't take into account pending completions.
|
| - // We therefore use _mayComplete.
|
| - bool get isCompleted => !future._mayComplete;
|
| -}
|
| -
|
| -class _AsyncCompleter<T> extends _Completer<T> {
|
| -
|
| - void complete([value]) {
|
| - if (!future._mayComplete) throw new StateError("Future already completed");
|
| - future._asyncComplete(value);
|
| - }
|
| -
|
| - void _completeError(Object error, StackTrace stackTrace) {
|
| - future._asyncCompleteError(error, stackTrace);
|
| - }
|
| -}
|
| -
|
| -class _SyncCompleter<T> extends _Completer<T> {
|
| - void complete([value]) {
|
| - if (!future._mayComplete) throw new StateError("Future already completed");
|
| - future._complete(value);
|
| - }
|
| -
|
| - void _completeError(Object error, StackTrace stackTrace) {
|
| - future._completeError(error, stackTrace);
|
| - }
|
| -}
|
| -
|
| -class _FutureListener<S, T> {
|
| - static const int MASK_VALUE = 1;
|
| - static const int MASK_ERROR = 2;
|
| - static const int MASK_TEST_ERROR = 4;
|
| - static const int MASK_WHENCOMPLETE = 8;
|
| - static const int STATE_CHAIN = 0;
|
| - static const int STATE_THEN = MASK_VALUE;
|
| - // TODO(johnmccutchan): Remove the hard coded value. See #26030.
|
| - static const int STATE_THEN_ONERROR = 3; // MASK_VALUE | MASK_ERROR.
|
| - static const int STATE_CATCHERROR = MASK_ERROR;
|
| - // TODO(johnmccutchan): Remove the hard coded value. See #26030.
|
| - static const int STATE_CATCHERROR_TEST = 6; // MASK_ERROR | MASK_TEST_ERROR.
|
| - static const int STATE_WHENCOMPLETE = MASK_WHENCOMPLETE;
|
| - // Listeners on the same future are linked through this link.
|
| - _FutureListener _nextListener = null;
|
| - // The future to complete when this listener is activated.
|
| - final _Future<T> result;
|
| - // Which fields means what.
|
| - final int state;
|
| - // Used for then/whenDone callback and error test
|
| - final Function callback;
|
| - // Used for error callbacks.
|
| - final Function errorCallback;
|
| -
|
| - _FutureListener.then(this.result,
|
| - _FutureOnValue<S, T> onValue, Function errorCallback)
|
| - : callback = onValue,
|
| - errorCallback = errorCallback,
|
| - state = (errorCallback == null) ? STATE_THEN : STATE_THEN_ONERROR;
|
| -
|
| - _FutureListener.catchError(this.result,
|
| - this.errorCallback, _FutureErrorTest test)
|
| - : callback = test,
|
| - state = (test == null) ? STATE_CATCHERROR : STATE_CATCHERROR_TEST;
|
| -
|
| - _FutureListener.whenComplete(this.result, _FutureAction onComplete)
|
| - : callback = onComplete,
|
| - errorCallback = null,
|
| - state = STATE_WHENCOMPLETE;
|
| -
|
| - Zone get _zone => result._zone;
|
| -
|
| - bool get handlesValue => (state & MASK_VALUE != 0);
|
| - bool get handlesError => (state & MASK_ERROR != 0);
|
| - bool get hasErrorTest => (state == STATE_CATCHERROR_TEST);
|
| - bool get handlesComplete => (state == STATE_WHENCOMPLETE);
|
| -
|
| -
|
| - _FutureOnValue<S, T> get _onValue {
|
| - assert(handlesValue);
|
| - return callback as Object /*=_FutureOnValue<S, T>*/;
|
| - }
|
| - Function get _onError => errorCallback;
|
| - _FutureErrorTest get _errorTest {
|
| - assert(hasErrorTest);
|
| - return callback as Object /*=_FutureErrorTest*/;
|
| - }
|
| - _FutureAction get _whenCompleteAction {
|
| - assert(handlesComplete);
|
| - return callback as Object /*=_FutureAction*/;
|
| - }
|
| -
|
| - /// Whether this listener has an error callback.
|
| - ///
|
| - /// This function must only be called if the listener [handlesError].
|
| - bool get hasErrorCallback {
|
| - assert(handlesError);
|
| - return _onError != null;
|
| - }
|
| -
|
| - dynamic/*T|Future<T>*/ handleValue(S sourceResult) {
|
| - return _zone.runUnary<dynamic/*T|Future<T>*/, S>(
|
| - _onValue, sourceResult);
|
| - }
|
| -
|
| - bool matchesErrorTest(AsyncError asyncError) {
|
| - if (!hasErrorTest) return true;
|
| - _FutureErrorTest test = _errorTest;
|
| - return _zone.runUnary<bool, dynamic>(_errorTest, asyncError.error);
|
| - }
|
| -
|
| - dynamic/*T|Future<T>*/ handleError(AsyncError asyncError) {
|
| - assert(handlesError && hasErrorCallback);
|
| - if (errorCallback is ZoneBinaryCallback) {
|
| - var typedErrorCallback = errorCallback as Object
|
| - /*=ZoneBinaryCallback<Object/*T|Future<T>*/, Object, StackTrace>*/;
|
| - return _zone.runBinary(typedErrorCallback,
|
| - asyncError.error,
|
| - asyncError.stackTrace);
|
| - } else {
|
| - return _zone.runUnary<dynamic/*T|Future<T>*/, dynamic>(
|
| - errorCallback, asyncError.error);
|
| - }
|
| - }
|
| -
|
| - dynamic handleWhenComplete() {
|
| - assert(!handlesError);
|
| - return _zone.run(_whenCompleteAction);
|
| - }
|
| -}
|
| -
|
| -class _Future<T> implements Future<T> {
|
| - /// Initial state, waiting for a result. In this state, the
|
| - /// [resultOrListeners] field holds a single-linked list of
|
| - /// [_FutureListener] listeners.
|
| - static const int _INCOMPLETE = 0;
|
| - /// Pending completion. Set when completed using [_asyncComplete] or
|
| - /// [_asyncCompleteError]. It is an error to try to complete it again.
|
| - /// [resultOrListeners] holds listeners.
|
| - static const int _PENDING_COMPLETE = 1;
|
| - /// The future has been chained to another future. The result of that
|
| - /// other future becomes the result of this future as well.
|
| - /// [resultOrListeners] contains the source future.
|
| - static const int _CHAINED = 2;
|
| - /// The future has been completed with a value result.
|
| - static const int _VALUE = 4;
|
| - /// The future has been completed with an error result.
|
| - static const int _ERROR = 8;
|
| -
|
| - /** Whether the future is complete, and as what. */
|
| - int _state = _INCOMPLETE;
|
| -
|
| - /**
|
| - * Zone that the future was completed from.
|
| - * This is the zone that an error result belongs to.
|
| - *
|
| - * Until the future is completed, the field may hold the zone that
|
| - * listener callbacks used to create this future should be run in.
|
| - */
|
| - final Zone _zone = Zone.current;
|
| -
|
| - /**
|
| - * Either the result, a list of listeners or another future.
|
| - *
|
| - * The result of the future is either a value or an error.
|
| - * A result is only stored when the future has completed.
|
| - *
|
| - * The listeners is an internally linked list of [_FutureListener]s.
|
| - * Listeners are only remembered while the future is not yet complete,
|
| - * and it is not chained to another future.
|
| - *
|
| - * The future is another future that his future is chained to. This future
|
| - * is waiting for the other future to complete, and when it does, this future
|
| - * will complete with the same result.
|
| - * All listeners are forwarded to the other future.
|
| - */
|
| - var _resultOrListeners;
|
| -
|
| - // This constructor is used by async/await.
|
| - _Future();
|
| -
|
| - /// Valid types for value: `T` or `Future<T>`.
|
| - _Future.immediate(value) {
|
| - _asyncComplete(value);
|
| - }
|
| -
|
| - _Future.immediateError(var error, [StackTrace stackTrace]) {
|
| - _asyncCompleteError(error, stackTrace);
|
| - }
|
| -
|
| - bool get _mayComplete => _state == _INCOMPLETE;
|
| - bool get _isPendingComplete => _state == _PENDING_COMPLETE;
|
| - bool get _mayAddListener => _state <= _PENDING_COMPLETE;
|
| - bool get _isChained => _state == _CHAINED;
|
| - bool get _isComplete => _state >= _VALUE;
|
| - bool get _hasError => _state == _ERROR;
|
| -
|
| - void _setChained(_Future source) {
|
| - assert(_mayAddListener);
|
| - _state = _CHAINED;
|
| - _resultOrListeners = source;
|
| - }
|
| -
|
| - Future<E> then<E>(
|
| - FutureOr<E> f(T value), { Function onError }) {
|
| - Zone currentZone = Zone.current;
|
| - ZoneUnaryCallback registered;
|
| - if (!identical(currentZone, _ROOT_ZONE)) {
|
| - f = currentZone.registerUnaryCallback<FutureOr<E>, T>(f);
|
| - if (onError != null) {
|
| - onError = _registerErrorHandler<T>(onError, currentZone);
|
| - }
|
| - }
|
| - return _thenNoZoneRegistration<E>(f, onError);
|
| - }
|
| -
|
| - // This method is used by async/await.
|
| - Future<E> _thenNoZoneRegistration<E>(f(T value), Function onError) {
|
| - _Future<E> result = new _Future<E>();
|
| - _addListener(new _FutureListener<T, E>.then(result, f, onError));
|
| - return result;
|
| - }
|
| -
|
| - Future<T> catchError(Function onError, { bool test(error) }) {
|
| - _Future<T> result = new _Future<T>();
|
| - if (!identical(result._zone, _ROOT_ZONE)) {
|
| - onError = _registerErrorHandler<T>(onError, result._zone);
|
| - if (test != null) test = result._zone.registerUnaryCallback(test);
|
| - }
|
| - _addListener(new _FutureListener<T, T>.catchError(
|
| - result, onError, test));
|
| - return result;
|
| - }
|
| -
|
| - Future<T> whenComplete(action()) {
|
| - _Future<T> result = new _Future<T>();
|
| - if (!identical(result._zone, _ROOT_ZONE)) {
|
| - action = result._zone.registerCallback<dynamic>(action);
|
| - }
|
| - _addListener(new _FutureListener<T, T>.whenComplete(result, action));
|
| - return result;
|
| - }
|
| -
|
| - Stream<T> asStream() => new Stream<T>.fromFuture(this);
|
| -
|
| - void _setPendingComplete() {
|
| - assert(_mayComplete);
|
| - _state = _PENDING_COMPLETE;
|
| - }
|
| -
|
| - void _clearPendingComplete() {
|
| - assert(_isPendingComplete);
|
| - _state = _INCOMPLETE;
|
| - }
|
| -
|
| - AsyncError get _error {
|
| - assert(_hasError);
|
| - return _resultOrListeners;
|
| - }
|
| -
|
| - _Future get _chainSource {
|
| - assert(_isChained);
|
| - return _resultOrListeners;
|
| - }
|
| -
|
| - // This method is used by async/await.
|
| - void _setValue(T value) {
|
| - assert(!_isComplete); // But may have a completion pending.
|
| - _state = _VALUE;
|
| - _resultOrListeners = value;
|
| - }
|
| -
|
| - void _setErrorObject(AsyncError error) {
|
| - assert(!_isComplete); // But may have a completion pending.
|
| - _state = _ERROR;
|
| - _resultOrListeners = error;
|
| - }
|
| -
|
| - void _setError(Object error, StackTrace stackTrace) {
|
| - _setErrorObject(new AsyncError(error, stackTrace));
|
| - }
|
| -
|
| - /// Copy the completion result of [source] into this future.
|
| - ///
|
| - /// Used when a chained future notices that its source is completed.
|
| - void _cloneResult(_Future source) {
|
| - assert(!_isComplete);
|
| - assert(source._isComplete);
|
| - _state = source._state;
|
| - _resultOrListeners = source._resultOrListeners;
|
| - }
|
| -
|
| - void _addListener(_FutureListener listener) {
|
| - assert(listener._nextListener == null);
|
| - if (_mayAddListener) {
|
| - listener._nextListener = _resultOrListeners;
|
| - _resultOrListeners = listener;
|
| - } else {
|
| - if (_isChained) {
|
| - // Delegate listeners to chained source future.
|
| - // If the source is complete, instead copy its values and
|
| - // drop the chaining.
|
| - _Future source = _chainSource;
|
| - if (!source._isComplete) {
|
| - source._addListener(listener);
|
| - return;
|
| - }
|
| - _cloneResult(source);
|
| - }
|
| - assert(_isComplete);
|
| - // Handle late listeners asynchronously.
|
| - _zone.scheduleMicrotask(() {
|
| - _propagateToListeners(this, listener);
|
| - });
|
| - }
|
| - }
|
| -
|
| - void _prependListeners(_FutureListener listeners) {
|
| - if (listeners == null) return;
|
| - if (_mayAddListener) {
|
| - _FutureListener existingListeners = _resultOrListeners;
|
| - _resultOrListeners = listeners;
|
| - if (existingListeners != null) {
|
| - _FutureListener cursor = listeners;
|
| - while (cursor._nextListener != null) {
|
| - cursor = cursor._nextListener;
|
| - }
|
| - cursor._nextListener = existingListeners;
|
| - }
|
| - } else {
|
| - if (_isChained) {
|
| - // Delegate listeners to chained source future.
|
| - // If the source is complete, instead copy its values and
|
| - // drop the chaining.
|
| - _Future source = _chainSource;
|
| - if (!source._isComplete) {
|
| - source._prependListeners(listeners);
|
| - return;
|
| - }
|
| - _cloneResult(source);
|
| - }
|
| - assert(_isComplete);
|
| - listeners = _reverseListeners(listeners);
|
| - _zone.scheduleMicrotask(() {
|
| - _propagateToListeners(this, listeners);
|
| - });
|
| - }
|
| - }
|
| -
|
| - _FutureListener _removeListeners() {
|
| - // Reverse listeners before returning them, so the resulting list is in
|
| - // subscription order.
|
| - assert(!_isComplete);
|
| - _FutureListener current = _resultOrListeners;
|
| - _resultOrListeners = null;
|
| - return _reverseListeners(current);
|
| - }
|
| -
|
| - _FutureListener _reverseListeners(_FutureListener listeners) {
|
| - _FutureListener prev = null;
|
| - _FutureListener current = listeners;
|
| - while (current != null) {
|
| - _FutureListener next = current._nextListener;
|
| - current._nextListener = prev;
|
| - prev = current;
|
| - current = next;
|
| - }
|
| - return prev;
|
| - }
|
| -
|
| - // Take the value (when completed) of source and complete target with that
|
| - // value (or error). This function could chain all Futures, but is slower
|
| - // for _Future than _chainCoreFuture, so you must use _chainCoreFuture
|
| - // in that case.
|
| - static void _chainForeignFuture(Future source, _Future target) {
|
| - assert(!target._isComplete);
|
| - assert(source is! _Future);
|
| -
|
| - // Mark the target as chained (and as such half-completed).
|
| - target._setPendingComplete();
|
| - try {
|
| - source.then((value) {
|
| - 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(value);
|
| - },
|
| - // TODO(floitsch): eventually we would like to make this non-optional
|
| - // and dependent on the listeners of the target future. If none of
|
| - // the target future's listeners want to have the stack trace we don't
|
| - // need a trace.
|
| - onError: (error, [stackTrace]) {
|
| - assert(target._isPendingComplete);
|
| - target._completeError(error, stackTrace);
|
| - });
|
| - } catch (e, s) {
|
| - // 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.
|
| - scheduleMicrotask(() {
|
| - target._completeError(e, s);
|
| - });
|
| - }
|
| - }
|
| -
|
| - // Take the value (when completed) of source and complete target with that
|
| - // value (or error). This function expects that source is a _Future.
|
| - static void _chainCoreFuture(_Future source, _Future target) {
|
| - assert(target._mayAddListener); // Not completed, not already chained.
|
| - while (source._isChained) {
|
| - source = source._chainSource;
|
| - }
|
| - if (source._isComplete) {
|
| - _FutureListener listeners = target._removeListeners();
|
| - target._cloneResult(source);
|
| - _propagateToListeners(target, listeners);
|
| - } else {
|
| - _FutureListener listeners = target._resultOrListeners;
|
| - target._setChained(source);
|
| - source._prependListeners(listeners);
|
| - }
|
| - }
|
| -
|
| - void _complete(value) {
|
| - assert(!_isComplete);
|
| - if (value is Future) {
|
| - if (value is _Future) {
|
| - _chainCoreFuture(value, this);
|
| - } else {
|
| - _chainForeignFuture(value, this);
|
| - }
|
| - } else {
|
| - _FutureListener listeners = _removeListeners();
|
| - _setValue(value as Object /*=T*/);
|
| - _propagateToListeners(this, listeners);
|
| - }
|
| - }
|
| -
|
| - void _completeWithValue(T value) {
|
| - assert(!_isComplete);
|
| - assert(value is! Future);
|
| -
|
| - _FutureListener listeners = _removeListeners();
|
| - _setValue(value);
|
| - _propagateToListeners(this, listeners);
|
| - }
|
| -
|
| - void _completeError(error, [StackTrace stackTrace]) {
|
| - assert(!_isComplete);
|
| -
|
| - _FutureListener listeners = _removeListeners();
|
| - _setError(error, stackTrace);
|
| - _propagateToListeners(this, listeners);
|
| - }
|
| -
|
| - void _asyncComplete(value) {
|
| - assert(!_isComplete);
|
| - // Two corner cases if the value is a future:
|
| - // 1. the future is already completed and an error.
|
| - // 2. the future is not yet completed but might become an error.
|
| - // The first case means that we must not immediately complete the Future,
|
| - // as our code would immediately start propagating the error without
|
| - // giving the time to install error-handlers.
|
| - // However the second case requires us to deal with the value immediately.
|
| - // Otherwise the value could complete with an error and report an
|
| - // unhandled error, even though we know we are already going to listen to
|
| - // it.
|
| -
|
| - if (value is Future) {
|
| - // Assign to typed variables so we get earlier checks in checked mode.
|
| - Future<T> typedFuture = value as Object /*=Future<T>*/;
|
| - if (typedFuture is _Future) {
|
| - _Future<T> coreFuture = typedFuture;
|
| - if (coreFuture._hasError) {
|
| - // Case 1 from above. Delay completion to enable the user to register
|
| - // callbacks.
|
| - _setPendingComplete();
|
| - _zone.scheduleMicrotask(() {
|
| - _chainCoreFuture(coreFuture, this);
|
| - });
|
| - } else {
|
| - _chainCoreFuture(coreFuture, this);
|
| - }
|
| - } else {
|
| - // Case 2 from above. Chain the future immediately.
|
| - // Note that we are still completing asynchronously (through
|
| - // _chainForeignFuture).
|
| - _chainForeignFuture(typedFuture, this);
|
| - }
|
| - return;
|
| - }
|
| - T typedValue = value as Object /*=T*/;
|
| -
|
| - _setPendingComplete();
|
| - _zone.scheduleMicrotask(() {
|
| - _completeWithValue(typedValue);
|
| - });
|
| - }
|
| -
|
| - void _asyncCompleteError(error, StackTrace stackTrace) {
|
| - assert(!_isComplete);
|
| -
|
| - _setPendingComplete();
|
| - _zone.scheduleMicrotask(() {
|
| - _completeError(error, stackTrace);
|
| - });
|
| - }
|
| -
|
| - /**
|
| - * Propagates the value/error of [source] to its [listeners], executing the
|
| - * listeners' callbacks.
|
| - */
|
| - static void _propagateToListeners(_Future source, _FutureListener listeners) {
|
| - while (true) {
|
| - assert(source._isComplete);
|
| - bool hasError = source._hasError;
|
| - if (listeners == null) {
|
| - if (hasError) {
|
| - AsyncError asyncError = source._error;
|
| - source._zone.handleUncaughtError(
|
| - asyncError.error, asyncError.stackTrace);
|
| - }
|
| - return;
|
| - }
|
| - // Usually futures only have one listener. If they have several, we
|
| - // call handle them separately in recursive calls, continuing
|
| - // here only when there is only one listener left.
|
| - while (listeners._nextListener != null) {
|
| - _FutureListener listener = listeners;
|
| - listeners = listener._nextListener;
|
| - listener._nextListener = null;
|
| - _propagateToListeners(source, listener);
|
| - }
|
| - _FutureListener listener = listeners;
|
| - final sourceResult = source._resultOrListeners;
|
| - // Do the actual propagation.
|
| - // Set initial state of listenerHasError and listenerValueOrError. These
|
| - // variables are updated with the outcome of potential callbacks.
|
| - // Non-error results, including futures, are stored in
|
| - // listenerValueOrError and listenerHasError is set to false. Errors
|
| - // are stored in listenerValueOrError as an [AsyncError] and
|
| - // listenerHasError is set to true.
|
| - bool listenerHasError = hasError;
|
| - var listenerValueOrError = sourceResult;
|
| -
|
| - // Only if we either have an error or callbacks, go into this, somewhat
|
| - // expensive, branch. Here we'll enter/leave the zone. Many futures
|
| - // don't have callbacks, so this is a significant optimization.
|
| - if (hasError || listener.handlesValue || listener.handlesComplete) {
|
| - Zone zone = listener._zone;
|
| - if (hasError && !source._zone.inSameErrorZone(zone)) {
|
| - // Don't cross zone boundaries with errors.
|
| - AsyncError asyncError = source._error;
|
| - source._zone.handleUncaughtError(
|
| - asyncError.error, asyncError.stackTrace);
|
| - return;
|
| - }
|
| -
|
| - Zone oldZone;
|
| - if (!identical(Zone.current, zone)) {
|
| - // Change zone if it's not current.
|
| - oldZone = Zone._enter(zone);
|
| - }
|
| -
|
| - // These callbacks are abstracted to isolate the try/catch blocks
|
| - // from the rest of the code to work around a V8 glass jaw.
|
| - void handleWhenCompleteCallback() {
|
| - // The whenComplete-handler is not combined with normal value/error
|
| - // handling. This means at most one handleX method is called per
|
| - // listener.
|
| - assert(!listener.handlesValue);
|
| - assert(!listener.handlesError);
|
| - var completeResult;
|
| - try {
|
| - completeResult = listener.handleWhenComplete();
|
| - } catch (e, s) {
|
| - if (hasError && identical(source._error.error, e)) {
|
| - listenerValueOrError = source._error;
|
| - } else {
|
| - listenerValueOrError = new AsyncError(e, s);
|
| - }
|
| - listenerHasError = true;
|
| - return;
|
| - }
|
| - if (completeResult is Future) {
|
| - if (completeResult is _Future && completeResult._isComplete) {
|
| - if (completeResult._hasError) {
|
| - listenerValueOrError = completeResult._error;
|
| - listenerHasError = true;
|
| - }
|
| - // Otherwise use the existing result of source.
|
| - return;
|
| - }
|
| - // We have to wait for the completeResult future to complete
|
| - // before knowing if it's an error or we should use the result
|
| - // of source.
|
| - var originalSource = source;
|
| - listenerValueOrError = completeResult.then((_) => originalSource);
|
| - listenerHasError = false;
|
| - }
|
| - }
|
| -
|
| - void handleValueCallback() {
|
| - try {
|
| - listenerValueOrError = listener.handleValue(sourceResult);
|
| - } catch (e, s) {
|
| - listenerValueOrError = new AsyncError(e, s);
|
| - listenerHasError = true;
|
| - }
|
| - }
|
| -
|
| - void handleError() {
|
| - try {
|
| - AsyncError asyncError = source._error;
|
| - if (listener.matchesErrorTest(asyncError) &&
|
| - listener.hasErrorCallback) {
|
| - listenerValueOrError = listener.handleError(asyncError);
|
| - listenerHasError = false;
|
| - }
|
| - } catch (e, s) {
|
| - if (identical(source._error.error, e)) {
|
| - listenerValueOrError = source._error;
|
| - } else {
|
| - listenerValueOrError = new AsyncError(e, s);
|
| - }
|
| - listenerHasError = true;
|
| - }
|
| - }
|
| -
|
| -
|
| - if (listener.handlesComplete) {
|
| - handleWhenCompleteCallback();
|
| - } else if (!hasError) {
|
| - if (listener.handlesValue) {
|
| - handleValueCallback();
|
| - }
|
| - } else {
|
| - if (listener.handlesError) {
|
| - handleError();
|
| - }
|
| - }
|
| -
|
| - // If we changed zone, oldZone will not be null.
|
| - if (oldZone != null) Zone._leave(oldZone);
|
| -
|
| - // If the listener's value is a future we need to chain it. Note that
|
| - // this can only happen if there is a callback.
|
| - if (listenerValueOrError is Future) {
|
| - Future chainSource = listenerValueOrError;
|
| - // Shortcut if the chain-source is already completed. Just continue
|
| - // the loop.
|
| - _Future result = listener.result;
|
| - if (chainSource is _Future) {
|
| - if (chainSource._isComplete) {
|
| - listeners = result._removeListeners();
|
| - result._cloneResult(chainSource);
|
| - source = chainSource;
|
| - continue;
|
| - } else {
|
| - _chainCoreFuture(chainSource, result);
|
| - }
|
| - } else {
|
| - _chainForeignFuture(chainSource, result);
|
| - }
|
| - return;
|
| - }
|
| - }
|
| - _Future result = listener.result;
|
| - listeners = result._removeListeners();
|
| - if (!listenerHasError) {
|
| - result._setValue(listenerValueOrError);
|
| - } else {
|
| - AsyncError asyncError = listenerValueOrError;
|
| - result._setErrorObject(asyncError);
|
| - }
|
| - // Prepare for next round.
|
| - source = result;
|
| - }
|
| - }
|
| -
|
| - Future<T> timeout(Duration timeLimit, {onTimeout()}) {
|
| - if (_isComplete) return new _Future.immediate(this);
|
| - _Future<T> result = new _Future<T>();
|
| - Timer timer;
|
| - if (onTimeout == null) {
|
| - timer = new Timer(timeLimit, () {
|
| - result._completeError(new TimeoutException("Future not completed",
|
| - timeLimit));
|
| - });
|
| - } else {
|
| - Zone zone = Zone.current;
|
| - onTimeout = zone.registerCallback(onTimeout);
|
| - timer = new Timer(timeLimit, () {
|
| - try {
|
| - result._complete(zone.run(onTimeout));
|
| - } catch (e, s) {
|
| - result._completeError(e, s);
|
| - }
|
| - });
|
| - }
|
| - this.then((T v) {
|
| - if (timer.isActive) {
|
| - timer.cancel();
|
| - result._completeWithValue(v);
|
| - }
|
| - }, onError: (e, s) {
|
| - if (timer.isActive) {
|
| - timer.cancel();
|
| - result._completeError(e, s);
|
| - }
|
| - });
|
| - return result;
|
| - }
|
| -}
|
|
|