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

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

Issue 269283007: Make errors from StreamController onCancel calls end up in the returned future. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address comments. Created 6 years, 7 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/stream.dart ('k') | tests/lib/async/stream_controller_test.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 // ------------------------------------------------------------------- 7 // -------------------------------------------------------------------
8 // Controller for creating and adding events to a stream. 8 // Controller for creating and adding events to a stream.
9 // ------------------------------------------------------------------- 9 // -------------------------------------------------------------------
10 10
(...skipping 402 matching lines...) Expand 10 before | Expand all | Expand 10 after
413 * After closing, no further events may be added using [add] or [addError]. 413 * After closing, no further events may be added using [add] or [addError].
414 * 414 *
415 * You are allowed to close the controller more than once, but only the first 415 * You are allowed to close the controller more than once, but only the first
416 * call has any effect. 416 * call has any effect.
417 * 417 *
418 * The first time a controller is closed, a "done" event is sent to its 418 * The first time a controller is closed, a "done" event is sent to its
419 * stream. 419 * stream.
420 */ 420 */
421 Future close() { 421 Future close() {
422 if (isClosed) { 422 if (isClosed) {
423 _ensureDoneFuture(); 423 return _ensureDoneFuture();
424 return _doneFuture;
425 } 424 }
426 if (!_mayAddEvent) throw _badEventState(); 425 if (!_mayAddEvent) throw _badEventState();
427 _state |= _STATE_CLOSED; 426 _state |= _STATE_CLOSED;
428 if (hasListener) { 427 if (hasListener) {
429 _sendDone(); 428 _sendDone();
430 } else if (_isInitialState) { 429 } else if (_isInitialState) {
431 _ensurePendingEvents().add(const _DelayedDone()); 430 _ensurePendingEvents().add(const _DelayedDone());
432 } 431 }
433 _ensureDoneFuture(); 432 return _ensureDoneFuture();
434 return _doneFuture;
435 } 433 }
436 434
437 // EventSink interface. Used by the [addStream] events. 435 // EventSink interface. Used by the [addStream] events.
438 436
439 // Add data event, used both by the [addStream] events and by [add]. 437 // Add data event, used both by the [addStream] events and by [add].
440 void _add(T value) { 438 void _add(T value) {
441 if (hasListener) { 439 if (hasListener) {
442 _sendData(value); 440 _sendData(value);
443 } else if (_isInitialState) { 441 } else if (_isInitialState) {
444 _ensurePendingEvents().add(new _DelayedData<T>(value)); 442 _ensurePendingEvents().add(new _DelayedData<T>(value));
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
482 } 480 }
483 subscription._setPendingEvents(pendingEvents); 481 subscription._setPendingEvents(pendingEvents);
484 subscription._guardCallback(() { 482 subscription._guardCallback(() {
485 _runGuarded(_onListen); 483 _runGuarded(_onListen);
486 }); 484 });
487 485
488 return subscription; 486 return subscription;
489 } 487 }
490 488
491 Future _recordCancel(StreamSubscription<T> subscription) { 489 Future _recordCancel(StreamSubscription<T> subscription) {
490 // When we cancel, we first cancel any stream being added,
491 // Then we call _onCancel, and finally the _doneFuture is completed.
492 // If either of addStream's cancel or _onCancel returns a future,
493 // we wait for it before continuing.
494 // Any error during this process ends up in the returned future.
495 // If more errors happen, we act as if it happens inside nested try/finallys
496 // or whenComplete calls, and only the last error ends up in the
497 // returned future.
498 Future result;
492 if (_isAddingStream) { 499 if (_isAddingStream) {
493 _StreamControllerAddStreamState addState = _varData; 500 _StreamControllerAddStreamState addState = _varData;
494 addState.cancel(); 501 result = addState.cancel();
495 } 502 }
496 _varData = null; 503 _varData = null;
497 _state = 504 _state =
498 (_state & ~(_STATE_SUBSCRIBED | _STATE_ADDSTREAM)) | _STATE_CANCELED; 505 (_state & ~(_STATE_SUBSCRIBED | _STATE_ADDSTREAM)) | _STATE_CANCELED;
499 506
507 if (_onCancel != null) {
508 if (result == null) {
509 // Only introduce a future if one is needed.
510 // If _onCancel returns null, no future is needed.
511 try {
512 result = _onCancel();
513 } catch (e, s) {
514 // Return the error in the returned future.
515 // Complete it asynchronously, so there is time for a listener
516 // to handle the error.
517 result = new _Future().._asyncCompleteError(e, s);
518 }
519 } else {
520 // Simpler case when we already know that we will return a future.
521 result = result.whenComplete(_onCancel);
522 }
523 }
524
500 void complete() { 525 void complete() {
501 if (_doneFuture != null && _doneFuture._mayComplete) { 526 if (_doneFuture != null && _doneFuture._mayComplete) {
502 _doneFuture._asyncComplete(null); 527 _doneFuture._asyncComplete(null);
503 } 528 }
504 } 529 }
505 530
506 Future future = _runGuarded(_onCancel); 531 if (result != null) {
507 if (future != null) { 532 result = result.whenComplete(complete);
508 future = future.whenComplete(complete);
509 } else { 533 } else {
510 complete(); 534 complete();
511 } 535 }
512 return future; 536
537 return result;
513 } 538 }
514 539
515 void _recordPause(StreamSubscription<T> subscription) { 540 void _recordPause(StreamSubscription<T> subscription) {
516 if (_isAddingStream) { 541 if (_isAddingStream) {
517 _StreamControllerAddStreamState addState = _varData; 542 _StreamControllerAddStreamState addState = _varData;
518 addState.pause(); 543 addState.pause();
519 } 544 }
520 _runGuarded(_onPause); 545 _runGuarded(_onPause);
521 } 546 }
522 547
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
696 }; 721 };
697 722
698 void pause() { 723 void pause() {
699 addSubscription.pause(); 724 addSubscription.pause();
700 } 725 }
701 726
702 void resume() { 727 void resume() {
703 addSubscription.resume(); 728 addSubscription.resume();
704 } 729 }
705 730
706 void cancel() { 731 /**
707 addSubscription.cancel(); 732 * Stop adding the stream.
708 complete(); 733 *
734 * Complete the future returned by `StreamController.addStream` when
735 * the cancel is complete.
736 *
737 * Return a future if the cancel takes time, otherwise return `null`.
738 */
739 Future cancel() {
740 var cancel = addSubscription.cancel();
741 if (cancel == null) {
742 addStreamFuture._asyncComplete(null);
743 return null;
744 }
745 return cancel.whenComplete(() { addStreamFuture._asyncComplete(null); });
709 } 746 }
710 747
711 void complete() { 748 void complete() {
712 addStreamFuture._asyncComplete(null); 749 addStreamFuture._asyncComplete(null);
713 } 750 }
714 } 751 }
715 752
716 class _StreamControllerAddStreamState<T> extends _AddStreamState<T> { 753 class _StreamControllerAddStreamState<T> extends _AddStreamState<T> {
717 // The subscription or pending data of a _StreamController. 754 // The subscription or pending data of a _StreamController.
718 // Stored here because we reuse the `_varData` field in the _StreamController 755 // Stored here because we reuse the `_varData` field in the _StreamController
719 // to store this state object. 756 // to store this state object.
720 var varData; 757 var varData;
721 758
722 _StreamControllerAddStreamState(_StreamController controller, 759 _StreamControllerAddStreamState(_StreamController controller,
723 this.varData, 760 this.varData,
724 Stream source, 761 Stream source,
725 bool cancelOnError) 762 bool cancelOnError)
726 : super(controller, source, cancelOnError) { 763 : super(controller, source, cancelOnError) {
727 if (controller.isPaused) { 764 if (controller.isPaused) {
728 addSubscription.pause(); 765 addSubscription.pause();
729 } 766 }
730 } 767 }
731 } 768 }
OLDNEW
« no previous file with comments | « sdk/lib/async/stream.dart ('k') | tests/lib/async/stream_controller_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698