Skip to content

Instantly share code, notes, and snippets.

Created February 23, 2018 22:50
Show Gist options
  • Save anonymous/3ac10128b3e6dc5b7dedc20f250babd5 to your computer and use it in GitHub Desktop.
Save anonymous/3ac10128b3e6dc5b7dedc20f250babd5 to your computer and use it in GitHub Desktop.
red-block-7846
import 'dart:async';
main() {
var completer = new SafeCompleter();
completer.complete('foo');
completer.getFuture().then((val) => print('Complete! $val'));
}
class SafeCompleter<T> {
bool _getFutureCalled = false;
Completer<T> _completer = new Completer<T>();
bool get isCompleted => _completer == null ? true : _completer.isCompleted;
void complete([FutureOr<T> value]) {
if (_completer == null) {
throw new StateError('Future already completed');
}
_completer.complete(value);
}
void completeError(Object error, [StackTrace stackTrace]) {
if (_completer == null) {
throw new StateError('Future already completed');
}
_completer.completeError(error, stackTrace);
}
/// Returns the future that will contain the result provided to this completer.
///
/// This method can only be called once for this instance; subsequent calls will throw a [StateError].
///
/// This restriction prevents this completer from leaking the completed value or errors,
/// while still allowing users to check [isCompleted].
Future<T> getFuture() {
if (_getFutureCalled) {
throw new StateError('getFuture can only be called once; the Future is no longer available');
}
_getFutureCalled = true;
_completer.future.then((_) {
_completer = null;
});
// TODO: this may be annoying in practice, but would help prevent leaks caused by getFuture never being called.
// TODO: Is there a better way to check this? Is it even necessary to protect against this case?
// This does not cause issues if `.getFuture()` is called after `.complete()`
// but within the same tick, due to the async nature of `.complete`.
assert(_completer == null || !_completer.isCompleted,
'getFuture must be called before the completer completes');
return _completer.future;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment