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

Side by Side Diff: sdk/lib/async/future_impl.dart

Issue 23926011: Rewrite Futures. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fix bad asserts. Created 7 years, 3 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 | Annotate | Revision Log
« no previous file with comments | « sdk/lib/async/future.dart ('k') | sdk/lib/async/stream.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of dart.async; 5 part of dart.async;
6 6
7 /** The onValue and onError handlers return either a value or a future */
8 typedef dynamic _FutureOnValue<T>(T value);
9 typedef dynamic _FutureOnError(error);
10 /** Test used by [Future.catchError] to handle skip some errors. */
11 typedef bool _FutureErrorTest(var error);
12 /** Used by [WhenFuture]. */
13 typedef _FutureAction();
14
7 abstract class _Completer<T> implements Completer<T> { 15 abstract class _Completer<T> implements Completer<T> {
8 final Future<T> future; 16 final _Future<T> future = new _Future<T>();
9 bool _isComplete = false;
10 17
11 _Completer() : future = new _FutureImpl<T>() { 18 void complete([T value]);
12 _FutureImpl futureImpl = future;
13 futureImpl._zone.expectCallback();
14 }
15 19
16 void _setFutureValue(T value); 20 void completeError(Object error, [Object stackTrace = null]);
17 void _setFutureError(error); 21
22 // The future's _isComplete doesn't take into account pending completions.
23 // We therefore use _mayComplete.
24 bool get isCompleted => !future._mayComplete;
25 }
26
27 class _AsyncCompleter<T> extends _Completer<T> {
18 28
19 void complete([T value]) { 29 void complete([T value]) {
20 if (_isComplete) throw new StateError("Future already completed"); 30 if (!future._mayComplete) throw new StateError("Future already completed");
21 _isComplete = true; 31 future._asyncComplete(value);
22 _FutureImpl futureImpl = future;
23 _setFutureValue(value);
24 } 32 }
25 33
26 void completeError(Object error, [Object stackTrace = null]) { 34 void completeError(Object error, [Object stackTrace = null]) {
27 if (_isComplete) throw new StateError("Future already completed"); 35 if (!future._mayComplete) throw new StateError("Future already completed");
28 _isComplete = true; 36 future._asyncCompleteError(error, stackTrace);
29 if (stackTrace != null) {
30 // Force the stack trace onto the error, even if it already had one.
31 _attachStackTrace(error, stackTrace);
32 }
33 _FutureImpl futureImpl = future;
34 _setFutureError(error);
35 }
36
37 bool get isCompleted => _isComplete;
38 }
39
40 class _AsyncCompleter<T> extends _Completer<T> {
41 void _setFutureValue(T value) {
42 _FutureImpl future = this.future;
43 future._asyncSetValue(value);
44 // The async-error will schedule another callback, so we can cancel
45 // the expectation without shutting down the zone.
46 future._zone.cancelCallbackExpectation();
47 }
48
49 void _setFutureError(error) {
50 _FutureImpl future = this.future;
51 future._asyncSetError(error);
52 // The async-error will schedule another callback, so we can cancel
53 // the expectation without shutting down the zone.
54 future._zone.cancelCallbackExpectation();
55 } 37 }
56 } 38 }
57 39
58 class _SyncCompleter<T> extends _Completer<T> { 40 class _SyncCompleter<T> extends _Completer<T> {
59 void _setFutureValue(T value) { 41
60 _FutureImpl future = this.future; 42 void complete([T value]) {
61 future._setValue(value); 43 if (!future._mayComplete) throw new StateError("Future already completed");
62 future._zone.cancelCallbackExpectation(); 44 future._complete(value);
63 } 45 }
64 46
65 void _setFutureError(error) { 47 void completeError(Object error, [Object stackTrace = null]) {
66 _FutureImpl future = this.future; 48 if (!future._mayComplete) throw new StateError("Future already completed");
67 future._setError(error); 49 future._completeError(error, stackTrace);
68 future._zone.cancelCallbackExpectation();
69 } 50 }
70 } 51 }
71 52
72 /** 53 class _Future<T> implements Future<T> {
73 * A listener on a future.
74 *
75 * When the future completes, the [_sendValue] or [_sendError] method
76 * is invoked with the result.
77 *
78 * Listeners are kept in a linked list.
79 */
80 abstract class _FutureListener<T> {
81 _FutureListener _nextListener;
82 factory _FutureListener.wrap(_FutureImpl future) {
83 return new _FutureListenerWrapper(future);
84 }
85 void _sendValue(T value);
86 void _sendError(error);
87
88 bool _inSameErrorZone(_Zone otherZone);
89 }
90
91 /** Adapter for a [_FutureImpl] to be a future result listener. */
92 class _FutureListenerWrapper<T> implements _FutureListener<T> {
93 _FutureImpl future;
94 _FutureListener _nextListener;
95 _FutureListenerWrapper(this.future);
96 _sendValue(T value) { future._setValueUnchecked(value); }
97 _sendError(error) { future._setErrorUnchecked(error); }
98 bool _inSameErrorZone(_Zone otherZone) => future._inSameErrorZone(otherZone);
99 }
100
101 /**
102 * This listener is installed at error-zone boundaries. It signals an
103 * uncaught error in the zone of origin when an error is sent from one error
104 * zone to another.
105 *
106 * When a Future is listening to another Future and they have not been
107 * instantiated in the same error-zone then Futures put an instance of this
108 * class between them (see [_FutureImpl._addListener]).
109 *
110 * For example:
111 *
112 * var completer = new Completer();
113 * var future = completer.future.then((x) => x);
114 * catchErrors(() {
115 * var future2 = future.catchError(print);
116 * });
117 * completer.completeError(499);
118 *
119 * In this example `future` and `future2` are in different error-zones. The
120 * error (499) that originates outside `catchErrors` must not reach the
121 * `catchError` future (`future2`) inside `catchErrors`.
122 *
123 * When invoking `catchError` on `future` the Future installs an
124 * [_ErrorZoneBoundaryListener] between itself and the result, `future2`.
125 *
126 * Conceptually _ErrorZoneBoundaryListeners could be implemented as
127 * `catchError`s on the origin future as well.
128 */
129 class _ErrorZoneBoundaryListener implements _FutureListener {
130 _FutureListener _nextListener;
131 final _FutureListener _listener;
132
133 _ErrorZoneBoundaryListener(this._listener);
134
135 bool _inSameErrorZone(_Zone otherZone) {
136 // Should never be called. We use [_inSameErrorZone] to know if we have
137 // to insert an instance of [_ErrorZoneBoundaryListener] (and in the
138 // controller). Once we have inserted one we should never need to use it
139 // anymore.
140 throw new UnsupportedError(
141 "A Zone boundary doesn't support the inSameErrorZone test.");
142 }
143
144 void _sendValue(value) {
145 _listener._sendValue(value);
146 }
147
148 void _sendError(error) {
149 // We are not allowed to send an error from one error-zone to another.
150 // This is the whole purpose of this class.
151 _Zone.current.handleUncaughtError(error);
152 }
153 }
154
155 class _FutureImpl<T> implements Future<T> {
156 // State of the future. The state determines the interpretation of the 54 // State of the future. The state determines the interpretation of the
157 // [resultOrListeners] field. 55 // [resultOrListeners] field.
158 // TODO(lrn): rename field since it can also contain a chained future. 56 // TODO(lrn): rename field since it can also contain a chained future.
159 57
160 /// Initial state, waiting for a result. In this state, the 58 /// Initial state, waiting for a result. In this state, the
161 /// [resultOrListeners] field holds a single-linked list of 59 /// [resultOrListeners] field holds a single-linked list of
162 /// [FutureListener] listeners. 60 /// [FutureListener] listeners.
163 static const int _INCOMPLETE = 0; 61 static const int _INCOMPLETE = 0;
164 /// Pending completion. Set when completed using [_asyncSetValue] or 62 /// Pending completion. Set when completed using [_asyncComplete] or
165 /// [_asyncSetError]. It is an error to try to complete it again. 63 /// [_asyncCompleteError]. It is an error to try to complete it again.
166 static const int _PENDING_COMPLETE = 1; 64 static const int _PENDING_COMPLETE = 1;
167 /// The future has been chained to another future. The result of that 65 /// The future has been chained to another future. The result of that
168 /// other future becomes the result of this future as well. 66 /// other future becomes the result of this future as well.
169 /// In this state, the [resultOrListeners] field holds the future that 67 /// In this state, no callback should be executed anymore.
170 /// will give the result to this future. Both existing and new listeners are 68 // TODO(floitsch): we don't really need a special "_CHAINED" state. We could
171 /// forwarded directly to the other future. 69 // just use the PENDING_COMPLETE state instead.
172 static const int _CHAINED = 2; 70 static const int _CHAINED = 2;
173 /// The future has been chained to another future, but there hasn't been
174 /// any listeners added to this future yet. If it is completed with an
175 /// error, the error will be considered unhandled.
176 static const int _CHAINED_UNLISTENED = 6;
177 /// The future has been completed with a value result. 71 /// The future has been completed with a value result.
178 static const int _VALUE = 8; 72 static const int _VALUE = 4;
179 /// The future has been completed with an error result. 73 /// The future has been completed with an error result.
180 static const int _ERROR = 12; 74 static const int _ERROR = 8;
181 75
182 /** Whether the future is complete, and as what. */ 76 /** Whether the future is complete, and as what. */
183 int _state = _INCOMPLETE; 77 int _state = _INCOMPLETE;
184 78
185 final _Zone _zone = _Zone.current.fork(); 79 final _Zone _zone = _Zone.current.fork();
186 80
187 bool get _isChained => (_state & _CHAINED) != 0; 81 bool get _mayComplete => _state == _INCOMPLETE;
188 bool get _hasChainedListener => _state == _CHAINED; 82 bool get _isChained => _state == _CHAINED;
189 bool get _isComplete => _state >= _VALUE; 83 bool get _isComplete => _state >= _VALUE;
190 bool get _mayComplete => _state == _INCOMPLETE;
191 bool get _hasValue => _state == _VALUE; 84 bool get _hasValue => _state == _VALUE;
192 bool get _hasError => _state >= _ERROR; 85 bool get _hasError => _state == _ERROR;
86
87 set _isChained(bool value) {
88 if (value) {
89 assert(!_isComplete);
90 _state = _CHAINED;
91 } else {
92 assert(_isChained);
93 _state = _INCOMPLETE;
94 }
95 }
193 96
194 /** 97 /**
195 * Either the result, a list of listeners or another future. 98 * Either the result, a list of listeners or another future.
196 * 99 *
197 * The result of the future is either a value or an error. 100 * The result of the future is either a value or an error.
198 * A result is only stored when the future has completed. 101 * A result is only stored when the future has completed.
199 * 102 *
200 * The listeners is an internally linked list of [_FutureListener]s. 103 * The listeners is an internally linked list of [_FutureListener]s.
201 * Listeners are only remembered while the future is not yet complete, 104 * Listeners are only remembered while the future is not yet complete,
202 * and it is not chained to another future. 105 * and it is not chained to another future.
203 * 106 *
204 * The future is another future that his future is chained to. This future 107 * The future is another future that his future is chained to. This future
205 * is waiting for the other future to complete, and when it does, this future 108 * is waiting for the other future to complete, and when it does, this future
206 * will complete with the same result. 109 * will complete with the same result.
207 * All listeners are forwarded to the other future. 110 * All listeners are forwarded to the other future.
208 * 111 *
209 * The cases are disjoint (incomplete and unchained, incomplete and 112 * The cases are disjoint (incomplete and unchained, incomplete and
210 * chained, or completed with value or error), so the field only needs to hold 113 * chained, or completed with value or error), so the field only needs to hold
211 * one value at a time. 114 * one value at a time.
212 */ 115 */
213 var _resultOrListeners; 116 var _resultOrListeners;
214 117
215 _FutureImpl(); 118 /**
119 * A [_Future] implements a linked list. If a future has more than one
120 * listener the [_nextListener] field of the first listener points to the
121 * remaining listeners.
122 */
123 // TODO(floitsch): since single listeners are the common case we should
124 // use a bit to indicate that the _resultOrListeners contains a container.
125 _Future _nextListener;
216 126
217 _FutureImpl.immediate(T value) { 127 // TODO(floitsch): we only need two closure fields to store the callbacks.
128 // If we store the type of a closure in the state field (where there are
129 // still bits left), we can just store two closures instead of using 4
130 // fields of which 2 are always null.
131 final _FutureOnValue _onValueCallback;
132 final _FutureErrorTest _errorTestCallback;
133 final _FutureOnError _onErrorCallback;
134 final _FutureAction _whenCompleteActionCallback;
135
136 _FutureOnValue get _onValue => _isChained ? null : _onValueCallback;
137 _FutureErrorTest get _errorTest => _isChained ? null : _errorTestCallback;
138 _FutureOnError get _onError => _isChained ? null : _onErrorCallback;
139 _FutureAction get _whenCompleteAction
140 => _isChained ? null : _whenCompleteActionCallback;
141
142 _Future()
143 : _onValueCallback = null, _errorTestCallback = null,
144 _onErrorCallback = null, _whenCompleteActionCallback = null;
145
146 _Future.immediate(T value)
147 : _onValueCallback = null, _errorTestCallback = null,
148 _onErrorCallback = null, _whenCompleteActionCallback = null {
149 _asyncComplete(value);
150 }
151
152 _Future.immediateError(var error, [Object stackTrace])
153 : _onValueCallback = null, _errorTestCallback = null,
154 _onErrorCallback = null, _whenCompleteActionCallback = null {
155 _asyncCompleteError(error, stackTrace);
156 }
157
158 _Future._then(this._onValueCallback, this._onErrorCallback)
159 : _errorTestCallback = null, _whenCompleteActionCallback = null {
160 _zone.expectCallback();
161 }
162
163 _Future._catchError(this._onErrorCallback, this._errorTestCallback)
164 : _onValueCallback = null, _whenCompleteActionCallback = null {
165 _zone.expectCallback();
166 }
167
168 _Future._whenComplete(this._whenCompleteActionCallback)
169 : _onValueCallback = null, _errorTestCallback = null,
170 _onErrorCallback = null {
171 _zone.expectCallback();
172 }
173
174 Future then(f(T value), { onError(error) }) {
175 _Future result;
176 result = new _Future._then(f, onError);
177 _addListener(result);
178 return result;
179 }
180
181 Future catchError(f(error), { bool test(error) }) {
182 _Future result = new _Future._catchError(f, test);
183 _addListener(result);
184 return result;
185 }
186
187 Future<T> whenComplete(action()) {
188 _Future result = new _Future<T>._whenComplete(action);
189 _addListener(result);
190 return result;
191 }
192
193 Stream<T> asStream() => new Stream.fromFuture(this);
194
195 void _markPendingCompletion() {
196 if (!_mayComplete) throw new StateError("Future already completed");
197 _state = _PENDING_COMPLETE;
198 }
199
200 T get _value {
201 assert(_isComplete && _hasValue);
202 return _resultOrListeners;
203 }
204
205 Object get _error {
206 assert(_isComplete && _hasError);
207 return _resultOrListeners;
208 }
209
210 void _setValue(T value) {
211 assert(!_isComplete); // But may have a completion pending.
218 _state = _VALUE; 212 _state = _VALUE;
219 _resultOrListeners = value; 213 _resultOrListeners = value;
220 } 214 }
221 215
222 _FutureImpl.immediateError(var error, [Object stackTrace]) { 216 void _setError(Object error) {
223 if (stackTrace != null) { 217 assert(!_isComplete); // But may have a completion pending.
224 // Force stack trace onto error, even if it had already one. 218 _state = _ERROR;
225 _attachStackTrace(error, stackTrace); 219 _resultOrListeners = error;
226 }
227 _asyncSetError(error);
228 } 220 }
229 221
230 factory _FutureImpl.wait(Iterable<Future> futures) { 222 void _addListener(_Future listener) {
231 Completer completer;
232 // List collecting values from the futures.
233 // Set to null if an error occurs.
234 List values;
235 void handleError(error) {
236 if (values != null) {
237 values = null;
238 completer.completeError(error);
239 }
240 }
241 // As each future completes, put its value into the corresponding
242 // position in the list of values.
243 int remaining = 0;
244 for (Future future in futures) {
245 int pos = remaining++;
246 future.catchError(handleError).then((Object value) {
247 if (values == null) return null;
248 values[pos] = value;
249 remaining--;
250 if (remaining == 0) {
251 completer.complete(values);
252 }
253 });
254 }
255 if (remaining == 0) {
256 return new Future.value(const []);
257 }
258 values = new List(remaining);
259 completer = new Completer<List>();
260 return completer.future;
261 }
262
263 Future then(f(T value), { onError(error) }) {
264 if (onError == null) {
265 return new _ThenFuture(f).._subscribeTo(this);
266 }
267 return new _SubscribeFuture(f, onError).._subscribeTo(this);
268 }
269
270 Future catchError(f(error), { bool test(error) }) {
271 return new _CatchErrorFuture(f, test).._subscribeTo(this);
272 }
273
274 Future<T> whenComplete(action()) {
275 return new _WhenFuture<T>(action).._subscribeTo(this);
276 }
277
278 Stream<T> asStream() => new Stream.fromFuture(this);
279
280 bool _inSameErrorZone(_Zone otherZone) {
281 return _zone.inSameErrorZone(otherZone);
282 }
283
284 void _setValue(T value) {
285 if (!_mayComplete) throw new StateError("Future already completed");
286 _setValueUnchecked(value);
287 }
288
289 void _setValueUnchecked(T value) {
290 _FutureListener listeners = _isChained ? null : _removeListeners();
291 _state = _VALUE;
292 _resultOrListeners = value;
293 while (listeners != null) {
294 _FutureListener listener = listeners;
295 listeners = listener._nextListener;
296 listener._nextListener = null;
297 listener._sendValue(value);
298 }
299 }
300
301 void _setError(Object error) {
302 if (!_mayComplete) throw new StateError("Future already completed");
303 _setErrorUnchecked(error);
304 }
305
306 void _setErrorUnchecked(Object error) {
307 _FutureListener listeners;
308 bool hasListeners;
309 if (_isChained) {
310 listeners = null;
311 hasListeners = (_state == _CHAINED); // and not _CHAINED_UNLISTENED.
312 } else {
313 listeners = _removeListeners();
314 hasListeners = (listeners != null);
315 }
316
317 _state = _ERROR;
318 _resultOrListeners = error;
319
320 if (!hasListeners) {
321 // TODO(floitsch): Hook this into unhandled error handling.
322 var error = _resultOrListeners;
323 _zone.handleUncaughtError(error);
324 return;
325 }
326 while (listeners != null) {
327 _FutureListener listener = listeners;
328 listeners = listener._nextListener;
329 listener._nextListener = null;
330 listener._sendError(error);
331 }
332 }
333
334 void _asyncSetValue(T value) {
335 if (!_mayComplete) throw new StateError("Future already completed");
336 _state = _PENDING_COMPLETE;
337 runAsync(() { _setValueUnchecked(value); });
338 }
339
340 void _asyncSetError(Object error) {
341 if (!_mayComplete) throw new StateError("Future already completed");
342 _state = _PENDING_COMPLETE;
343 runAsync(() { _setErrorUnchecked(error); });
344 }
345
346 void _addListener(_FutureListener listener) {
347 assert(listener._nextListener == null); 223 assert(listener._nextListener == null);
348 if (!listener._inSameErrorZone(_zone)) {
349 listener = new _ErrorZoneBoundaryListener(listener);
350 }
351 if (_isChained) {
352 _state = _CHAINED; // In case it was _CHAINED_UNLISTENED.
353 _FutureImpl resultSource = _chainSource;
354 resultSource._addListener(listener);
355 return;
356 }
357 if (_isComplete) { 224 if (_isComplete) {
358 // Handle late listeners asynchronously. 225 // Handle late listeners asynchronously.
359 runAsync(() { 226 runAsync(() {
360 if (_hasValue) { 227 _propagateToListeners(this, listener);
361 T value = _resultOrListeners;
362 listener._sendValue(value);
363 } else {
364 assert(_hasError);
365 listener._sendError(_resultOrListeners);
366 }
367 }); 228 });
368 } else { 229 } else {
369 assert(!_isComplete);
370 listener._nextListener = _resultOrListeners; 230 listener._nextListener = _resultOrListeners;
371 _resultOrListeners = listener; 231 _resultOrListeners = listener;
372 } 232 }
373 } 233 }
374 234
375 _FutureListener _removeListeners() { 235 _Future _removeListeners() {
376 // Reverse listeners before returning them, so the resulting list is in 236 // Reverse listeners before returning them, so the resulting list is in
377 // subscription order. 237 // subscription order.
378 assert(!_isComplete); 238 assert(!_isComplete);
379 _FutureListener current = _resultOrListeners; 239 _Future current = _resultOrListeners;
380 _resultOrListeners = null; 240 _resultOrListeners = null;
381 _FutureListener prev = null; 241 _Future prev = null;
382 while (current != null) { 242 while (current != null) {
383 _FutureListener next = current._nextListener; 243 _Future next = current._nextListener;
384 current._nextListener = prev; 244 current._nextListener = prev;
385 prev = current; 245 prev = current;
386 current = next; 246 current = next;
387 } 247 }
388 return prev; 248 return prev;
389 } 249 }
390 250
251 static void _chainFutures(Future source, _Future target) {
252 assert(!target._isComplete);
253
254 // Mark the target as chained (and as such half-completed).
255 target._isChained = true;
256 if (source is _Future) {
257 _Future internalFuture = source;
258 if (internalFuture._isComplete) {
259 _propagateToListeners(internalFuture, target);
260 } else {
261 internalFuture._addListener(target);
262 }
263 } else {
264 source.then((value) {
265 assert(target._isChained);
266 target._complete(value);
267 },
268 onError: (error) {
269 assert(target._isChained);
270 target._completeError(error);
271 });
272 }
273 }
274
275 void _complete(value) {
276 assert(!_isComplete);
277 assert(_onValue == null);
278 assert(_onError == null);
279 assert(_whenCompleteAction == null);
280 assert(_errorTest == null);
281
282 if (value is Future) {
283 _chainFutures(value, this);
284 return;
285 }
286 _Future listeners = _removeListeners();
287 _setValue(value);
288 _propagateToListeners(this, listeners);
289 }
290
291 void _completeError(error, [StackTrace stackTrace]) {
292 assert(!_isComplete);
293 assert(_onValue == null);
294 assert(_onError == null);
295 assert(_whenCompleteAction == null);
296 assert(_errorTest == null);
297
298 if (stackTrace != null) {
299 // Force the stack trace onto the error, even if it already had one.
300 _attachStackTrace(error, stackTrace);
301 }
302
303 _Future listeners = _isChained ? null : _removeListeners();
304 _setError(error);
305 _propagateToListeners(this, listeners);
306 }
307
308 void _asyncComplete(value) {
309 assert(!_isComplete);
310 assert(_onValue == null);
311 assert(_onError == null);
312 assert(_whenCompleteAction == null);
313 assert(_errorTest == null);
314 // Two corner cases if the value is a future:
315 // 1. the future is already completed and an error.
316 // 2. the future is not yet completed but might become an error.
317 // The first case means that we must not immediately complete the Future,
318 // as our code would immediately start propagating the error without
319 // giving the time to install error-handlers.
320 // However the second case requires us to deal with the value immediately.
321 // Otherwise the value could complete with an error and report an
322 // unhandled error, even though we know we are already going to listen to
323 // it.
324 if (value is Future &&
325 (value is! _Future || !(value as _Future)._isComplete)) {
326 // Case 2 from above. We need to register.
327 // Note that we are still completing asynchronously: either we register
328 // through .then (in which case the completing is asynchronous), or we
329 // have a _Future which isn't complete yet.
330 _complete(value);
331 return;
332 }
333
334 _markPendingCompletion();
335 runAsync(() {
336 _complete(value);
337 });
338 }
339
340 void _asyncCompleteError(error, [StackTrace stackTrace]) {
341 assert(!_isComplete);
342 assert(_onValue == null);
343 assert(_onError == null);
344 assert(_whenCompleteAction == null);
345 assert(_errorTest == null);
346
347 _markPendingCompletion();
348 runAsync(() {
349 _completeError(error, stackTrace);
350 });
351 }
352
391 /** 353 /**
392 * Make another [_FutureImpl] receive the result of this one. 354 * Propagates the value/error of [source] to its [listeners].
393 * 355 *
394 * If this future is already complete, the [future] is notified 356 * Unlinks all listeners and propagates the source to each listener
395 * immediately. This function is only called during event resolution 357 * separately.
396 * where it's acceptable to send an event.
397 */ 358 */
398 void _chain(_FutureImpl future) { 359 static void _propagateMultipleListeners(_Future source, _Future listeners) {
399 if (!_isComplete) { 360 assert(listeners != null);
400 future._chainFromFuture(this); 361 assert(listeners._nextListener != null);
401 } else if (_hasValue) { 362 do {
402 future._setValue(_resultOrListeners); 363 _Future listener = listeners;
403 } else { 364 listeners = listener._nextListener;
404 assert(_hasError); 365 listener._nextListener = null;
405 future._setError(_resultOrListeners); 366 _propagateToListeners(source, listener);
406 } 367 } while (listeners != null);
407 } 368 }
408 369
409 /** 370 /**
410 * Returns the future that this future is chained to. 371 * Propagates the value/error of [source] to its [listeners], executing the
372 * listeners' callbacks.
411 * 373 *
412 * If that future is itself chained to something else, 374 * If [runCallback] is true (which should be the default) it executes
413 * get the [_chainSource] of that future instead, and make this 375 * the registered action of listeners. If it is `false` then the callback is
414 * future chain directly to the earliest source. 376 * skipped. This is used to complete futures with chained futures.
415 */ 377 */
416 _FutureImpl get _chainSource { 378 static void _propagateToListeners(_Future source, _Future listeners) {
417 assert(_isChained); 379 while (true) {
418 _FutureImpl future = _resultOrListeners; 380 if (!source._isComplete) return; // Chained future.
419 if (future._isChained) { 381 bool hasError = source._hasError;
420 future = _resultOrListeners = future._chainSource; 382 if (hasError && listeners == null) {
421 } 383 source._zone.handleUncaughtError(source._error);
422 return future; 384 return;
423 } 385 }
424 386 if (listeners == null) return;
425 /** 387 _Future listener = listeners;
426 * Make this incomplete future end up with the same result as [resultSource]. 388 if (listener._nextListener != null) {
427 * 389 // Usually futures only have one listener. If they have several, we
428 * This is done by moving all listeners to [resultSource] and forwarding all 390 // handle them specially.
429 * future [_addListener] calls to [resultSource] directly. 391 _propagateMultipleListeners(source, listeners);
430 */ 392 return;
431 void _chainFromFuture(_FutureImpl resultSource) { 393 }
432 assert(!_isComplete); 394 if (hasError && !source._zone.inSameErrorZone(listener._zone)) {
433 assert(!_isChained); 395 // Don't cross zone boundaries with errors.
434 if (resultSource._isChained) { 396 source._zone.handleUncaughtError(source._error);
435 resultSource = resultSource._chainSource; 397 return;
436 } 398 }
437 assert(!resultSource._isChained); 399 if (!identical(_Zone.current, listener._zone)) {
438 if (identical(this, resultSource)) { 400 // Run the propagation in the listener's zone to avoid
439 // The only unchained future in a future dependency tree (as defined 401 // zone transitions. The idea is that many chained futures will
440 // by the chain-relations) is the "root" that every other future depends 402 // be in the same zone.
441 // on. The future we are adding is unchained, so if it is already in the 403 listener._zone.executePeriodicCallback(() {
442 // tree, it must be the root, so that's the only one we need to check 404 _propagateToListeners(source, listener);
443 // against to detect a cycle. 405 });
444 _setError(new StateError("Cyclic future dependency.")); 406 return;
445 return; 407 }
446 } 408
447 _FutureListener cursor = _removeListeners(); 409 // Do the actual propagation.
448 bool hadListeners = cursor != null; 410 // TODO(floitsch): Do we need to go through the zone even if we
449 while (cursor != null) { 411 // don't have a callback to execute?
450 _FutureListener listener = cursor; 412 bool listenerHasValue;
451 cursor = cursor._nextListener; 413 var listenerValueOrError;
452 listener._nextListener = null; 414 // Set to true if a whenComplete needs to wait for a future.
453 resultSource._addListener(listener); 415 // The whenComplete action will resume the propagation by itself.
454 } 416 bool isPropagationAborted = false;
455 // Listen with this future as well, so that when the other future completes, 417 // Even though we are already in the right zone (due to the optimization
456 // this future will be completed as well. 418 // above), we still need to go through the zone. The overhead of
457 resultSource._addListener(this._asListener()); 419 // executeCallback is however smaller when it is already in the correct
458 _resultOrListeners = resultSource; 420 // zone.
459 _state = hadListeners ? _CHAINED : _CHAINED_UNLISTENED; 421 // TODO(floitsch): only run callbacks in the zone, not the whole
460 } 422 // handling code.
461 423 listener._zone.executeCallback(() {
462 /** 424 // TODO(floitsch): mark the listener as pending completion. Currently
463 * Helper function to handle the result of transforming an incoming event. 425 // we can't do this, since the markPendingCompletion verifies that
464 * 426 // the future is not already marked (or chained).
465 * If the result is itself a [Future], this future is linked to that 427 try {
466 * future's output. If not, this future is completed with the result. 428 if (!hasError) {
467 */ 429 var value = source._value;
468 void _setOrChainValue(var result) { 430 if (listener._onValue != null) {
469 assert(!_isChained); 431 listenerValueOrError = listener._onValue(value);
470 assert(!_isComplete); 432 listenerHasValue = true;
471 if (result is Future) { 433 } else {
472 // Result should be a Future<T>. 434 // Copy over the value from the source.
473 if (result is _FutureImpl) { 435 listenerValueOrError = value;
474 _FutureImpl chainFuture = result; 436 listenerHasValue = true;
475 chainFuture._chain(this); 437 }
476 return; 438 } else {
439 Object error = source._error;
440 _FutureErrorTest test = listener._errorTest;
441 bool matchesTest = true;
442 if (test != null) {
443 matchesTest = test(error);
444 }
445 if (matchesTest && listener._onError != null) {
446 listenerValueOrError = listener._onError(error);
447 listenerHasValue = true;
448 } else {
449 // Copy over the error from the source.
450 listenerValueOrError = error;
451 listenerHasValue = false;
452 }
453 }
454
455 if (listener._whenCompleteAction != null) {
456 var completeResult = listener._whenCompleteAction();
457 if (completeResult is Future) {
458 listener._isChained = true;
459 completeResult.then((ignored) {
460 // Try again, but this time don't run the whenComplete callback.
461 _propagateToListeners(source, listener);
462 }, onError: (error) {
463 // When there is an error, we have to make the error the new
464 // result of the current listener.
465 if (completeResult is! _Future) {
466 // This should be a rare case.
467 completeResult = new _Future();
468 completeResult._setError(error);
469 }
470 _propagateToListeners(completeResult, listener);
471 });
472 isPropagationAborted = true;
473 // We will reenter the listener's zone.
474 listener._zone.expectCallback();
475 }
476 }
477 } catch (e, s) {
478 // Set the exception as error.
479 listenerValueOrError = _asyncError(e, s);
480 listenerHasValue = false;
481 }
482 if (listenerHasValue && listenerValueOrError is Future) {
483 // We are going to reenter the zone to finish what we started.
484 listener._zone.expectCallback();
485 }
486 });
487 if (isPropagationAborted) return;
488 // If the listener's value is a future we need to chain it.
489 if (listenerHasValue && listenerValueOrError is Future) {
490 Future chainSource = listenerValueOrError;
491 // Shortcut if the chain-source is already completed. Just continue the
492 // loop.
493 if (chainSource is _Future && (chainSource as _Future)._isComplete) {
494 // propagate the value (simulating a tail call).
495 listener._isChained = true;
496 source = chainSource;
497 listeners = listener;
498 continue;
499 }
500 _chainFutures(chainSource, listener);
501 return;
502 }
503
504 if (listenerHasValue) {
505 listeners = listener._removeListeners();
506 listener._setValue(listenerValueOrError);
477 } else { 507 } else {
478 Future future = result; 508 listeners = listener._removeListeners();
479 future.then(_setValue, 509 listener._setError(listenerValueOrError);
480 onError: _setError); 510 }
481 return; 511 // Prepare for next round.
482 } 512 source = listener;
483 } else { 513 }
484 // Result must be of type T. 514 }
485 _setValue(result);
486 }
487 }
488
489 _FutureListener _asListener() => new _FutureListener.wrap(this);
490 } 515 }
491
492 /**
493 * Transforming future base class.
494 *
495 * A transforming future is itself a future and a future listener.
496 * Subclasses override [_sendValue]/[_sendError] to intercept
497 * the results of a previous future.
498 */
499 abstract class _TransformFuture<S, T> extends _FutureImpl<T>
500 implements _FutureListener<S> {
501 // _FutureListener implementation.
502 _FutureListener _nextListener;
503
504 _TransformFuture() {
505 _zone.expectCallback();
506 }
507
508 void _sendValue(S value) {
509 _zone.executeCallback(() => _zonedSendValue(value));
510 }
511
512 void _sendError(error) {
513 _zone.executeCallback(() => _zonedSendError(error));
514 }
515
516 void _subscribeTo(_FutureImpl future) {
517 future._addListener(this);
518 }
519
520 void _zonedSendValue(S value);
521 void _zonedSendError(error);
522 }
523
524 /** The onValue and onError handlers return either a value or a future */
525 typedef dynamic _FutureOnValue<T>(T value);
526 typedef dynamic _FutureOnError(error);
527 /** Test used by [Future.catchError] to handle skip some errors. */
528 typedef bool _FutureErrorTest(var error);
529 /** Used by [WhenFuture]. */
530 typedef _FutureAction();
531
532 /** Future returned by [Future.then] with no [:onError:] parameter. */
533 class _ThenFuture<S, T> extends _TransformFuture<S, T> {
534 // TODO(ahe): Restore type when feature is implemented in dart2js
535 // checked mode.
536 final /* _FutureOnValue<S> */ _onValue;
537
538 _ThenFuture(this._onValue);
539
540 _zonedSendValue(S value) {
541 assert(_onValue != null);
542 var result;
543 try {
544 result = _onValue(value);
545 } catch (e, s) {
546 _setError(_asyncError(e, s));
547 return;
548 }
549 _setOrChainValue(result);
550 }
551
552 void _zonedSendError(error) {
553 _setError(error);
554 }
555 }
556
557 /** Future returned by [Future.catchError]. */
558 class _CatchErrorFuture<T> extends _TransformFuture<T,T> {
559 final _FutureErrorTest _test;
560 final _FutureOnError _onError;
561
562 _CatchErrorFuture(this._onError, this._test);
563
564 _zonedSendValue(T value) {
565 _setValue(value);
566 }
567
568 _zonedSendError(error) {
569 assert(_onError != null);
570 // if _test is supplied, check if it returns true, otherwise just
571 // forward the error unmodified.
572 if (_test != null) {
573 bool matchesTest;
574 try {
575 matchesTest = _test(error);
576 } catch (e, s) {
577 _setError(_asyncError(e, s));
578 return;
579 }
580 if (!matchesTest) {
581 _setError(error);
582 return;
583 }
584 }
585 // Act on the error, and use the result as this future's result.
586 var result;
587 try {
588 result = _onError(error);
589 } catch (e, s) {
590 _setError(_asyncError(e, s));
591 return;
592 }
593 _setOrChainValue(result);
594 }
595 }
596
597 /** Future returned by [Future.then] with an [:onError:] parameter. */
598 class _SubscribeFuture<S, T> extends _ThenFuture<S, T> {
599 final _FutureOnError _onError;
600
601 _SubscribeFuture(onValue(S value), this._onError) : super(onValue);
602
603 // The _sendValue method is inherited from ThenFuture.
604
605 void _zonedSendError(error) {
606 assert(_onError != null);
607 var result;
608 try {
609 result = _onError(error);
610 } catch (e, s) {
611 _setError(_asyncError(e, s));
612 return;
613 }
614 _setOrChainValue(result);
615 }
616 }
617
618 /** Future returned by [Future.whenComplete]. */
619 class _WhenFuture<T> extends _TransformFuture<T, T> {
620 final _FutureAction _action;
621
622 _WhenFuture(this._action);
623
624 void _zonedSendValue(T value) {
625 try {
626 var result = _action();
627 if (result is Future) {
628 Future resultFuture = result;
629 resultFuture.then((_) {
630 _setValue(value);
631 }, onError: _setError);
632 return;
633 }
634 } catch (e, s) {
635 _setError(_asyncError(e, s));
636 return;
637 }
638 _setValue(value);
639 }
640
641 void _zonedSendError(error) {
642 try {
643 var result = _action();
644 if (result is Future) {
645 Future resultFuture = result;
646 // TODO(lrn): Find a way to combine [error] into [e].
647 resultFuture.then((_) {
648 _setError(error);
649 }, onError: _setError);
650 return;
651 }
652 } catch (e, s) {
653 error = _asyncError(e, s);
654 }
655 _setError(error);
656 }
657 }
OLDNEW
« no previous file with comments | « sdk/lib/async/future.dart ('k') | sdk/lib/async/stream.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698