Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 } |
| OLD | NEW |