Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(173)

Unified Diff: pkg/analyzer/lib/src/cancelable_future.dart

Issue 806733003: Make futures returned by AnalysisContext cancelable. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/analyzer/lib/src/cancelable_future.dart
diff --git a/pkg/analyzer/lib/src/cancelable_future.dart b/pkg/analyzer/lib/src/cancelable_future.dart
new file mode 100644
index 0000000000000000000000000000000000000000..34226c4eb1ed4dd27ccfa8f8ffd001f493b25461
--- /dev/null
+++ b/pkg/analyzer/lib/src/cancelable_future.dart
@@ -0,0 +1,230 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library cancelable_future;
+
+import 'dart:async';
+
+/**
+ * Type of callback called when the future returned by a CancelableCompleter
+ * is canceled.
+ */
+typedef void CancelHandler();
+
+class CancelableCompleter<T> implements Completer<T> {
Brian Wilkerson 2014/12/15 19:49:26 I'd like to see doc comments for all of the classe
Paul Berry 2014/12/16 16:58:06 Done.
+ /**
+ * The completer which holds the state of the computation. If the
+ * computation is canceled, this completer will remain in the non-completed
+ * state.
+ */
+ final Completer<T> _innerCompleter = new Completer<T>.sync();
+
+ /**
+ * The completer which holds the future that is exposed to the client
+ * through [future]. If the computation is canceled, this completer will
+ * be completed with a FutureCanceledError.
+ */
+ final Completer<T> _outerCompleter = new Completer<T>();
+
+ /**
+ * The callback to invoke if the 'cancel' method is called on the future
+ * returned by [future]. This callback will only be invoked if the future
+ * is canceled before being completed.
+ */
+ final CancelHandler _onCancel;
+
+ _CancelableCompleterFuture<T> _future;
+
+ /**
+ * Create a CancelableCompleter that will invoke the given callback
+ * synchronously if its future is canceled. The callback will not be
+ * invoked if the future is completed before being canceled.
Brian Wilkerson 2014/12/15 19:49:26 And the future will be completed with an error bef
+ */
+ CancelableCompleter(this._onCancel) {
+ _future = new _CancelableCompleterFuture<T>(this);
+
+ // When the client completes the inner completer, we need to check whether
+ // the outer completer has been completed. If it has, then the operation
+ // was canceled before it finished, and it's too late to un-cancel it, so
+ // we just ignore the result from the inner completer. If it hasn't, then
+ // we simply pass along the result from the inner completer to the outer
+ // completer.
+ //
+ // Note that the reason it is safe for the inner completer to be
+ // synchronous is that we don't expose its future to client code, and we
+ // only use it to complete the outer completer (which is asynchronous).
+ _innerCompleter.future.then((T value) {
+ if (!_outerCompleter.isCompleted) {
+ _outerCompleter.complete(value);
+ }
+ }, onError: (Object error, StackTrace stackTrace) {
+ if (!_outerCompleter.isCompleted) {
+ _outerCompleter.completeError(error, stackTrace);
+ }
+ });
+ }
+
+ @override
+ CancelableFuture<T> get future => _future;
+
+ @override
+ bool get isCompleted => _innerCompleter.isCompleted;
+
+ @override
+ void complete([value]) {
+ _innerCompleter.complete(value);
+ }
+
+ @override
+ void completeError(Object error, [StackTrace stackTrace]) {
+ _innerCompleter.completeError(error, stackTrace);
+ }
+
+ void _cancel() {
+ if (!_outerCompleter.isCompleted) {
+ _outerCompleter.completeError(new FutureCanceledError());
+ _onCancel();
+ }
+ }
+}
+
+/**
+ * An object representing a delayed computation that can be canceled.
+ */
+abstract class CancelableFuture<T> implements Future<T> {
+ /**
+ * A CancelableFuture containing the result of calling [computation]
+ * asynchronously. Since the computation is started without delay, calling
+ * the future's cancel method will have no effect.
+ */
+ factory CancelableFuture(computation()) =>
+ new _WrappedFuture<T>(new Future<T>(computation));
+
+ /**
+ * A CancelableFuture containing the result of calling [computation] after
+ * [duration] has passed.
+ *
+ * TODO(paulberry): if the future is canceled before the duration has
+ * elapsed, the computation should not be performed.
+ */
+ factory CancelableFuture.delayed(Duration duration, [computation()]) =>
+ new _WrappedFuture<T>(new Future<T>.delayed(duration, computation));
+
+ /**
+ * A CancelableFuture that completes with error. Since the future is
+ * completed without delay, calling the future's cancel method will have no
+ * effect.
+ */
+ factory CancelableFuture.error(Object error, [StackTrace stackTrace]) =>
+ new _WrappedFuture<T>(new Future<T>.error(error, stackTrace));
+
+ /**
+ * A CancelableFuture containing the result of calling [computation]
+ * asynchronously with scheduleMicrotask. Since the computation is started
+ * without delay, calling the future's cancel method will have no effect.
+ */
+ factory CancelableFuture.microtask(computation()) =>
+ new _WrappedFuture<T>(new Future<T>.microtask(computation));
+
+ /**
+ * A CancelableFuture containing the result of immediately calling
+ * [computation]. Since the computation is started without delay, calling
+ * the future's cancel method will have no effect.
+ */
+ factory CancelableFuture.sync(computation()) =>
+ new _WrappedFuture<T>(new Future<T>.sync(computation));
+
+ /**
+ * A CancelableFuture whose value is available in the next event-loop
+ * iteration. Since the value is available without delay, calling the
+ * future's cancel method will have no effect.
+ */
+ factory CancelableFuture.value([value]) =>
+ new _WrappedFuture<T>(new Future<T>.value(value));
+
+ /**
+ * If the delayed computation has not yet completed, attempt to cancel it.
+ * Note that the cancellation is not always possible. If the computation
+ * could be canceled, the future is completed with a FutureCanceledError.
+ * Otherwise it will behave as though cancel() was not called.
+ *
+ * Note that attempting to cancel a future that has already completed will
+ * never succeed--futures that have already completed retain their final
+ * state forever.
+ */
+ void cancel();
+}
+
+class FutureCanceledError {
+}
+
+class _CancelableCompleterFuture<T> implements CancelableFuture<T> {
+ final CancelableCompleter<T> _completer;
+
+ _CancelableCompleterFuture(this._completer);
+
+ @override
+ Stream<T> asStream() {
+ // TODO(paulberry): Implement this in such a way that
+ // StreamSubscription.cancel() cancels the future.
+ return _completer._outerCompleter.future.asStream();
+ }
+
+ @override
+ void cancel() {
+ _completer._cancel();
+ }
+
+ @override
+ Future catchError(Function onError, {bool test(Object error)}) =>
+ _completer._outerCompleter.future.catchError(onError, test: test);
+
+ @override
+ Future then(onValue(T value), {Function onError}) =>
+ _completer._outerCompleter.future.then(onValue, onError: onError);
+
+ @override
+ Future timeout(Duration timeLimit, {onTimeout()}) {
+ // TODO(paulberry): Implement this in such a way that a timeout cancels
+ // the future.
+ return _completer._outerCompleter.future.timeout(
+ timeLimit,
+ onTimeout: onTimeout);
+ }
+
+ @override
+ Future<T> whenComplete(action()) =>
+ _completer._outerCompleter.future.whenComplete(action);
+}
+
+/**
+ * A CancelableFuture that wraps an ordinary Future. Attempting to cancel a
+ * _WrappedFuture has no effect.
+ */
+class _WrappedFuture<T> implements CancelableFuture<T> {
+ final Future<T> _future;
+
+ _WrappedFuture(this._future);
+
+ @override
+ Stream asStream() => _future.asStream();
+
+ @override
+ void cancel() {}
+
+ @override
+ Future catchError(Function onError, {bool test(Object error)}) =>
+ _future.catchError(onError, test: test);
+
+ @override
+ Future then(onValue(value), {Function onError}) =>
+ _future.then(onValue, onError: onError);
+
+ @override
+ Future timeout(Duration timeLimit, {onTimeout()}) =>
+ _future.timeout(timeLimit, onTimeout: onTimeout);
+
+ @override
+ Future whenComplete(action()) => _future.whenComplete(action);
+}
« no previous file with comments | « no previous file | pkg/analyzer/lib/src/generated/engine.dart » ('j') | pkg/analyzer/test/generated/engine_test.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698