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

440 行
16 KiB

using System;
using System.Collections.Generic;
using Unity.UIWidgets.widgets;
namespace Unity.UIWidgets.async {
public struct FutureOr {
public object v;
public Future f;
public bool isFuture => f != null;
public static FutureOr value(object value) {
return new FutureOr {v = value};
}
public static FutureOr future(Future future) {
return new FutureOr {f = future};
}
public static readonly FutureOr nil = value(null);
public static implicit operator FutureOr(Future f) => future(f);
public static implicit operator FutureOr(bool v) => value(v);
public static implicit operator FutureOr(int v) => value(v);
public static implicit operator FutureOr(long v) => value(v);
public static implicit operator FutureOr(float v) => value(v);
public static implicit operator FutureOr(double v) => value(v);
public static implicit operator FutureOr(string v) => value(v);
public static implicit operator FutureOr(byte[] v) => value(v);
public static implicit operator FutureOr(RoutePopDisposition v) => value(v);
public static implicit operator FutureOr(Dictionary<Type, object> v) => value(v);
}
public abstract class Future {
internal static readonly _Future _nullFuture = _Future.zoneValue(null, Zone.root);
internal static readonly _Future _falseFuture = _Future.zoneValue(false, Zone.root);
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 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 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 static Future value(FutureOr value = default) {
return _Future.immediate(value);
}
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);
}
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;
}
public static Future wait<T>(IEnumerable<Future> futures, bool eagerError = false, Action<T> cleanUp = null) {
_Future result = new _Future();
List<T> values = null; // Collects the values. Set to null on error.
int remaining = 0; // How many futures are we waiting for.
Exception error = null; // The first error from a future.
Func<Exception, FutureOr> handleError = (Exception theError) => {
remaining--;
if (values != null) {
if (cleanUp != null) {
foreach (var value in values) {
if (value != null) {
// Ensure errors from cleanUp are uncaught.
sync(() => {
cleanUp(value);
return FutureOr.nil;
});
}
}
}
values = null;
if (remaining == 0 || eagerError) {
result._completeError(theError);
}
else {
error = theError;
}
}
else if (remaining == 0 && !eagerError) {
result._completeError(error);
}
return FutureOr.nil;
};
try {
// As each future completes, put its value into the corresponding
// position in the list of values.
foreach (var future in futures) {
int pos = remaining;
future.then((object value) => {
remaining--;
if (values != null) {
values[pos] = (T)value;
if (remaining == 0) {
result._completeWithValue(values);
}
}
else {
if (cleanUp != null && value != null) {
// Ensure errors from cleanUp are uncaught.
sync(() => {
cleanUp((T) value);
return FutureOr.nil;
});
}
if (remaining == 0 && !eagerError) {
result._completeError(error);
}
}
return FutureOr.nil;
}, onError: handleError);
// Increment the 'remaining' after the call to 'then'.
// If that call throws, we don't expect any future callback from
// the future, and we also don't increment remaining.
remaining++;
}
if (remaining == 0) {
return value(FutureOr.value(new List<T>()));
}
values = new List<T>(new T[remaining]);
}
catch (Exception e) {
// The error must have been thrown while iterating over the futures
// list, or while installing a callback handler on the future.
if (remaining == 0 || eagerError) {
// Throw a new Future.error.
// Don't just call `result._completeError` since that would propagate
// the error too eagerly, not giving the callers time to install
// error handlers.
// Also, don't use `_asyncCompleteError` since that one doesn't give
// zones the chance to intercept the error.
return Future.error(e);
}
else {
// Don't allocate a list for values, thus indicating that there was an
// error.
// Set error to the caught exception.
error = e;
}
}
return result;
}
public static Future any(IEnumerable<Future> futures) {
var completer = Completer.sync();
Func<object, FutureOr> onValue = (object value) => {
if (!completer.isCompleted) completer.complete(FutureOr.value(value));
return FutureOr.nil;
};
Func<Exception, FutureOr> onError = (Exception error) => {
if (!completer.isCompleted) completer.completeError(error);
return FutureOr.nil;
};
foreach (var future in futures) {
future.then(onValue, onError: onError);
}
return completer.future;
}
public static Future forEach<T>(IEnumerable<T> elements, Func<T, FutureOr> action) {
var iterator = elements.GetEnumerator();
return doWhile(() => {
if (!iterator.MoveNext()) return false;
var result = action(iterator.Current);
if (result.isFuture) return FutureOr.future(result.f.then(_kTrue));
return true;
});
}
static readonly Func<object, FutureOr> _kTrue = (_) => true;
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;
}
public abstract Future then(Func<object, FutureOr> onValue, Func<Exception, FutureOr> onError = null);
public Future then(Action<object> onValue, Func<Exception, FutureOr> onError = null) {
return then(v => {
onValue(v);
return FutureOr.nil;
}, onError);
}
public abstract Future catchError(Func<Exception, FutureOr> onError, Func<Exception, bool> test = null);
public Future catchError(Action<Exception> onError, Func<Exception, bool> test = null) {
return catchError(e => {
onError(e);
return FutureOr.nil;
}, test);
}
public abstract Future whenComplete(Func<FutureOr> action);
public Future whenComplete(Action action) {
return whenComplete(() => {
action();
return FutureOr.nil;
});
}
// public abstract Stream asStream();
public abstract Future timeout(TimeSpan timeLimit, Func<FutureOr> onTimeout = null);
public Future<T> to<T>() {
if (this is Future<T>) {
return (Future<T>) this;
}
return new Future<T>(this);
}
}
public class Future<T> : Future {
readonly Future _future;
public Future(Future future) {
_future = future;
}
public override Future then(Func<object, FutureOr> onValue, Func<Exception, FutureOr> onError = null) {
return _future.then(onValue, onError);
}
public Future then_(Func<T, FutureOr> onValue, Func<Exception, FutureOr> onError = null) {
return _future.then(obj => onValue((T) obj), onError);
}
public Future<R> then_<R>(Func<T, FutureOr> onValue, Func<Exception, FutureOr> onError = null) {
return _future.then(obj => onValue((T) obj), onError).to<R>();
}
public Future then_(Action<T> onValue, Func<Exception, FutureOr> onError = null) {
return _future.then(obj => onValue((T) obj), onError);
}
public override Future catchError(Func<Exception, FutureOr> onError, Func<Exception, bool> test = null) {
return _future.catchError(onError, test);
}
public override Future whenComplete(Func<FutureOr> action) {
return _future.whenComplete(action);
}
public override Future timeout(TimeSpan timeLimit, Func<FutureOr> onTimeout = null) {
return _future.timeout(timeLimit, onTimeout);
}
}
public class TimeoutException : Exception {
public readonly TimeSpan? duration;
public TimeoutException(string message, TimeSpan? duration = null) : base(message) {
this.duration = duration;
}
public override string ToString() {
string result = "TimeoutException";
if (duration != null) result = $"TimeoutException after {duration}";
if (Message != null) result = $"result: {Message}";
return result;
}
}
public abstract class Completer {
public static Completer create() => new _AsyncCompleter();
public static Completer sync() => new _SyncCompleter();
public abstract Future future { get; }
public abstract void complete(FutureOr value = default);
public abstract void completeError(Exception error);
public abstract bool isCompleted { get; }
}
public static partial class async_ {
internal static void _completeWithErrorCallback(_Future result, Exception error) {
AsyncError replacement = Zone.current.errorCallback(error);
if (replacement != null) {
error = _nonNullError(replacement.InnerException);
}
result._completeError(error);
}
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 Exception _nonNullError(Exception error) =>
error ?? new Exception("Throw of null.");
}
}