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

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

Issue 48733002: Fix bugs in StreamController.addStream. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 1 month 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/broadcast_stream_controller.dart ('k') | tests/co19/co19-co19.status » ('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 28 matching lines...) Expand all
39 * Whether to invoke a callback depends only on the state before and after 39 * Whether to invoke a callback depends only on the state before and after
40 * a stream action, for example firing an event. If the state changes multiple 40 * a stream action, for example firing an event. If the state changes multiple
41 * times during the action, and then ends up in the same state as before, no 41 * times during the action, and then ends up in the same state as before, no
42 * callback is performed. 42 * callback is performed.
43 * 43 *
44 * If listeners are added after the stream has completed (sent a "done" event), 44 * If listeners are added after the stream has completed (sent a "done" event),
45 * the listeners will be sent a "done" event eventually, but they won't affect 45 * the listeners will be sent a "done" event eventually, but they won't affect
46 * the stream at all, and won't trigger callbacks. From the controller's point 46 * the stream at all, and won't trigger callbacks. From the controller's point
47 * of view, the stream is completely inert when has completed. 47 * of view, the stream is completely inert when has completed.
48 */ 48 */
49 abstract class StreamController<T> implements StreamSink<T> { 49 abstract class StreamController<T> implements StreamControllerSink<T> {
50 /** The stream that this controller is controlling. */ 50 /** The stream that this controller is controlling. */
51 Stream<T> get stream; 51 Stream<T> get stream;
52 52
53 /** 53 /**
54 * A controller with a [stream] that supports only one single subscriber. 54 * A controller with a [stream] that supports only one single subscriber.
55 * 55 *
56 * If [sync] is true, events may be passed directly to the stream's listener 56 * If [sync] is true, events may be passed directly to the stream's listener
57 * during an [add], [addError] or [close] call. If [sync] is false, the event 57 * during an [add], [addError] or [close] call. If [sync] is false, the event
58 * will be passed to the listener at a later time, after the code creating 58 * will be passed to the listener at a later time, after the code creating
59 * the event has returned. 59 * the event has returned.
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
127 void onCancel(), 127 void onCancel(),
128 bool sync: false}) { 128 bool sync: false}) {
129 return sync 129 return sync
130 ? new _SyncBroadcastStreamController<T>(onListen, onCancel) 130 ? new _SyncBroadcastStreamController<T>(onListen, onCancel)
131 : new _AsyncBroadcastStreamController<T>(onListen, onCancel); 131 : new _AsyncBroadcastStreamController<T>(onListen, onCancel);
132 } 132 }
133 133
134 /** 134 /**
135 * Returns a view of this object that only exposes the [StreamSink] interface. 135 * Returns a view of this object that only exposes the [StreamSink] interface.
136 */ 136 */
137 StreamSink<T> get sink; 137 StreamControllerSink<T> get sink;
138 138
139 /** 139 /**
140 * Whether the stream is closed for adding more events. 140 * Whether the stream is closed for adding more events.
141 * 141 *
142 * If true, the "done" event might not have fired yet, but it has been 142 * If true, the "done" event might not have fired yet, but it has been
143 * scheduled, and it is too late to add more events. 143 * scheduled, and it is too late to add more events.
144 */ 144 */
145 bool get isClosed; 145 bool get isClosed;
146 146
147 /** 147 /**
(...skipping 14 matching lines...) Expand all
162 162
163 /** 163 /**
164 * Send or enqueue an error event. 164 * Send or enqueue an error event.
165 * 165 *
166 * Also allows an objection stack trace object, on top of what [EventSink] 166 * Also allows an objection stack trace object, on top of what [EventSink]
167 * allows. 167 * allows.
168 */ 168 */
169 void addError(Object error, [StackTrace stackTrace]); 169 void addError(Object error, [StackTrace stackTrace]);
170 } 170 }
171 171
172 /**
173 * Extension of [StreamSink] with optional `cancelOnError` parameter
174 * on `addStream`.
175 *
176 * This interface is implemented by [StreamController] and by the
177 * `StreamSink` returned by [StreamController.sink].
178 */
179 abstract class StreamControllerSink<T> extends StreamSink<T> {
Anders Johnsen 2013/10/28 13:44:26 Is this worth a hole new type? dart:async is alrea
Anders Johnsen 2013/10/28 13:44:26 Thinking some more about it, I think it's a proper
Lasse Reichstein Nielsen 2013/10/29 08:49:45 You are right, it's too much overhead just so that
180 Future addStream(Stream<T> source, { bool cancelOnError: true });
181 }
182
172 183
173 abstract class _StreamControllerLifecycle<T> { 184 abstract class _StreamControllerLifecycle<T> {
174 StreamSubscription<T> _subscribe(bool cancelOnError); 185 StreamSubscription<T> _subscribe(bool cancelOnError);
175 void _recordPause(StreamSubscription<T> subscription) {} 186 void _recordPause(StreamSubscription<T> subscription) {}
176 void _recordResume(StreamSubscription<T> subscription) {} 187 void _recordResume(StreamSubscription<T> subscription) {}
177 Future _recordCancel(StreamSubscription<T> subscription) => null; 188 Future _recordCancel(StreamSubscription<T> subscription) => null;
178 } 189 }
179 190
180 /** 191 /**
181 * Default implementation of [StreamController]. 192 * Default implementation of [StreamController].
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
257 _NotificationHandler get _onPause; 268 _NotificationHandler get _onPause;
258 _NotificationHandler get _onResume; 269 _NotificationHandler get _onResume;
259 _NotificationHandler get _onCancel; 270 _NotificationHandler get _onCancel;
260 271
261 // Return a new stream every time. The streams are equal, but not identical. 272 // Return a new stream every time. The streams are equal, but not identical.
262 Stream<T> get stream => new _ControllerStream(this); 273 Stream<T> get stream => new _ControllerStream(this);
263 274
264 /** 275 /**
265 * Returns a view of this object that only exposes the [StreamSink] interface. 276 * Returns a view of this object that only exposes the [StreamSink] interface.
266 */ 277 */
267 StreamSink<T> get sink => new _StreamSinkWrapper<T>(this); 278 StreamControllerSink<T> get sink => new _StreamSinkWrapper<T>(this);
268 279
269 /** 280 /**
270 * Whether a listener has existed and been canceled. 281 * Whether a listener has existed and been canceled.
271 * 282 *
272 * After this, adding more events will be ignored. 283 * After this, adding more events will be ignored.
273 */ 284 */
274 bool get _isCanceled => (_state & _STATE_CANCELED) != 0; 285 bool get _isCanceled => (_state & _STATE_CANCELED) != 0;
275 286
276 /** Whether there is an active listener. */ 287 /** Whether there is an active listener. */
277 bool get hasListener => (_state & _STATE_SUBSCRIBED) != 0; 288 bool get hasListener => (_state & _STATE_SUBSCRIBED) != 0;
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
337 */ 348 */
338 Error _badEventState() { 349 Error _badEventState() {
339 if (isClosed) { 350 if (isClosed) {
340 return new StateError("Cannot add event after closing"); 351 return new StateError("Cannot add event after closing");
341 } 352 }
342 assert(_isAddingStream); 353 assert(_isAddingStream);
343 return new StateError("Cannot add event while adding a stream"); 354 return new StateError("Cannot add event while adding a stream");
344 } 355 }
345 356
346 // StreamSink interface. 357 // StreamSink interface.
347 Future addStream(Stream<T> source) { 358 /**
359 * Receives events from [source] and puts them into this controller's stream.
360 *
361 * Returns a future which completes when the stream adding is done.
Anders Johnsen 2013/10/28 13:44:26 ... when the source stream is done.
Lasse Reichstein Nielsen 2013/10/29 08:49:45 Done.
362 *
363 * Events must not be added directly to this controller using [add],
364 * [addError], [close] or [addStream], until the returned future
365 * is complete.
366 *
367 * Data and error events are forwarded to this controller's stream. A done
368 * event on the source will end the `addStream` operation and complete the
369 * returned future.
370 *
371 * If [cancelOnError] is true, only the first error on [source] is
372 * forwarded to the controller's stream, and the `addStream` ends
373 * after theis. If [cancelOnError] is false, all errors are forwarded
374 * and only a done event from
375 */
376 Future addStream(Stream<T> source, { bool cancelOnError: true }) {
348 if (!_mayAddEvent) throw _badEventState(); 377 if (!_mayAddEvent) throw _badEventState();
349 if (_isCanceled) return new _Future.immediate(null); 378 if (_isCanceled) return new _Future.immediate(null);
350 _StreamControllerAddStreamState addState = 379 _StreamControllerAddStreamState addState =
351 new _StreamControllerAddStreamState(this, _varData, source); 380 new _StreamControllerAddStreamState(this, _varData, source,
381 cancelOnError);
Anders Johnsen 2013/10/28 13:44:26 Nit: argument should be on one line or each on a l
Lasse Reichstein Nielsen 2013/10/29 08:49:45 That's silly. But done.
352 _varData = addState; 382 _varData = addState;
353 _state |= _STATE_ADDSTREAM; 383 _state |= _STATE_ADDSTREAM;
354 return addState.addStreamFuture; 384 return addState.addStreamFuture;
355 } 385 }
356 386
357 Future get done => _ensureDoneFuture(); 387 Future get done => _ensureDoneFuture();
358 388
359 Future _ensureDoneFuture() { 389 Future _ensureDoneFuture() {
360 if (_doneFuture == null) { 390 if (_doneFuture == null) {
361 _doneFuture = new _Future(); 391 _doneFuture = new _Future();
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
447 throw new StateError("Stream has already been listened to."); 477 throw new StateError("Stream has already been listened to.");
448 } 478 }
449 _ControllerSubscription subscription = 479 _ControllerSubscription subscription =
450 new _ControllerSubscription(this, cancelOnError); 480 new _ControllerSubscription(this, cancelOnError);
451 481
452 _PendingEvents pendingEvents = _pendingEvents; 482 _PendingEvents pendingEvents = _pendingEvents;
453 _state |= _STATE_SUBSCRIBED; 483 _state |= _STATE_SUBSCRIBED;
454 if (_isAddingStream) { 484 if (_isAddingStream) {
455 _StreamControllerAddStreamState addState = _varData; 485 _StreamControllerAddStreamState addState = _varData;
456 addState.varData = subscription; 486 addState.varData = subscription;
487 addState.resume();
457 } else { 488 } else {
458 _varData = subscription; 489 _varData = subscription;
459 } 490 }
460 subscription._setPendingEvents(pendingEvents); 491 subscription._setPendingEvents(pendingEvents);
461 subscription._guardCallback(() { 492 subscription._guardCallback(() {
462 _runGuarded(_onListen); 493 _runGuarded(_onListen);
463 }); 494 });
464 495
465 return subscription; 496 return subscription;
466 } 497 }
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
625 _controller._recordPause(this); 656 _controller._recordPause(this);
626 } 657 }
627 658
628 void _onResume() { 659 void _onResume() {
629 _controller._recordResume(this); 660 _controller._recordResume(this);
630 } 661 }
631 } 662 }
632 663
633 664
634 /** A class that exposes only the [StreamSink] interface of an object. */ 665 /** A class that exposes only the [StreamSink] interface of an object. */
635 class _StreamSinkWrapper<T> implements StreamSink<T> { 666 class _StreamSinkWrapper<T> implements StreamControllerSink<T> {
636 final StreamSink _target; 667 final StreamController _target;
637 _StreamSinkWrapper(this._target); 668 _StreamSinkWrapper(this._target);
638 void add(T data) { _target.add(data); } 669 void add(T data) { _target.add(data); }
639 void addError(Object error, [StackTrace stackTrace]) { 670 void addError(Object error, [StackTrace stackTrace]) {
640 _target.addError(error); 671 _target.addError(error);
641 } 672 }
642 Future close() => _target.close(); 673 Future close() => _target.close();
643 Future addStream(Stream<T> source) => _target.addStream(source); 674 Future addStream(Stream<T> source, { bool cancelOnError: true})
675 => _target.addStream(source, cancelOnError: cancelOnError);
644 Future get done => _target.done; 676 Future get done => _target.done;
645 } 677 }
646 678
647 /** 679 /**
648 * Object containing the state used to handle [StreamController.addStream]. 680 * Object containing the state used to handle [StreamController.addStream].
649 */ 681 */
650 class _AddStreamState<T> { 682 class _AddStreamState<T> {
651 // [_Future] returned by call to addStream. 683 // [_Future] returned by call to addStream.
652 _Future addStreamFuture; 684 final _Future addStreamFuture;
653 685
654 // Subscription on stream argument to addStream. 686 // Subscription on stream argument to addStream.
655 StreamSubscription addSubscription; 687 final StreamSubscription addSubscription;
656 688
657 _AddStreamState(_EventSink<T> controller, Stream source) 689 _AddStreamState(_EventSink<T> controller, Stream source, bool cancelOnError)
658 : addStreamFuture = new _Future(), 690 : addStreamFuture = new _Future(),
659 addSubscription = source.listen(controller._add, 691 addSubscription = source.listen(controller._add,
660 onError: controller._addError, 692 onError: cancelOnError
693 ? makeErrorHandler(controller)
694 : controller._addError,
661 onDone: controller._close, 695 onDone: controller._close,
662 cancelOnError: true); 696 cancelOnError: cancelOnError);
697
698 static makeErrorHandler(_EventSink<T> controller) =>
699 (e, StackTrace s) {
700 controller._addError(e, s);
701 controller._close();
702 };
663 703
664 void pause() { 704 void pause() {
665 addSubscription.pause(); 705 addSubscription.pause();
666 } 706 }
667 707
668 void resume() { 708 void resume() {
669 addSubscription.resume(); 709 addSubscription.resume();
670 } 710 }
671 711
672 void cancel() { 712 void cancel() {
673 addSubscription.cancel(); 713 addSubscription.cancel();
674 complete(); 714 complete();
675 } 715 }
676 716
677 void complete() { 717 void complete() {
678 addStreamFuture._asyncComplete(null); 718 addStreamFuture._asyncComplete(null);
679 } 719 }
680 } 720 }
681 721
682 class _StreamControllerAddStreamState<T> extends _AddStreamState<T> { 722 class _StreamControllerAddStreamState<T> extends _AddStreamState<T> {
683 // The subscription or pending data of a _StreamController. 723 // The subscription or pending data of a _StreamController.
684 // Stored here because we reuse the `_varData` field in the _StreamController 724 // Stored here because we reuse the `_varData` field in the _StreamController
685 // to store this state object. 725 // to store this state object.
686 var varData; 726 var varData;
687 727
688 _StreamControllerAddStreamState(_StreamController controller, 728 _StreamControllerAddStreamState(_StreamController controller,
689 this.varData, 729 this.varData,
690 Stream source) : super(controller, source) { 730 Stream source,
731 bool cancelOnError)
732 : super(controller, source, cancelOnError) {
691 if (controller.isPaused) { 733 if (controller.isPaused) {
692 addSubscription.pause(); 734 addSubscription.pause();
693 } 735 }
694 } 736 }
695 } 737 }
OLDNEW
« no previous file with comments | « sdk/lib/async/broadcast_stream_controller.dart ('k') | tests/co19/co19-co19.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698