您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 
 

817 行
31 KiB

using System;
using Unity.UIWidgets.foundation;
namespace Unity.UIWidgets.async {
using _FutureOnValue = Func<object, FutureOr>;
using _FutureErrorTest = Func<Exception, bool>;
using _FutureAction = Func<FutureOr>;
abstract class _Completer : Completer {
protected readonly _Future _future = new _Future();
public override Future future => _future;
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);
}
protected abstract void _completeError(Exception error);
public override bool isCompleted => !_future._mayComplete;
}
class _AsyncCompleter : _Completer {
public override void complete(FutureOr value = default) {
if (!_future._mayComplete) throw new Exception("Future already completed");
_future._asyncComplete(value);
}
protected override void _completeError(Exception error) {
_future._asyncCompleteError(error);
}
}
class _SyncCompleter : _Completer {
public override void complete(FutureOr value = default) {
if (!_future._mayComplete) throw new Exception("Future already completed");
_future._complete(value);
}
protected override void _completeError(Exception error) {
_future._completeError(error);
}
}
class _FutureListener {
public const int maskValue = 1;
public const int maskError = 2;
public const int maskTestError = 4;
public const int maskWhencomplete = 8;
public const int stateChain = 0;
public const int stateThen = maskValue;
public const int stateThenOnerror = maskValue | maskError;
public const int stateCatcherror = maskError;
public const int stateCatcherrorTest = maskError | maskTestError;
public const int stateWhencomplete = maskWhencomplete;
public const int maskType = maskValue | maskError | maskTestError | maskWhencomplete;
public const int stateIsAwait = 16;
internal _FutureListener _nextListener;
public readonly _Future result;
public readonly int state;
public readonly Delegate callback;
public readonly Func<Exception, FutureOr> errorCallback;
_FutureListener(_Future result, Delegate callback, Func<Exception, FutureOr> errorCallback, int state) {
this.result = result;
this.state = state;
this.callback = callback;
this.errorCallback = errorCallback;
}
public static _FutureListener then(
_Future result, _FutureOnValue onValue, Func<Exception, FutureOr> errorCallback) {
return new _FutureListener(
result, onValue, errorCallback,
(errorCallback == null) ? stateThen : stateThenOnerror
);
}
public static _FutureListener thenAwait(
_Future result, _FutureOnValue onValue, Func<Exception, FutureOr> errorCallback) {
return new _FutureListener(
result, onValue, errorCallback,
((errorCallback == null) ? stateThen : stateThenOnerror) | stateIsAwait
);
}
public static _FutureListener catchError(_Future result, Func<Exception, FutureOr> errorCallback,
_FutureErrorTest callback) {
return new _FutureListener(
result, callback, errorCallback,
(callback == null) ? stateCatcherror : stateCatcherrorTest
);
}
public static _FutureListener whenComplete(_Future result, _FutureAction callback) {
return new _FutureListener(
result, callback, null,
stateWhencomplete
);
}
internal Zone _zone => result._zone;
public bool handlesValue => (state & maskValue) != 0;
public bool handlesError => (state & maskError) != 0;
public bool hasErrorTest => (state & maskType) == stateCatcherrorTest;
public bool handlesComplete => (state & maskType) == stateWhencomplete;
public bool isAwait => (state & stateIsAwait) != 0;
internal _FutureOnValue _onValue {
get {
D.assert(handlesValue);
return (_FutureOnValue) callback;
}
}
internal Func<Exception, FutureOr> _onError => errorCallback;
internal _FutureErrorTest _errorTest {
get {
D.assert(hasErrorTest);
return (_FutureErrorTest) callback;
}
}
internal _FutureAction _whenCompleteAction {
get {
D.assert(handlesComplete);
return (_FutureAction) callback;
}
}
public bool hasErrorCallback {
get {
D.assert(handlesError);
return _onError != null;
}
}
public FutureOr handleValue(object sourceResult) {
return (FutureOr) _zone.runUnary(arg => _onValue(arg), sourceResult);
}
public bool matchesErrorTest(AsyncError asyncError) {
if (!hasErrorTest) return true;
return (bool) _zone.runUnary(arg => _errorTest((Exception) arg), asyncError.InnerException);
}
public FutureOr handleError(AsyncError asyncError) {
D.assert(handlesError && hasErrorCallback);
var errorCallback = this.errorCallback;
return (FutureOr) _zone.runUnary(arg => errorCallback((Exception) arg), asyncError.InnerException);
}
public FutureOr handleWhenComplete() {
D.assert(!handlesError);
return (FutureOr) _zone.run(() => _whenCompleteAction());
}
}
public class _Future : Future {
internal const int _stateIncomplete = 0;
internal const int _statePendingComplete = 1;
internal const int _stateChained = 2;
internal const int _stateValue = 4;
internal const int _stateError = 8;
internal int _state = _stateIncomplete;
internal readonly Zone _zone;
internal object _resultOrListeners;
internal _Future() {
_zone = Zone.current;
}
internal _Future(Zone zone) {
_zone = zone;
}
internal static _Future immediate(FutureOr result) {
var future = new _Future(Zone.current);
future._asyncComplete(result);
return future;
}
internal static _Future zoneValue(object value, Zone zone) {
var future = new _Future(zone);
future._setValue(value);
return future;
}
internal static _Future immediateError(Exception error) {
var future = new _Future(Zone.current);
future._asyncCompleteError(error);
return future;
}
internal static _Future value(object value) {
return zoneValue(value, Zone.current);
}
internal bool _mayComplete => _state == _stateIncomplete;
internal bool _isPendingComplete => _state == _statePendingComplete;
internal bool _mayAddListener => _state <= _statePendingComplete;
internal bool _isChained => _state == _stateChained;
internal bool _isComplete => _state >= _stateValue;
internal bool _hasError => _state == _stateError;
internal void _setChained(_Future source) {
D.assert(_mayAddListener);
_state = _stateChained;
_resultOrListeners = source;
}
public override Future then(Func<object, FutureOr> f, Func<Exception, FutureOr> onError = null) {
Zone currentZone = Zone.current;
if (!ReferenceEquals(currentZone, async_._rootZone)) {
f = async_._registerUnaryHandler(f, currentZone);
if (onError != null) {
onError = async_._registerErrorHandler(onError, currentZone);
}
}
_Future result = new _Future();
_addListener(_FutureListener.then(result, f, onError));
return result;
}
public override Future catchError(Func<Exception, FutureOr> onError, Func<Exception, bool> test = null) {
_Future result = new _Future();
if (!ReferenceEquals(result._zone, async_._rootZone)) {
onError = async_._registerErrorHandler(onError, result._zone);
if (test != null) {
test = async_._registerUnaryHandler(test, result._zone);
}
}
_addListener(_FutureListener.catchError(result, onError, test));
return result;
}
public override Future whenComplete(Func<FutureOr> action) {
_Future result = new _Future();
if (!ReferenceEquals(result._zone, async_._rootZone)) {
action = async_._registerHandler(action, result._zone);
}
_addListener(_FutureListener.whenComplete(result, action));
return result;
}
// Stream<T> asStream() => new Stream<T>.fromFuture(this);
internal void _setPendingComplete() {
D.assert(_mayComplete);
_state = _statePendingComplete;
}
internal void _clearPendingComplete() {
D.assert(_isPendingComplete);
_state = _stateIncomplete;
}
internal AsyncError _error {
get {
D.assert(_hasError);
return (AsyncError) _resultOrListeners;
}
}
internal _Future _chainSource {
get {
D.assert(_isChained);
return (_Future) _resultOrListeners;
}
}
internal void _setValue(object value) {
D.assert(!(value is Future || value is FutureOr));
D.assert(!_isComplete); // But may have a completion pending.
_state = _stateValue;
_resultOrListeners = value;
}
internal void _setErrorObject(AsyncError error) {
D.assert(!_isComplete); // But may have a completion pending.
_state = _stateError;
_resultOrListeners = error;
}
internal void _setError(Exception error) {
_setErrorObject(new AsyncError(error));
}
internal void _cloneResult(_Future source) {
D.assert(!_isComplete);
D.assert(source._isComplete);
_state = source._state;
_resultOrListeners = source._resultOrListeners;
}
internal void _addListener(_FutureListener listener) {
D.assert(listener._nextListener == null);
if (_mayAddListener) {
listener._nextListener = (_FutureListener) _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);
}
D.assert(_isComplete);
// Handle late listeners asynchronously.
_zone.scheduleMicrotask(() => {
_propagateToListeners(this, listener);
return null;
});
}
}
void _prependListeners(_FutureListener listeners) {
if (listeners == null) return;
if (_mayAddListener) {
_FutureListener existingListeners = (_FutureListener) _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);
}
D.assert(_isComplete);
listeners = _reverseListeners(listeners);
_zone.scheduleMicrotask(() => {
_propagateToListeners(this, listeners);
return null;
});
}
}
_FutureListener _removeListeners() {
// Reverse listeners before returning them, so the resulting list is in
// subscription order.
D.assert(!_isComplete);
_FutureListener current = (_FutureListener) _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;
}
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;
});
}
}
static void _chainCoreFuture(_Future source, _Future target) {
D.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 = (_FutureListener) target._resultOrListeners;
target._setChained(source);
source._prependListeners(listeners);
}
}
internal void _complete(FutureOr value = default) {
D.assert(!_isComplete);
if (value.isFuture) {
if (value.f is _Future coreFuture) {
_chainCoreFuture(coreFuture, this);
}
else {
_chainForeignFuture(value.f, this);
}
}
else {
_FutureListener listeners = _removeListeners();
_setValue(value.v);
_propagateToListeners(this, listeners);
}
}
internal void _completeWithValue(object value) {
D.assert(!_isComplete);
_FutureListener listeners = _removeListeners();
_setValue(value);
_propagateToListeners(this, listeners);
}
internal void _completeError(Exception error) {
D.assert(!_isComplete);
_FutureListener listeners = _removeListeners();
_setError(error);
_propagateToListeners(this, listeners);
}
internal void _asyncComplete(FutureOr value) {
D.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.isFuture) {
_chainFuture(value.f);
return;
}
_setPendingComplete();
_zone.scheduleMicrotask(() => {
_completeWithValue(value.v);
return null;
});
}
internal void _chainFuture(Future value) {
if (value is _Future future) {
if (future._hasError) {
// Delay completion to allow the user to register callbacks.
_setPendingComplete();
_zone.scheduleMicrotask(() => {
_chainCoreFuture(future, this);
return null;
});
}
else {
_chainCoreFuture(future, this);
}
return;
}
// Just listen on the foreign future. This guarantees an async delay.
_chainForeignFuture(value, this);
}
internal void _asyncCompleteError(Exception error) {
D.assert(!_isComplete);
_setPendingComplete();
_zone.scheduleMicrotask(() => {
_completeError(error);
return null;
});
}
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;
}
}
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 partial class async_ {
internal static Func<object> _registerHandler(Func<object> handler, Zone zone) {
var callback = zone.registerCallback(() => handler());
return () => callback();
}
internal static Func<FutureOr> _registerHandler(Func<FutureOr> handler, Zone zone) {
var callback = zone.registerCallback(() => handler());
return () => (FutureOr) callback();
}
internal static Func<object, FutureOr> _registerUnaryHandler(Func<object, FutureOr> handler, Zone zone) {
var callback = zone.registerUnaryCallback(arg => handler(arg));
return arg => (FutureOr) callback(arg);
}
internal static Func<Exception, bool> _registerUnaryHandler(Func<Exception, bool> handler, Zone zone) {
var callback = zone.registerUnaryCallback(arg => handler((Exception) arg));
return arg => (bool) callback(arg);
}
internal static Func<Exception, FutureOr> _registerErrorHandler(Func<Exception, FutureOr> errorHandler,
Zone zone) {
var callback = zone.registerUnaryCallback(arg => errorHandler((Exception) arg));
return arg => (FutureOr) callback(arg);
}
}
}