public static Future sync(Func <FutureOr> computation) { try { var result = computation(); if (result.isFuture) { return(result.f); } else { return(_Future.value(result)); } } catch (Exception error) { var future = new _Future(); AsyncError replacement = Zone.current.errorCallback(error); if (replacement != null) { future._asyncCompleteError(async_._nonNullError(replacement.InnerException)); } else { future._asyncCompleteError(error); } return(future); } }
public FutureOr handleError(AsyncError asyncError) { D.assert(handlesError && hasErrorCallback); var errorCallback = this.errorCallback; return((FutureOr)_zone.runUnary(arg => errorCallback((Exception)arg), asyncError.InnerException)); }
public bool matchesErrorTest(AsyncError asyncError) { if (!hasErrorTest) { return(true); } return((bool)_zone.runUnary(arg => _errorTest((Exception)arg), asyncError.InnerException)); }
// @Since("2.5") public static Stream <T> error(object error, string stackTrace = null) { // ArgumentError.checkNotNull(error, "error"); var result = new _AsyncStreamController <T>(null, null, null, null); result._addError(error, stackTrace ?? AsyncError.defaultStackTrace(error)); result._closeUnchecked(); return(result.stream); }
internal static void _asyncCompleteWithErrorCallback(_Future result, Exception error) { AsyncError replacement = Zone.current.errorCallback(error); if (replacement != null) { error = _nonNullError(replacement.InnerException); } result._asyncCompleteError(error); }
// internal static void _addErrorWithReplacement <T>(_EventSink <T> sink, Exception error, string stackTrace) { AsyncError replacement = Zone.current.errorCallback(error); if (replacement != null) { error = async_._nonNullError(replacement); stackTrace = replacement.StackTrace; } sink._addError(error, stackTrace); }
internal static void _cancelAndErrorWithReplacement <T>(StreamSubscription <T> subscription, _Future future, Exception error) { AsyncError replacement = Zone.current.errorCallback(error); if (replacement != null) { error = (Exception)_async._nonNullError(replacement); } _cancelAndError(subscription, future, error); }
public override void addError(object error, string stackTrace) { // ArgumentError.checkNotNull(error, "error"); if (_isClosed) { throw new Exception("Sink is closed"); } if (_handleError != null) { stackTrace = stackTrace ?? AsyncError.defaultStackTrace(error); _handleError(error, stackTrace, _sink); } else { _sink.addError(error, stackTrace); } }
public static Future error(Exception error) { if (error == null) { throw new ArgumentNullException(nameof(error)); } if (!ReferenceEquals(Zone.current, async_._rootZone)) { AsyncError replacement = Zone.current.errorCallback(error); if (replacement != null) { error = async_._nonNullError(replacement.InnerException); } } return(_Future.immediateError(error)); }
/** Runs user code and takes actions depending on success or failure. */ internal static void _runUserCode <T>( Func <T> userCode, Action <T> onSuccess, Action <Exception> onError) { try { onSuccess(userCode()); } catch (Exception e) { AsyncError replacement = Zone.current.errorCallback(e); if (replacement == null) { onError(e); } else { var error = async_._nonNullError(replacement); onError(error); } } }
public override void completeError(Exception error) { if (error == null) { throw new ArgumentNullException(nameof(error)); } if (!_future._mayComplete) { throw new Exception("Future already completed"); } AsyncError replacement = Zone.current.errorCallback(error); if (replacement != null) { error = async_._nonNullError(replacement.InnerException); } _completeError(error); }
public override void addError(object error, string stackTrace) { _sink._addError(error, stackTrace ?? AsyncError.defaultStackTrace(error)); }
static void _propagateToListeners(_Future source, _FutureListener listeners) { while (true) { D.assert(source._isComplete); bool hasError = source._hasError; if (listeners == null) { if (hasError) { AsyncError asyncError = source._error; source._zone.handleUncaughtError(asyncError); } 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 currentListener = listeners; listeners = currentListener._nextListener; currentListener._nextListener = null; _propagateToListeners(source, currentListener); } _FutureListener listener = listeners; var 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); return; } Zone oldZone = null; if (!ReferenceEquals(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. Action handleWhenCompleteCallback = () => { // The whenComplete-handler is not combined with normal value/error // handling. This means at most one handleX method is called per // listener. D.assert(!listener.handlesValue); D.assert(!listener.handlesError); FutureOr completeResult; try { completeResult = listener.handleWhenComplete(); } catch (Exception e) { if (hasError && ReferenceEquals(source._error.InnerException, e)) { listenerValueOrError = source._error; } else { listenerValueOrError = new AsyncError(e); } listenerHasError = true; return; } if (completeResult.isFuture) { var completeResultFuture = completeResult.f; if (completeResultFuture is _Future completeResultCoreFuture && completeResultCoreFuture._isComplete) { if (completeResultCoreFuture._hasError) { listenerValueOrError = completeResultCoreFuture._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 = completeResultFuture.then((_) => FutureOr.future(originalSource)); listenerHasError = false; } }; Action handleValueCallback = () => { try { listenerValueOrError = listener.handleValue(sourceResult); } catch (Exception e) { listenerValueOrError = new AsyncError(e); listenerHasError = true; } }; Action handleError = () => { try { AsyncError asyncError = source._error; if (listener.matchesErrorTest(asyncError) && listener.hasErrorCallback) { listenerValueOrError = listener.handleError(asyncError); listenerHasError = false; } } catch (Exception e) { if (ReferenceEquals(source._error.InnerException, e)) { listenerValueOrError = source._error; } else { listenerValueOrError = new AsyncError(e); } 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 (listenerValueOrError is FutureOr futureOr) { listenerValueOrError = futureOr.isFuture ? futureOr.f : futureOr.v; } // 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 chainSource) { // Shortcut if the chain-source is already completed. Just continue // the loop. _Future listenerResult = listener.result; if (chainSource is _Future chainSourceCore) { if (chainSourceCore._isComplete) { listeners = listenerResult._removeListeners(); listenerResult._cloneResult(chainSourceCore); source = chainSourceCore; continue; } else { _chainCoreFuture(chainSourceCore, listenerResult); } } else { _chainForeignFuture(chainSource, listenerResult); } return; } } _Future result = listener.result; listeners = result._removeListeners(); if (!listenerHasError) { result._setValue(listenerValueOrError); } else { AsyncError asyncError = (AsyncError)listenerValueOrError; result._setErrorObject(asyncError); } // Prepare for next round. source = result; } }
internal void _setErrorObject(AsyncError error) { D.assert(!_isComplete); // But may have a completion pending. _state = _stateError; _resultOrListeners = error; }