| 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 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 StreamSink<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, the returned stream controller is a |
| 57 * during an [add], [addError] or [close] call. If [sync] is false, the event | 57 * [SynchronousStreamController], and must be used with the care |
| 58 * will be passed to the listener at a later time, after the code creating | 58 * and attention necessary to not break the [Stream] contract. |
| 59 * the event has returned. | |
| 60 * | 59 * |
| 61 * The controller will buffer all incoming events until the subscriber is | 60 * The controller will buffer all incoming events until the subscriber is |
| 62 * registered. | 61 * registered. |
| 63 * | 62 * |
| 64 * The [onPause] function is called when the stream becomes | 63 * The [onPause] function is called when the stream becomes |
| 65 * paused. [onResume] is called when the stream resumed. | 64 * paused. [onResume] is called when the stream resumed. |
| 66 * | 65 * |
| 67 * The [onListen] callback is called when the stream | 66 * The [onListen] callback is called when the stream |
| 68 * receives its listener and [onCancel] when the listener ends | 67 * receives its listener and [onCancel] when the listener ends |
| 69 * its subscription. If [onCancel] needs to perform an asynchronous operation, | 68 * its subscription. If [onCancel] needs to perform an asynchronous operation, |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 101 * call has returned. The controller does not have any internal queue of | 100 * call has returned. The controller does not have any internal queue of |
| 102 * events, and if there are no listeners at the time the event is added, | 101 * events, and if there are no listeners at the time the event is added, |
| 103 * it will just be dropped, or, if it is an error, be reported as uncaught. | 102 * it will just be dropped, or, if it is an error, be reported as uncaught. |
| 104 * | 103 * |
| 105 * Each listener subscription is handled independently, | 104 * Each listener subscription is handled independently, |
| 106 * and if one pauses, only the pausing listener is affected. | 105 * and if one pauses, only the pausing listener is affected. |
| 107 * A paused listener will buffer events internally until unpaused or canceled. | 106 * A paused listener will buffer events internally until unpaused or canceled. |
| 108 * | 107 * |
| 109 * If [sync] is true, events may be fired directly by the stream's | 108 * If [sync] is true, events may be fired directly by the stream's |
| 110 * subscriptions during an [add], [addError] or [close] call. | 109 * subscriptions during an [add], [addError] or [close] call. |
| 111 * If [sync] is false, the event will be fired at a later time, | 110 * The returned stream controller is a [SynchronousStreamController], |
| 111 * and must be used with the care and attention necessary to not break |
| 112 * the [Stream] contract. |
| 113 * |
| 114 * If [sync] is false, the event will always be fired at a later time, |
| 112 * after the code adding the event has completed. | 115 * after the code adding the event has completed. |
| 113 * | 116 * In that case, no guarantees are given with regard to when |
| 114 * When [sync] is false, no guarantees are given with regard to when | |
| 115 * multiple listeners get the events, except that each listener will get | 117 * multiple listeners get the events, except that each listener will get |
| 116 * all events in the correct order. Each subscription handles the events | 118 * all events in the correct order. Each subscription handles the events |
| 117 * individually. | 119 * individually. |
| 118 * If two events are sent on an async controller with two listeners, | 120 * If two events are sent on an async controller with two listeners, |
| 119 * one of the listeners may get both events | 121 * one of the listeners may get both events |
| 120 * before the other listener gets any. | 122 * before the other listener gets any. |
| 121 * A listener must be subscribed both when the event is initiated | 123 * A listener must be subscribed both when the event is initiated |
| 122 * (that is, when [add] is called) | 124 * (that is, when [add] is called) |
| 123 * and when the event is later delivered, | 125 * and when the event is later delivered, |
| 124 * in order to receive the event. | 126 * in order to receive the event. |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 195 * | 197 * |
| 196 * If [cancelOnError] is true, only the first error on [source] is | 198 * If [cancelOnError] is true, only the first error on [source] is |
| 197 * forwarded to the controller's stream, and the `addStream` ends | 199 * forwarded to the controller's stream, and the `addStream` ends |
| 198 * after this. If [cancelOnError] is false, all errors are forwarded | 200 * after this. If [cancelOnError] is false, all errors are forwarded |
| 199 * and only a done event will end the `addStream`. | 201 * and only a done event will end the `addStream`. |
| 200 */ | 202 */ |
| 201 Future addStream(Stream<T> source, {bool cancelOnError: true}); | 203 Future addStream(Stream<T> source, {bool cancelOnError: true}); |
| 202 } | 204 } |
| 203 | 205 |
| 204 | 206 |
| 207 /** |
| 208 * A stream controller that delivers its events synchronously. |
| 209 * |
| 210 * A synchronous stream controller is intended for cases where |
| 211 * an already asynchronous event triggers an event on a stream. |
| 212 * |
| 213 * Instead of adding the event to the stream in a later microtask, |
| 214 * causing extra latency, the event is instead fired immediately by the |
| 215 * synchronous stream controller, as if the stream event was |
| 216 * the current event or microtask. |
| 217 * |
| 218 * The synchronous stream controller can be used to break the contract |
| 219 * on [Stream], and it must be used carefully to avoid doing so. |
| 220 * |
| 221 * The only advantage to using a [SynchronousStreamController] over a |
| 222 * normal [StreamController] is the improved latency. |
| 223 * Only use the synchronous version if the improvement is significant, |
| 224 * and if its use is safe. Otherwise just use a normal stream controller, |
| 225 * which will always have the correct behavior for a [Stream], and won't |
| 226 * accidentally break other code. |
| 227 * |
| 228 * Adding events to a synchronous controller should only happen as the |
| 229 * very last part of a the handling of the original event. |
| 230 * At that point, adding an event to the stream is equivalent to |
| 231 * returning to the event loop and adding the event in the next microtask. |
| 232 * |
| 233 * Each listener callback will be run as if it was a top-level event |
| 234 * or microtask. This means that if it throws, the error will be reported as |
| 235 * uncaught as soon as possible. |
| 236 * This is one reason to add the event as the last thing in the original event |
| 237 * handler - any action done after adding the event will delay the report of |
| 238 * errors in the event listener callbacks. |
| 239 * |
| 240 * If an event is added in a setting that isn't known to be another event, |
| 241 * it may cause the stream's listener to get that event before the listener |
| 242 * is ready to handle it. We promise that after calling [Stream.listen], |
| 243 * you won't get any events until the code doing the listen has completed. |
| 244 * Calling [add] in response to a function call of unknown origin may break |
| 245 * that promise. |
| 246 * |
| 247 * An [onListen] callback from the controller is *not* an asynchronous event, |
| 248 * and adding events to the controller in the `onListen` callback is always |
| 249 * wrong. The events will be delivered before the listener has even received |
| 250 * the subscription yet. |
| 251 * |
| 252 * The synchronous broadcast stream controller also has a restrictions that a |
| 253 * normal stream controller does not: |
| 254 * The [add], [addError], [close] and [addStream] methods *must not* be |
| 255 * called while an event is being delivered. |
| 256 * That is, if a callback on a subscription on the controller's stream causes |
| 257 * a call to any of the functions above, the call will fail. |
| 258 * A broadcast stream may have more than one listener, and if an |
| 259 * event is added synchronously while another is being also in the process |
| 260 * of being added, the latter event might reach some listeners before |
| 261 * the former. To prevent that, an event cannot be added while a previous |
| 262 * event is being fired. |
| 263 * This guarantees that an event is fully delivered when the |
| 264 * first [add], [addError] or [close] returns, |
| 265 * and further events will be delivered in the correct order. |
| 266 * |
| 267 * This still only guarantees that the event is delivered to the subscription. |
| 268 * If the subscription is paused, the actual callback may still happen later, |
| 269 * and the event will instead be buffered by the subscription. |
| 270 * Barring pausing, and the following buffered events that haven't been |
| 271 * delivered yet, callbacks will be called synchronously when an event is added. |
| 272 * |
| 273 * Adding an event to a synchronous non-broadcast stream controller while |
| 274 * another event is in progress may cause the second event to be delayed |
| 275 * and not be delivered synchronously, and until that event is delivered, |
| 276 * the controller will not act synchronously. |
| 277 */ |
| 278 abstract class SynchronousStreamController<T> implements StreamController<T> { |
| 279 /** |
| 280 * Adds event to the controller's stream. |
| 281 * |
| 282 * As [StreamController.add], but must not be called while an event is |
| 283 * being added by [add], [addError] or [close]. |
| 284 */ |
| 285 void add(T data); |
| 286 |
| 287 /** |
| 288 * Adds error to the controller's stream. |
| 289 * |
| 290 * As [StreamController.addError], but must not be called while an event is |
| 291 * being added by [add], [addError] or [close]. |
| 292 */ |
| 293 void addError(Object error, StackTrace stackTrace); |
| 294 |
| 295 /** |
| 296 * Closes the controller's stream. |
| 297 * |
| 298 * As [StreamController.close], but must not be called while an event is |
| 299 * being added by [add], [addError] or [close]. |
| 300 */ |
| 301 Future close(); |
| 302 } |
| 303 |
| 205 abstract class _StreamControllerLifecycle<T> { | 304 abstract class _StreamControllerLifecycle<T> { |
| 206 StreamSubscription<T> _subscribe( | 305 StreamSubscription<T> _subscribe( |
| 207 void onData(T data), | 306 void onData(T data), |
| 208 Function onError, | 307 Function onError, |
| 209 void onDone(), | 308 void onDone(), |
| 210 bool cancelOnError); | 309 bool cancelOnError); |
| 211 void _recordPause(StreamSubscription<T> subscription) {} | 310 void _recordPause(StreamSubscription<T> subscription) {} |
| 212 void _recordResume(StreamSubscription<T> subscription) {} | 311 void _recordResume(StreamSubscription<T> subscription) {} |
| 213 Future _recordCancel(StreamSubscription<T> subscription) => null; | 312 Future _recordCancel(StreamSubscription<T> subscription) => null; |
| 214 } | 313 } |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 414 */ | 513 */ |
| 415 void add(T value) { | 514 void add(T value) { |
| 416 if (!_mayAddEvent) throw _badEventState(); | 515 if (!_mayAddEvent) throw _badEventState(); |
| 417 _add(value); | 516 _add(value); |
| 418 } | 517 } |
| 419 | 518 |
| 420 /** | 519 /** |
| 421 * Send or enqueue an error event. | 520 * Send or enqueue an error event. |
| 422 */ | 521 */ |
| 423 void addError(Object error, [StackTrace stackTrace]) { | 522 void addError(Object error, [StackTrace stackTrace]) { |
| 523 if (!_mayAddEvent) throw _badEventState(); |
| 424 error = _nonNullError(error); | 524 error = _nonNullError(error); |
| 425 if (!_mayAddEvent) throw _badEventState(); | |
| 426 AsyncError replacement = Zone.current.errorCallback(error, stackTrace); | 525 AsyncError replacement = Zone.current.errorCallback(error, stackTrace); |
| 427 if (replacement != null) { | 526 if (replacement != null) { |
| 428 error = _nonNullError(replacement.error); | 527 error = _nonNullError(replacement.error); |
| 429 stackTrace = replacement.stackTrace; | 528 stackTrace = replacement.stackTrace; |
| 430 } | 529 } |
| 431 _addError(error, stackTrace); | 530 _addError(error, stackTrace); |
| 432 } | 531 } |
| 433 | 532 |
| 434 /** | 533 /** |
| 435 * Closes this controller and sends a done event on the stream. | 534 * Closes this controller and sends a done event on the stream. |
| 436 * | 535 * |
| 437 * The first time a controller is closed, a "done" event is added to its | 536 * The first time a controller is closed, a "done" event is added to its |
| 438 * stream. | 537 * stream. |
| 439 * | 538 * |
| 440 * You are allowed to close the controller more than once, but only the first | 539 * You are allowed to close the controller more than once, but only the first |
| 441 * call has any effect. | 540 * call has any effect. |
| 442 * | 541 * |
| 443 * After closing, no further events may be added using [add] or [addError]. | 542 * After closing, no further events may be added using [add], [addError] |
| 543 * or [addStream]. |
| 444 * | 544 * |
| 445 * The returned future is completed when the done event has been delivered. | 545 * The returned future is completed when the done event has been delivered. |
| 446 */ | 546 */ |
| 447 Future close() { | 547 Future close() { |
| 448 if (isClosed) { | 548 if (isClosed) { |
| 449 return _ensureDoneFuture(); | 549 return _ensureDoneFuture(); |
| 450 } | 550 } |
| 451 if (!_mayAddEvent) throw _badEventState(); | 551 if (!_mayAddEvent) throw _badEventState(); |
| 452 _closeUnchecked(); | 552 _closeUnchecked(); |
| 453 return _ensureDoneFuture(); | 553 return _ensureDoneFuture(); |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 583 void _recordResume(StreamSubscription<T> subscription) { | 683 void _recordResume(StreamSubscription<T> subscription) { |
| 584 if (_isAddingStream) { | 684 if (_isAddingStream) { |
| 585 _StreamControllerAddStreamState addState = _varData; | 685 _StreamControllerAddStreamState addState = _varData; |
| 586 addState.resume(); | 686 addState.resume(); |
| 587 } | 687 } |
| 588 _runGuarded(_onResume); | 688 _runGuarded(_onResume); |
| 589 } | 689 } |
| 590 } | 690 } |
| 591 | 691 |
| 592 abstract class _SyncStreamControllerDispatch<T> | 692 abstract class _SyncStreamControllerDispatch<T> |
| 593 implements _StreamController<T> { | 693 implements _StreamController<T>, SynchronousStreamController<T> { |
| 694 int get _state; |
| 695 void set _state(int state); |
| 696 |
| 594 void _sendData(T data) { | 697 void _sendData(T data) { |
| 595 _subscription._add(data); | 698 _subscription._add(data); |
| 596 } | 699 } |
| 597 | 700 |
| 598 void _sendError(Object error, StackTrace stackTrace) { | 701 void _sendError(Object error, StackTrace stackTrace) { |
| 599 _subscription._addError(error, stackTrace); | 702 _subscription._addError(error, stackTrace); |
| 600 } | 703 } |
| 601 | 704 |
| 602 void _sendDone() { | 705 void _sendDone() { |
| 603 _subscription._close(); | 706 _subscription._close(); |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 799 _StreamControllerAddStreamState(_StreamController controller, | 902 _StreamControllerAddStreamState(_StreamController controller, |
| 800 this.varData, | 903 this.varData, |
| 801 Stream source, | 904 Stream source, |
| 802 bool cancelOnError) | 905 bool cancelOnError) |
| 803 : super(controller, source, cancelOnError) { | 906 : super(controller, source, cancelOnError) { |
| 804 if (controller.isPaused) { | 907 if (controller.isPaused) { |
| 805 addSubscription.pause(); | 908 addSubscription.pause(); |
| 806 } | 909 } |
| 807 } | 910 } |
| 808 } | 911 } |
| OLD | NEW |