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

Side by Side Diff: analyzer/lib/src/cancelable_future.dart

Issue 1400473008: Roll Observatory packages and add a roll script (Closed) Base URL: git@github.com:dart-lang/observatory_pub_packages.git@master
Patch Set: Created 5 years, 2 months 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 unified diff | Download patch
« no previous file with comments | « analyzer/lib/source/sdk_ext.dart ('k') | analyzer/lib/src/context/cache.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 library cancelable_future;
6
7 import 'dart:async';
8
9 /**
10 * Type of callback called when the future returned by a CancelableCompleter
11 * is canceled.
12 */
13 typedef void CancelHandler();
14
15 /**
16 * A way to produce [CancelableFuture] objects and to complete them later with
17 * a value or error.
18 *
19 * This class behaves like the standard library [Completer] class, except that
20 * its [future] getter returns a [CancelableFuture].
21 *
22 * If the future is canceled before being completed, the [CancelHandler] which
23 * was passed to the constructor is invoked, and any further attempt to
24 * complete the future has no effect. For example, in the following code:
25 *
26 * main() {
27 * var cc = new CancelableCompleter(() {
28 * print('cancelled'); // (2)
29 * });
30 * cc.future.then((value) {
31 * print('completed with value $value');
32 * }, onError: (error) {
33 * print('completed with error $error'); // (3)
34 * });
35 * cc.future.cancel(); // (1)
36 * }
37 *
38 * The call at (1) causes (2) to be invoked immediately. (3) will be invoked
39 * later (on a microtask), with an error that is an instance of
40 * [FutureCanceledError].
41 *
42 * Note that since the closure passed to then() is executed on a microtask,
43 * there is a short window of time between the call to [complete] and the
44 * client being informed that the future has completed. During this window,
45 * any attempt to cancel the future will have no effect. For example, in the
46 * following code:
47 *
48 * main() {
49 * var cc = new CancelableCompleter(() {
50 * print('cancelled'); // (3)
51 * });
52 * cc.future.then((value) {
53 * print('completed with value $value'); // (4)
54 * }, onError: (error) {
55 * print('completed with error $error');
56 * });
57 * cc.complete(100); // (1)
58 * cc.future.cancel(); // (2)
59 * }
60 *
61 * The call at (1) will place the completer in the "completed" state, so the
62 * call at (2) will have no effect (in particular, (3) won't ever execute).
63 * Later, (4) will be invoked on a microtask.
64 */
65 class CancelableCompleter<T> implements Completer<T> {
66 /**
67 * The completer which holds the state of the computation. If the
68 * computation is canceled, this completer will remain in the non-completed
69 * state.
70 */
71 final Completer<T> _innerCompleter = new Completer<T>.sync();
72
73 /**
74 * The completer which holds the future that is exposed to the client
75 * through [future]. If the computation is canceled, this completer will
76 * be completed with a FutureCanceledError.
77 */
78 final Completer<T> _outerCompleter = new Completer<T>();
79
80 /**
81 * The callback to invoke if the 'cancel' method is called on the future
82 * returned by [future]. This callback will only be invoked if the future
83 * is canceled before being completed.
84 */
85 final CancelHandler _onCancel;
86
87 _CancelableCompleterFuture<T> _future;
88
89 /**
90 * Create a CancelableCompleter that will invoke the given callback
91 * synchronously if its future is canceled. The callback will not be
92 * invoked if the future is completed before being canceled.
93 */
94 CancelableCompleter(this._onCancel) {
95 _future = new _CancelableCompleterFuture<T>(this);
96
97 // When the client completes the inner completer, we need to check whether
98 // the outer completer has been completed. If it has, then the operation
99 // was canceled before it finished, and it's too late to un-cancel it, so
100 // we just ignore the result from the inner completer. If it hasn't, then
101 // we simply pass along the result from the inner completer to the outer
102 // completer.
103 //
104 // Note that the reason it is safe for the inner completer to be
105 // synchronous is that we don't expose its future to client code, and we
106 // only use it to complete the outer completer (which is asynchronous).
107 _innerCompleter.future.then((T value) {
108 if (!_outerCompleter.isCompleted) {
109 _outerCompleter.complete(value);
110 }
111 }, onError: (Object error, StackTrace stackTrace) {
112 if (!_outerCompleter.isCompleted) {
113 _outerCompleter.completeError(error, stackTrace);
114 }
115 });
116 }
117
118 /**
119 * The [CancelableFuture] that will contain the result provided to this
120 * completer.
121 */
122 @override
123 CancelableFuture<T> get future => _future;
124
125 /**
126 * Whether the future has been completed. This is independent of whether
127 * the future has been canceled.
128 */
129 @override
130 bool get isCompleted => _innerCompleter.isCompleted;
131
132 /**
133 * Complete [future] with the supplied value. If the future has previously
134 * been canceled, this will have no effect on [future], however it will
135 * still set [isCompleted] to true.
136 */
137 @override
138 void complete([value]) {
139 _innerCompleter.complete(value);
140 }
141
142 /**
143 * Complete [future] with an error. If the future has previously been
144 * canceled, this will have no effect on [future], however it will still set
145 * [isCompleted] to true.
146 */
147 @override
148 void completeError(Object error, [StackTrace stackTrace]) {
149 _innerCompleter.completeError(error, stackTrace);
150 }
151
152 void _cancel() {
153 if (!_outerCompleter.isCompleted) {
154 _outerCompleter.completeError(new FutureCanceledError());
155 _onCancel();
156 }
157 }
158 }
159
160 /**
161 * An object representing a delayed computation that can be canceled.
162 */
163 abstract class CancelableFuture<T> implements Future<T> {
164 /**
165 * A CancelableFuture containing the result of calling [computation]
166 * asynchronously. Since the computation is started without delay, calling
167 * the future's cancel method will have no effect.
168 */
169 factory CancelableFuture(computation()) =>
170 new _WrappedFuture<T>(new Future<T>(computation));
171
172 /**
173 * A CancelableFuture containing the result of calling [computation] after
174 * [duration] has passed.
175 *
176 * TODO(paulberry): if the future is canceled before the duration has
177 * elapsed, the computation should not be performed.
178 */
179 factory CancelableFuture.delayed(Duration duration, [computation()]) =>
180 new _WrappedFuture<T>(new Future<T>.delayed(duration, computation));
181
182 /**
183 * A CancelableFuture that completes with error. Since the future is
184 * completed without delay, calling the future's cancel method will have no
185 * effect.
186 */
187 factory CancelableFuture.error(Object error, [StackTrace stackTrace]) =>
188 new _WrappedFuture<T>(new Future<T>.error(error, stackTrace));
189
190 /**
191 * A CancelableFuture containing the result of calling [computation]
192 * asynchronously with scheduleMicrotask. Since the computation is started
193 * without delay, calling the future's cancel method will have no effect.
194 */
195 factory CancelableFuture.microtask(computation()) =>
196 new _WrappedFuture<T>(new Future<T>.microtask(computation));
197
198 /**
199 * A CancelableFuture containing the result of immediately calling
200 * [computation]. Since the computation is started without delay, calling
201 * the future's cancel method will have no effect.
202 */
203 factory CancelableFuture.sync(computation()) =>
204 new _WrappedFuture<T>(new Future<T>.sync(computation));
205
206 /**
207 * A CancelableFuture whose value is available in the next event-loop
208 * iteration. Since the value is available without delay, calling the
209 * future's cancel method will have no effect.
210 */
211 factory CancelableFuture.value([value]) =>
212 new _WrappedFuture<T>(new Future<T>.value(value));
213
214 /**
215 * If the delayed computation has not yet completed, attempt to cancel it.
216 * Note that the cancellation is not always possible. If the computation
217 * could be canceled, the future is completed with a FutureCanceledError.
218 * Otherwise it will behave as though cancel() was not called.
219 *
220 * Note that attempting to cancel a future that has already completed will
221 * never succeed--futures that have already completed retain their final
222 * state forever.
223 */
224 void cancel();
225 }
226
227 /**
228 * Error which is used to complete any [CancelableFuture] which has been
229 * successfully canceled by calling its 'cancel' method.
230 */
231 class FutureCanceledError {}
232
233 class _CancelableCompleterFuture<T> implements CancelableFuture<T> {
234 final CancelableCompleter<T> _completer;
235
236 _CancelableCompleterFuture(this._completer);
237
238 @override
239 Stream<T> asStream() {
240 // TODO(paulberry): Implement this in such a way that
241 // StreamSubscription.cancel() cancels the future.
242 return _completer._outerCompleter.future.asStream();
243 }
244
245 @override
246 void cancel() {
247 _completer._cancel();
248 }
249
250 @override
251 Future catchError(Function onError, {bool test(Object error)}) =>
252 _completer._outerCompleter.future.catchError(onError, test: test);
253
254 @override
255 Future then(onValue(T value), {Function onError}) =>
256 _completer._outerCompleter.future.then(onValue, onError: onError);
257
258 @override
259 Future timeout(Duration timeLimit, {onTimeout()}) {
260 // TODO(paulberry): Implement this in such a way that a timeout cancels
261 // the future.
262 return _completer._outerCompleter.future.timeout(timeLimit,
263 onTimeout: onTimeout);
264 }
265
266 @override
267 Future<T> whenComplete(action()) =>
268 _completer._outerCompleter.future.whenComplete(action);
269 }
270
271 /**
272 * A CancelableFuture that wraps an ordinary Future. Attempting to cancel a
273 * _WrappedFuture has no effect.
274 */
275 class _WrappedFuture<T> implements CancelableFuture<T> {
276 final Future<T> _future;
277
278 _WrappedFuture(this._future);
279
280 @override
281 Stream<T> asStream() => _future.asStream();
282
283 @override
284 void cancel() {}
285
286 @override
287 Future catchError(Function onError, {bool test(Object error)}) =>
288 _future.catchError(onError, test: test);
289
290 @override
291 Future then(onValue(value), {Function onError}) =>
292 _future.then(onValue, onError: onError);
293
294 @override
295 Future timeout(Duration timeLimit, {onTimeout()}) =>
296 _future.timeout(timeLimit, onTimeout: onTimeout);
297
298 @override
299 Future<T> whenComplete(action()) => _future.whenComplete(action);
300 }
OLDNEW
« no previous file with comments | « analyzer/lib/source/sdk_ext.dart ('k') | analyzer/lib/src/context/cache.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698