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

Side by Side Diff: test/generated_sdk/lib/async/future_impl.dart

Issue 1162723007: remove generated_sdk from checked in code (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 6 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
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 part of dart.async;
6
7 /** The onValue and onError handlers return either a value or a future */
8 typedef dynamic _FutureOnValue<T>(T value);
9 /** Test used by [Future.catchError] to handle skip some errors. */
10 typedef bool _FutureErrorTest(var error);
11 /** Used by [WhenFuture]. */
12 typedef _FutureAction();
13
14 abstract class _Completer<T> implements Completer<T> {
15 final _Future<T> future = new _Future<T>();
16
17 void complete([value]);
18
19 void completeError(Object error, [StackTrace stackTrace]) {
20 error = _nonNullError(error);
21 if (!future._mayComplete) throw new StateError("Future already completed");
22 AsyncError replacement = Zone.current.errorCallback(error, stackTrace);
23 if (replacement != null) {
24 error = _nonNullError(replacement.error);
25 stackTrace = replacement.stackTrace;
26 }
27 _completeError(error, stackTrace);
28 }
29
30 void _completeError(Object error, StackTrace stackTrace);
31
32 // The future's _isComplete doesn't take into account pending completions.
33 // We therefore use _mayComplete.
34 bool get isCompleted => !future._mayComplete;
35 }
36
37 class _AsyncCompleter<T> extends _Completer<T> {
38
39 void complete([value]) {
40 if (!future._mayComplete) throw new StateError("Future already completed");
41 future._asyncComplete(value);
42 }
43
44 void _completeError(Object error, StackTrace stackTrace) {
45 future._asyncCompleteError(error, stackTrace);
46 }
47 }
48
49 class _SyncCompleter<T> extends _Completer<T> {
50 void complete([value]) {
51 if (!future._mayComplete) throw new StateError("Future already completed");
52 future._complete(value);
53 }
54
55 void _completeError(Object error, StackTrace stackTrace) {
56 future._completeError(error, stackTrace);
57 }
58 }
59
60 class _FutureListener {
61 static const int MASK_VALUE = 1;
62 static const int MASK_ERROR = 2;
63 static const int MASK_TEST_ERROR = 4;
64 static const int MASK_WHENCOMPLETE = 8;
65 static const int STATE_CHAIN = 0;
66 static const int STATE_THEN = MASK_VALUE;
67 static const int STATE_THEN_ONERROR = MASK_VALUE | MASK_ERROR;
68 static const int STATE_CATCHERROR = MASK_ERROR;
69 static const int STATE_CATCHERROR_TEST = MASK_ERROR | MASK_TEST_ERROR;
70 static const int STATE_WHENCOMPLETE = MASK_WHENCOMPLETE;
71 // Listeners on the same future are linked through this link.
72 _FutureListener _nextListener = null;
73 // The future to complete when this listener is activated.
74 final _Future result;
75 // Which fields means what.
76 final int state;
77 // Used for then/whenDone callback and error test
78 final Function callback;
79 // Used for error callbacks.
80 final Function errorCallback;
81
82 _FutureListener.then(this.result,
83 _FutureOnValue onValue, Function errorCallback)
84 : callback = onValue,
85 errorCallback = errorCallback,
86 state = (errorCallback == null) ? STATE_THEN : STATE_THEN_ONERROR;
87
88 _FutureListener.catchError(this.result,
89 this.errorCallback, _FutureErrorTest test)
90 : callback = test,
91 state = (test == null) ? STATE_CATCHERROR : STATE_CATCHERROR_TEST;
92
93 _FutureListener.whenComplete(this.result, _FutureAction onComplete)
94 : callback = onComplete,
95 errorCallback = null,
96 state = STATE_WHENCOMPLETE;
97
98 _FutureListener.chain(this.result)
99 : callback = null,
100 errorCallback = null,
101 state = STATE_CHAIN;
102
103 Zone get _zone => result._zone;
104
105 bool get handlesValue => (state & MASK_VALUE != 0);
106 bool get handlesError => (state & MASK_ERROR != 0);
107 bool get hasErrorTest => (state == STATE_CATCHERROR_TEST);
108 bool get handlesComplete => (state == STATE_WHENCOMPLETE);
109
110 _FutureOnValue get _onValue {
111 assert(handlesValue);
112 return callback;
113 }
114 Function get _onError => errorCallback;
115 _FutureErrorTest get _errorTest {
116 assert(hasErrorTest);
117 return callback;
118 }
119 _FutureAction get _whenCompleteAction {
120 assert(handlesComplete);
121 return callback;
122 }
123 }
124
125 class _Future<T> implements Future<T> {
126 /// Initial state, waiting for a result. In this state, the
127 /// [resultOrListeners] field holds a single-linked list of
128 /// [_FutureListener] listeners.
129 static const int _INCOMPLETE = 0;
130 /// Pending completion. Set when completed using [_asyncComplete] or
131 /// [_asyncCompleteError]. It is an error to try to complete it again.
132 /// [resultOrListeners] holds listeners.
133 static const int _PENDING_COMPLETE = 1;
134 /// The future has been chained to another future. The result of that
135 /// other future becomes the result of this future as well.
136 // TODO(floitsch): we don't really need a special "_CHAINED" state. We could
137 // just use the PENDING_COMPLETE state instead.
138 static const int _CHAINED = 2;
139 /// The future has been completed with a value result.
140 static const int _VALUE = 4;
141 /// The future has been completed with an error result.
142 static const int _ERROR = 8;
143
144 /** Whether the future is complete, and as what. */
145 int _state = _INCOMPLETE;
146
147 /**
148 * Zone that the future was completed from.
149 * This is the zone that an error result belongs to.
150 *
151 * Until the future is completed, the field may hold the zone that
152 * listener callbacks used to create this future should be run in.
153 */
154 final Zone _zone = Zone.current;
155
156 /**
157 * Either the result, a list of listeners or another future.
158 *
159 * The result of the future is either a value or an error.
160 * A result is only stored when the future has completed.
161 *
162 * The listeners is an internally linked list of [_FutureListener]s.
163 * Listeners are only remembered while the future is not yet complete,
164 * and it is not chained to another future.
165 *
166 * The future is another future that his future is chained to. This future
167 * is waiting for the other future to complete, and when it does, this future
168 * will complete with the same result.
169 * All listeners are forwarded to the other future.
170 *
171 * The cases are disjoint - incomplete and unchained ([_INCOMPLETE]),
172 * incomplete and chained ([_CHAINED]), or completed with value or error
173 * ([_VALUE] or [_ERROR]) - so the field only needs to hold
174 * one value at a time.
175 */
176 var _resultOrListeners;
177
178 _Future();
179
180 /// Valid types for value: `T` or `Future<T>`.
181 _Future.immediate(value) {
182 _asyncComplete(value);
183 }
184
185 _Future.immediateError(var error, [StackTrace stackTrace]) {
186 _asyncCompleteError(error, stackTrace);
187 }
188
189 bool get _mayComplete => _state == _INCOMPLETE;
190 bool get _isChained => _state == _CHAINED;
191 bool get _isComplete => _state >= _VALUE;
192 bool get _hasValue => _state == _VALUE;
193 bool get _hasError => _state == _ERROR;
194
195 set _isChained(bool value) {
196 if (value) {
197 assert(!_isComplete);
198 _state = _CHAINED;
199 } else {
200 assert(_isChained);
201 _state = _INCOMPLETE;
202 }
203 }
204
205 Future then(f(T value), { Function onError }) {
206 _Future result = new _Future();
207 if (!identical(result._zone, _ROOT_ZONE)) {
208 f = result._zone.registerUnaryCallback(f);
209 if (onError != null) {
210 onError = _registerErrorHandler(onError, result._zone);
211 }
212 }
213 _addListener(new _FutureListener.then(result, f, onError));
214 return result;
215 }
216
217 Future catchError(Function onError, { bool test(error) }) {
218 _Future result = new _Future();
219 if (!identical(result._zone, _ROOT_ZONE)) {
220 onError = _registerErrorHandler(onError, result._zone);
221 if (test != null) test = result._zone.registerUnaryCallback(test);
222 }
223 _addListener(new _FutureListener.catchError(result, onError, test));
224 return result;
225 }
226
227 Future<T> whenComplete(action()) {
228 _Future result = new _Future<T>();
229 if (!identical(result._zone, _ROOT_ZONE)) {
230 action = result._zone.registerCallback(action);
231 }
232 _addListener(new _FutureListener.whenComplete(result, action));
233 return result;
234 }
235
236 Stream<T> asStream() => new Stream.fromFuture(this);
237
238 void _markPendingCompletion() {
239 if (!_mayComplete) throw new StateError("Future already completed");
240 _state = _PENDING_COMPLETE;
241 }
242
243 T get _value {
244 assert(_isComplete && _hasValue);
245 return _resultOrListeners;
246 }
247
248 AsyncError get _error {
249 assert(_isComplete && _hasError);
250 return _resultOrListeners;
251 }
252
253 void _setValue(T value) {
254 assert(!_isComplete); // But may have a completion pending.
255 _state = _VALUE;
256 _resultOrListeners = value;
257 }
258
259 void _setErrorObject(AsyncError error) {
260 assert(!_isComplete); // But may have a completion pending.
261 _state = _ERROR;
262 _resultOrListeners = error;
263 }
264
265 void _setError(Object error, StackTrace stackTrace) {
266 _setErrorObject(new AsyncError(error, stackTrace));
267 }
268
269 void _addListener(_FutureListener listener) {
270 assert(listener._nextListener == null);
271 if (_isComplete) {
272 // Handle late listeners asynchronously.
273 _zone.scheduleMicrotask(() {
274 _propagateToListeners(this, listener);
275 });
276 } else {
277 listener._nextListener = _resultOrListeners;
278 _resultOrListeners = listener;
279 }
280 }
281
282 _FutureListener _removeListeners() {
283 // Reverse listeners before returning them, so the resulting list is in
284 // subscription order.
285 assert(!_isComplete);
286 _FutureListener current = _resultOrListeners;
287 _resultOrListeners = null;
288 _FutureListener prev = null;
289 while (current != null) {
290 _FutureListener next = current._nextListener;
291 current._nextListener = prev;
292 prev = current;
293 current = next;
294 }
295 return prev;
296 }
297
298 // Take the value (when completed) of source and complete target with that
299 // value (or error). This function can chain all Futures, but is slower
300 // for _Future than _chainCoreFuture - Use _chainCoreFuture in that case.
301 static void _chainForeignFuture(Future source, _Future target) {
302 assert(!target._isComplete);
303 assert(source is! _Future);
304
305 // Mark the target as chained (and as such half-completed).
306 target._isChained = true;
307 source.then((value) {
308 assert(target._isChained);
309 target._completeWithValue(value);
310 },
311 // TODO(floitsch): eventually we would like to make this non-optional
312 // and dependent on the listeners of the target future. If none of
313 // the target future's listeners want to have the stack trace we don't
314 // need a trace.
315 onError: (error, [stackTrace]) {
316 assert(target._isChained);
317 target._completeError(error, stackTrace);
318 });
319 }
320
321 // Take the value (when completed) of source and complete target with that
322 // value (or error). This function expects that source is a _Future.
323 static void _chainCoreFuture(_Future source, _Future target) {
324 assert(!target._isComplete);
325 assert(source is _Future);
326
327 // Mark the target as chained (and as such half-completed).
328 target._isChained = true;
329 _FutureListener listener = new _FutureListener.chain(target);
330 if (source._isComplete) {
331 _propagateToListeners(source, listener);
332 } else {
333 source._addListener(listener);
334 }
335 }
336
337 void _complete(value) {
338 assert(!_isComplete);
339 if (value is Future) {
340 if (value is _Future) {
341 _chainCoreFuture(value, this);
342 } else {
343 _chainForeignFuture(value, this);
344 }
345 } else {
346 _FutureListener listeners = _removeListeners();
347 _setValue(value);
348 _propagateToListeners(this, listeners);
349 }
350 }
351
352 void _completeWithValue(value) {
353 assert(!_isComplete);
354 assert(value is! Future);
355
356 _FutureListener listeners = _removeListeners();
357 _setValue(value);
358 _propagateToListeners(this, listeners);
359 }
360
361 void _completeError(error, [StackTrace stackTrace]) {
362 assert(!_isComplete);
363
364 _FutureListener listeners = _removeListeners();
365 _setError(error, stackTrace);
366 _propagateToListeners(this, listeners);
367 }
368
369 void _asyncComplete(value) {
370 assert(!_isComplete);
371 // Two corner cases if the value is a future:
372 // 1. the future is already completed and an error.
373 // 2. the future is not yet completed but might become an error.
374 // The first case means that we must not immediately complete the Future,
375 // as our code would immediately start propagating the error without
376 // giving the time to install error-handlers.
377 // However the second case requires us to deal with the value immediately.
378 // Otherwise the value could complete with an error and report an
379 // unhandled error, even though we know we are already going to listen to
380 // it.
381
382 if (value == null) {
383 // No checks for `null`.
384 } else if (value is Future) {
385 // Assign to typed variables so we get earlier checks in checked mode.
386 Future<T> typedFuture = value;
387 if (typedFuture is _Future) {
388 _Future<T> coreFuture = typedFuture;
389 if (coreFuture._isComplete && coreFuture._hasError) {
390 // Case 1 from above. Delay completion to enable the user to register
391 // callbacks.
392 _markPendingCompletion();
393 _zone.scheduleMicrotask(() {
394 _chainCoreFuture(coreFuture, this);
395 });
396 } else {
397 _chainCoreFuture(coreFuture, this);
398 }
399 } else {
400 // Case 2 from above. Chain the future immidiately.
401 // Note that we are still completing asynchronously (through
402 // _chainForeignFuture)..
403 _chainForeignFuture(typedFuture, this);
404 }
405 return;
406 } else {
407 T typedValue = value;
408 }
409
410 _markPendingCompletion();
411 _zone.scheduleMicrotask(() {
412 _completeWithValue(value);
413 });
414 }
415
416 void _asyncCompleteError(error, StackTrace stackTrace) {
417 assert(!_isComplete);
418
419 _markPendingCompletion();
420 _zone.scheduleMicrotask(() {
421 _completeError(error, stackTrace);
422 });
423 }
424
425 /**
426 * Propagates the value/error of [source] to its [listeners], executing the
427 * listeners' callbacks.
428 */
429 static void _propagateToListeners(_Future source, _FutureListener listeners) {
430 while (true) {
431 assert(source._isComplete);
432 bool hasError = source._hasError;
433 if (listeners == null) {
434 if (hasError) {
435 AsyncError asyncError = source._error;
436 source._zone.handleUncaughtError(
437 asyncError.error, asyncError.stackTrace);
438 }
439 return;
440 }
441 // Usually futures only have one listener. If they have several, we
442 // call handle them separately in recursive calls, continuing
443 // here only when there is only one listener left.
444 while (listeners._nextListener != null) {
445 _FutureListener listener = listeners;
446 listeners = listener._nextListener;
447 listener._nextListener = null;
448 _propagateToListeners(source, listener);
449 }
450 _FutureListener listener = listeners;
451 // Do the actual propagation.
452 // Set initial state of listenerHasValue and listenerValueOrError. These
453 // variables are updated, with the outcome of potential callbacks.
454 bool listenerHasValue = true;
455 final sourceValue = hasError ? null : source._value;
456 var listenerValueOrError = sourceValue;
457 // Set to true if a whenComplete needs to wait for a future.
458 // The whenComplete action will resume the propagation by itself.
459 bool isPropagationAborted = false;
460 // TODO(floitsch): mark the listener as pending completion. Currently
461 // we can't do this, since the markPendingCompletion verifies that
462 // the future is not already marked (or chained).
463 // Only if we either have an error or callbacks, go into this, somewhat
464 // expensive, branch. Here we'll enter/leave the zone. Many futures
465 // doesn't have callbacks, so this is a significant optimization.
466 if (hasError || (listener.handlesValue || listener.handlesComplete)) {
467 Zone zone = listener._zone;
468 if (hasError && !source._zone.inSameErrorZone(zone)) {
469 // Don't cross zone boundaries with errors.
470 AsyncError asyncError = source._error;
471 source._zone.handleUncaughtError(
472 asyncError.error, asyncError.stackTrace);
473 return;
474 }
475
476 Zone oldZone;
477 if (!identical(Zone.current, zone)) {
478 // Change zone if it's not current.
479 oldZone = Zone._enter(zone);
480 }
481
482 bool handleValueCallback() {
483 try {
484 listenerValueOrError = zone.runUnary(listener._onValue,
485 sourceValue);
486 return true;
487 } catch (e, s) {
488 listenerValueOrError = new AsyncError(e, s);
489 return false;
490 }
491 }
492
493 void handleError() {
494 AsyncError asyncError = source._error;
495 bool matchesTest = true;
496 if (listener.hasErrorTest) {
497 _FutureErrorTest test = listener._errorTest;
498 try {
499 matchesTest = zone.runUnary(test, asyncError.error);
500 } catch (e, s) {
501 listenerValueOrError = identical(asyncError.error, e) ?
502 asyncError : new AsyncError(e, s);
503 listenerHasValue = false;
504 return;
505 }
506 }
507 Function errorCallback = listener._onError;
508 if (matchesTest && errorCallback != null) {
509 try {
510 if (errorCallback is ZoneBinaryCallback) {
511 listenerValueOrError = zone.runBinary(errorCallback,
512 asyncError.error,
513 asyncError.stackTrace);
514 } else {
515 listenerValueOrError = zone.runUnary(errorCallback,
516 asyncError.error);
517 }
518 } catch (e, s) {
519 listenerValueOrError = identical(asyncError.error, e) ?
520 asyncError : new AsyncError(e, s);
521 listenerHasValue = false;
522 return;
523 }
524 listenerHasValue = true;
525 } else {
526 // Copy over the error from the source.
527 listenerValueOrError = asyncError;
528 listenerHasValue = false;
529 }
530 }
531
532 void handleWhenCompleteCallback() {
533 var completeResult;
534 try {
535 completeResult = zone.run(listener._whenCompleteAction);
536 } catch (e, s) {
537 if (hasError && identical(source._error.error, e)) {
538 listenerValueOrError = source._error;
539 } else {
540 listenerValueOrError = new AsyncError(e, s);
541 }
542 listenerHasValue = false;
543 return;
544 }
545 if (completeResult is Future) {
546 _Future result = listener.result;
547 result._isChained = true;
548 isPropagationAborted = true;
549 completeResult.then((ignored) {
550 _propagateToListeners(source, new _FutureListener.chain(result));
551 }, onError: (error, [stackTrace]) {
552 // When there is an error, we have to make the error the new
553 // result of the current listener.
554 if (completeResult is! _Future) {
555 // This should be a rare case.
556 completeResult = new _Future();
557 completeResult._setError(error, stackTrace);
558 }
559 _propagateToListeners(completeResult,
560 new _FutureListener.chain(result));
561 });
562 }
563 }
564
565 if (!hasError) {
566 if (listener.handlesValue) {
567 listenerHasValue = handleValueCallback();
568 }
569 } else {
570 handleError();
571 }
572 if (listener.handlesComplete) {
573 handleWhenCompleteCallback();
574 }
575 // If we changed zone, oldZone will not be null.
576 if (oldZone != null) Zone._leave(oldZone);
577
578 if (isPropagationAborted) return;
579 // If the listener's value is a future we need to chain it. Note that
580 // this can only happen if there is a callback. Since 'is' checks
581 // can be expensive, we're trying to avoid it.
582 if (listenerHasValue &&
583 !identical(sourceValue, listenerValueOrError) &&
584 listenerValueOrError is Future) {
585 Future chainSource = listenerValueOrError;
586 // Shortcut if the chain-source is already completed. Just continue
587 // the loop.
588 _Future result = listener.result;
589 if (chainSource is _Future) {
590 if (chainSource._isComplete) {
591 // propagate the value (simulating a tail call).
592 result._isChained = true;
593 source = chainSource;
594 listeners = new _FutureListener.chain(result);
595 continue;
596 } else {
597 _chainCoreFuture(chainSource, result);
598 }
599 } else {
600 _chainForeignFuture(chainSource, result);
601 }
602 return;
603 }
604 }
605 _Future result = listener.result;
606 listeners = result._removeListeners();
607 if (listenerHasValue) {
608 result._setValue(listenerValueOrError);
609 } else {
610 AsyncError asyncError = listenerValueOrError;
611 result._setErrorObject(asyncError);
612 }
613 // Prepare for next round.
614 source = result;
615 }
616 }
617
618 Future timeout(Duration timeLimit, {onTimeout()}) {
619 if (_isComplete) return new _Future.immediate(this);
620 _Future result = new _Future();
621 Timer timer;
622 if (onTimeout == null) {
623 timer = new Timer(timeLimit, () {
624 result._completeError(new TimeoutException("Future not completed",
625 timeLimit));
626 });
627 } else {
628 Zone zone = Zone.current;
629 onTimeout = zone.registerCallback(onTimeout);
630 timer = new Timer(timeLimit, () {
631 try {
632 result._complete(zone.run(onTimeout));
633 } catch (e, s) {
634 result._completeError(e, s);
635 }
636 });
637 }
638 this.then((T v) {
639 if (timer.isActive) {
640 timer.cancel();
641 result._completeWithValue(v);
642 }
643 }, onError: (e, s) {
644 if (timer.isActive) {
645 timer.cancel();
646 result._completeError(e, s);
647 }
648 });
649 return result;
650 }
651 }
OLDNEW
« no previous file with comments | « test/generated_sdk/lib/async/future.dart ('k') | test/generated_sdk/lib/async/schedule_microtask.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698