blob: 9f0cafff9e17d2e7a21b9ba0f101f081de5a1223 [file] [log] [blame]
// Copyright 2012 Google Inc. All Rights Reserved.
// Dart core library.
class FutureImpl<T> implements Future<T> {
bool _isComplete = false;
/**
* Value that was provided to this Future by the Completer
*/
T _value;
/**
* Exception that occured, if there was a problem providing
* Value.
*/
Object _exception;
/**
* Stack trace associated with [_exception], if one was provided.
*/
Object _stackTrace;
/**
* true, if any onException handler handled the exception.
*/
bool _exceptionHandled = false;
/**
* Listeners waiting to receive the value of this future.
*/
final List<Function> _successListeners;
/**
* Exception handlers waiting for exceptions.
*/
final List<Function> _exceptionHandlers;
/**
* Listeners waiting to be called when the future completes.
*/
final List<Function> _completionListeners;
FutureImpl()
: _successListeners = [],
_exceptionHandlers = [],
_completionListeners = [];
factory FutureImpl.immediate(T value) {
final res = new FutureImpl();
res._setValue(value);
return res;
}
T get value {
if (!isComplete) {
throw new FutureNotCompleteException();
}
if (_exception !== null) {
throw _exception;
}
return _value;
}
Object get exception {
if (!isComplete) {
throw new FutureNotCompleteException();
}
return _exception;
}
Object get stackTrace {
if (!isComplete) {
throw new FutureNotCompleteException();
}
return _stackTrace;
}
bool get isComplete {
return _isComplete;
}
bool get hasValue {
return isComplete && _exception === null;
}
void then(void onSuccess(T value)) {
if (hasValue) {
onSuccess(value);
} else if (!isComplete) {
_successListeners.add(onSuccess);
} else if (!_exceptionHandled) {
throw _exception;
}
}
void handleException(bool onException(Object exception)) {
if (_exceptionHandled) return;
if (_isComplete) {
if (_exception != null) {
_exceptionHandled = onException(_exception);
}
} else {
_exceptionHandlers.add(onException);
}
}
void onComplete(void complete(Future<T> future)) {
if (_isComplete) {
try {
complete(this);
} catch (e) {}
} else {
_completionListeners.add(complete);
}
}
void _complete() {
_isComplete = true;
try {
if (_exception !== null) {
for (Function handler in _exceptionHandlers) {
// Explicitly check for true here so that if the handler returns null,
// we don't get an exception in checked mode.
if (handler(_exception) == true) {
_exceptionHandled = true;
break;
}
}
}
if (hasValue) {
for (Function listener in _successListeners) {
listener(value);
}
} else {
if (!_exceptionHandled && _successListeners.length > 0) {
throw _exception;
}
}
} finally {
for (Function listener in _completionListeners) {
try {
listener(this);
} catch (e) {}
}
}
}
void _setValue(T value) {
if (_isComplete) {
throw new FutureAlreadyCompleteException();
}
_value = value;
_complete();
}
void _setException(Object exception, Object stackTrace) {
if (exception === null) {
// null is not a legal value for the exception of a Future.
throw new ArgumentError(null);
}
if (_isComplete) {
throw new FutureAlreadyCompleteException();
}
_exception = exception;
_stackTrace = stackTrace;
_complete();
}
Future transform(Function transformation) {
final completer = new Completer();
_forwardException(this, completer);
then((v) {
var transformed = null;
try {
transformed = transformation(v);
} catch (e, stackTrace) {
completer.completeException(e, stackTrace);
return;
}
completer.complete(transformed);
});
return completer.future;
}
Future chain(Function transformation) {
final completer = new Completer();
_forwardException(this, completer);
then((v) {
var future = null;
try {
future = transformation(v);
} catch (ex, stackTrace) {
completer.completeException(ex, stackTrace);
return;
}
_forward(future, completer);
});
return completer.future;
}
Future transformException(transformation(Object exception)) {
final completer = new Completer();
handleException((ex) {
try {
final result = transformation(ex);
// If the transformation itself returns a future, then we will
// complete to what that completes to.
if (result is Future) {
_forward(result, completer);
} else {
completer.complete(result);
}
} catch (innerException, stackTrace) {
completer.completeException(innerException, stackTrace);
}
return true;
});
then(completer.complete);
return completer.future;
}
/**
* Forwards the success or error completion from [future] to [completer].
*/
_forward(Future future, Completer completer) {
_forwardException(future, completer);
future.then(completer.complete);
}
/**
* Forwards the exception completion from [future] to [completer].
*/
_forwardException(Future future, Completer completer) {
future.handleException((e) {
completer.completeException(e, future.stackTrace);
return true;
});
}
}
class CompleterImpl<T> implements Completer<T> {
final FutureImpl<T> _futureImpl;
CompleterImpl() : _futureImpl = new FutureImpl() {}
Future<T> get future {
return _futureImpl;
}
void complete(T value) {
_futureImpl._setValue(value);
}
void completeException(Object exception, [Object stackTrace]) {
_futureImpl._setException(exception, stackTrace);
}
}