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 // States shared by single/multi stream implementations. | 7 // States shared by single/multi stream implementations. |
| 8 | 8 |
| 9 /// Initial and default state where the stream can receive and send events. | 9 /// Initial and default state where the stream can receive and send events. |
| 10 const int _STREAM_OPEN = 0; | 10 const int _STREAM_OPEN = 0; |
| 11 /// The stream has received a request to complete, but hasn't done so yet. | 11 /// The stream has received a request to complete, but hasn't done so yet. |
| 12 /// No further events can be added to the stream. | 12 /// No further events can be added to the stream. |
| 13 const int _STREAM_CLOSED = 1; | 13 const int _STREAM_CLOSED = 1; |
| 14 /// The stream has completed and will no longer receive or send events. | 14 /// The stream has completed and will no longer receive or send events. |
| 15 /// Also counts as closed. The stream must not be paused when it's completed. | 15 /// Also counts as closed. The stream must not be paused when it's completed. |
| 16 /// Always used in conjunction with [_STREAM_CLOSED]. | 16 /// Always used in conjunction with [_STREAM_CLOSED]. |
| 17 const int _STREAM_COMPLETE = 2; | 17 const int _STREAM_COMPLETE = 2; |
| 18 /// Bit that alternates between events, and listeners are updated to the | 18 /// Bit that alternates between events, and listeners are updated to the |
| 19 /// current value when they are notified of the event. | 19 /// current value when they are notified of the event. |
| 20 const int _STREAM_EVENT_ID = 4; | 20 const int _STREAM_EVENT_ID = 4; |
| 21 const int _STREAM_EVENT_ID_SHIFT = 2; | 21 const int _STREAM_EVENT_ID_SHIFT = 2; |
| 22 /// Bit set while firing and clear while not. | 22 /// Bit set while firing and clear while not. |
| 23 const int _STREAM_FIRING = 8; | 23 const int _STREAM_FIRING = 8; |
| 24 /// Bit set while calling a pause-state or subscription-state change callback. | |
| 25 const int _STREAM_CALLBACK = 16; | |
| 24 /// The count of times a stream has paused is stored in the | 26 /// The count of times a stream has paused is stored in the |
| 25 /// state, shifted by this amount. | 27 /// state, shifted by this amount. |
| 26 const int _STREAM_PAUSE_COUNT_SHIFT = 4; | 28 const int _STREAM_PAUSE_COUNT_SHIFT = 8; |
| 27 | 29 |
| 28 // States for listeners. | 30 // States for listeners. |
| 29 | 31 |
| 30 /// The listener is currently not subscribed to its source stream. | 32 /// The listener is currently not subscribed to its source stream. |
| 31 const int _LISTENER_UNSUBSCRIBED = 0; | 33 const int _LISTENER_UNSUBSCRIBED = 0; |
| 32 /// The listener is actively subscribed to its source stream. | 34 /// The listener is actively subscribed to its source stream. |
| 33 const int _LISTENER_SUBSCRIBED = 1; | 35 const int _LISTENER_SUBSCRIBED = 1; |
| 34 /// The listener is subscribed until it has been notified of the current event. | 36 /// The listener is subscribed until it has been notified of the current event. |
| 35 /// This flag bit is always used in conjuction with [_LISTENER_SUBSCRIBED]. | 37 /// This flag bit is always used in conjuction with [_LISTENER_SUBSCRIBED]. |
| 36 const int _LISTENER_PENDING_UNSUBSCRIBE = 2; | 38 const int _LISTENER_PENDING_UNSUBSCRIBE = 2; |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 146 /** Whether one or more active subscribers have requested a pause. */ | 148 /** Whether one or more active subscribers have requested a pause. */ |
| 147 bool get _isPaused => _state >= (1 << _STREAM_PAUSE_COUNT_SHIFT); | 149 bool get _isPaused => _state >= (1 << _STREAM_PAUSE_COUNT_SHIFT); |
| 148 | 150 |
| 149 /** Check whether the pending event queue is non-empty */ | 151 /** Check whether the pending event queue is non-empty */ |
| 150 bool get _hasPendingEvent => | 152 bool get _hasPendingEvent => |
| 151 _pendingEvents != null && !_pendingEvents.isEmpty; | 153 _pendingEvents != null && !_pendingEvents.isEmpty; |
| 152 | 154 |
| 153 /** Whether we are currently firing an event. */ | 155 /** Whether we are currently firing an event. */ |
| 154 bool get _isFiring => (_state & _STREAM_FIRING) != 0; | 156 bool get _isFiring => (_state & _STREAM_FIRING) != 0; |
| 155 | 157 |
| 158 /** Whether the state bits allow firing. */ | |
| 159 bool get _mayFireState { | |
| 160 // The state disallows firing if: | |
| 161 // - an event is currently firing | |
| 162 // - a stat-change callback is being called | |
| 163 // - the pause-count is not zero. | |
| 164 const int mask = | |
| 165 _STREAM_FIRING | | |
| 166 _STREAM_CALLBACK | | |
| 167 ~((1 << _STREAM_PAUSE_COUNT_SHIFT) - 1); | |
| 168 return (_state & mask) == 0; | |
| 169 } | |
| 170 | |
| 156 int get _currentEventIdBit => | 171 int get _currentEventIdBit => |
| 157 (_state & _STREAM_EVENT_ID ) >> _STREAM_EVENT_ID_SHIFT; | 172 (_state & _STREAM_EVENT_ID ) >> _STREAM_EVENT_ID_SHIFT; |
| 158 | 173 |
| 159 /** Whether there is currently a subscriber on this [Stream]. */ | 174 /** Whether there is currently a subscriber on this [Stream]. */ |
| 160 bool get _hasSubscribers; | 175 bool get _hasSubscribers; |
| 161 | 176 |
| 162 /** Whether the stream can fire a new event. */ | 177 /** Whether the stream can fire a new event. */ |
| 163 bool get _canFireEvent => !_isFiring && !_isPaused && !_hasPendingEvent; | 178 bool get _canFireEvent => _mayFireState && !_hasPendingEvent; |
| 164 | 179 |
| 165 // State modification. | 180 // State modification. |
| 166 | 181 |
| 167 /** Record an increases in the number of times the listener has paused. */ | 182 /** Record an increases in the number of times the listener has paused. */ |
| 168 void _incrementPauseCount(_StreamListener<T> listener) { | 183 void _incrementPauseCount(_StreamListener<T> listener) { |
| 169 listener._incrementPauseCount(); | 184 listener._incrementPauseCount(); |
| 170 _updatePauseCount(1); | 185 _updatePauseCount(1); |
| 171 } | 186 } |
| 172 | 187 |
| 173 /** Record a decrease in the number of times the listener has paused. */ | 188 /** Record a decrease in the number of times the listener has paused. */ |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 209 // This sets the _STREAM_FIRING bit and toggles the _STREAM_EVENT_ID | 224 // This sets the _STREAM_FIRING bit and toggles the _STREAM_EVENT_ID |
| 210 // bit. All current subscribers will now have a _LISTENER_EVENT_ID | 225 // bit. All current subscribers will now have a _LISTENER_EVENT_ID |
| 211 // that doesn't match _STREAM_EVENT_ID, and they will receive the | 226 // that doesn't match _STREAM_EVENT_ID, and they will receive the |
| 212 // event being fired. | 227 // event being fired. |
| 213 _state ^= _STREAM_FIRING | _STREAM_EVENT_ID; | 228 _state ^= _STREAM_FIRING | _STREAM_EVENT_ID; |
| 214 } | 229 } |
| 215 | 230 |
| 216 void _endFiring() { | 231 void _endFiring() { |
| 217 assert(_isFiring); | 232 assert(_isFiring); |
| 218 _state ^= _STREAM_FIRING; | 233 _state ^= _STREAM_FIRING; |
| 219 if (_isPaused) _onPauseStateChange(); | 234 |
|
Anders Johnsen
2013/02/20 12:42:02
Extra space.
| |
| 220 if (!_hasSubscribers) _onSubscriptionStateChange(); | 235 if (!_hasSubscribers) { |
| 236 _callOnSubscriptionStateChange(); | |
| 237 } else if (_isPaused) { | |
| 238 _callOnPauseStateChange(); | |
| 239 } | |
| 221 } | 240 } |
| 222 | 241 |
| 223 /** | 242 /** |
| 224 * Record that a listener wants a pause from events. | 243 * Record that a listener wants a pause from events. |
| 225 * | 244 * |
| 226 * This methods is called from [_StreamListener.pause()]. | 245 * This methods is called from [_StreamListener.pause()]. |
| 227 * Subclasses can override this method, along with [isPaused] and | 246 * Subclasses can override this method, along with [isPaused] and |
| 228 * [createSubscription], if they want to do a different handling of paused | 247 * [createSubscription], if they want to do a different handling of paused |
| 229 * subscriptions, e.g., a filtering stream pausing its own source if all its | 248 * subscriptions, e.g., a filtering stream pausing its own source if all its |
| 230 * subscribers are paused. | 249 * subscribers are paused. |
| 231 */ | 250 */ |
| 232 void _pause(_StreamListener<T> listener, Future resumeSignal) { | 251 void _pause(_StreamListener<T> listener, Future resumeSignal) { |
| 233 assert(identical(listener._source, this)); | 252 assert(identical(listener._source, this)); |
| 234 if (!listener._isSubscribed) { | 253 if (!listener._isSubscribed) { |
| 235 throw new StateError("Subscription has been canceled."); | 254 throw new StateError("Subscription has been canceled."); |
| 236 } | 255 } |
| 237 assert(!_isComplete); // There can be no subscribers when complete. | 256 assert(!_isComplete); // There can be no subscribers when complete. |
| 238 bool wasPaused = _isPaused; | 257 bool wasPaused = _isPaused; |
| 239 _incrementPauseCount(listener); | 258 _incrementPauseCount(listener); |
| 240 if (resumeSignal != null) { | 259 if (resumeSignal != null) { |
| 241 resumeSignal.whenComplete(() { this._resume(listener, true); }); | 260 resumeSignal.whenComplete(() { this._resume(listener, true); }); |
| 242 } | 261 } |
| 243 if (!wasPaused && !_isFiring) { | 262 if (!wasPaused && !_isFiring) { |
| 244 _onPauseStateChange(); | 263 _callOnPauseStateChange(); |
| 245 } | 264 } |
| 246 } | 265 } |
| 247 | 266 |
| 248 /** Stops pausing due to one request from the given listener. */ | 267 /** Stops pausing due to one request from the given listener. */ |
| 249 void _resume(_StreamListener<T> listener, bool fromEvent) { | 268 void _resume(_StreamListener<T> listener, bool fromEvent) { |
| 250 if (!listener.isPaused) return; | 269 if (!listener.isPaused) return; |
| 251 assert(listener._isSubscribed); | 270 assert(listener._isSubscribed); |
| 252 assert(_isPaused); | 271 assert(_isPaused); |
| 253 _decrementPauseCount(listener); | 272 _decrementPauseCount(listener); |
| 254 if (!_isPaused) { | 273 if (!_isPaused) { |
| 255 if (!_isFiring) _onPauseStateChange(); | 274 if (!_isFiring) _callOnPauseStateChange(); |
| 256 if (_hasPendingEvent) { | 275 if (_hasPendingEvent) { |
| 257 // If we can fire events now, fire any pending events right away. | 276 // If we can fire events now, fire any pending events right away. |
| 258 if (fromEvent && !_isFiring) { | 277 if (fromEvent && !_isFiring) { |
| 259 _handlePendingEvents(); | 278 _handlePendingEvents(); |
| 260 } else { | 279 } else { |
| 261 _schedulePendingEvents(); | 280 _schedulePendingEvents(); |
| 262 } | 281 } |
| 263 } | 282 } |
| 264 } | 283 } |
| 265 } | 284 } |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 302 * Any change in the pause state is only reported after all subscribers have | 321 * Any change in the pause state is only reported after all subscribers have |
| 303 * received the event. | 322 * received the event. |
| 304 * | 323 * |
| 305 * The [action] must not throw, or the controller will be left in an | 324 * The [action] must not throw, or the controller will be left in an |
| 306 * invalid state. | 325 * invalid state. |
| 307 * | 326 * |
| 308 * This method must not be called while [isFiring] is true. | 327 * This method must not be called while [isFiring] is true. |
| 309 */ | 328 */ |
| 310 void _forEachSubscriber(void action(_StreamSubscriptionImpl<T> subscription)); | 329 void _forEachSubscriber(void action(_StreamSubscriptionImpl<T> subscription)); |
| 311 | 330 |
| 331 /** Calls [_onPauseStateChange] while setting callback bit. */ | |
| 332 void _callOnPauseStateChange() { | |
| 333 // After calling [_close], all pauses are handled internally by the Stream. | |
| 334 if (_isClosed) return; | |
| 335 _state |= _STREAM_CALLBACK; | |
| 336 _onPauseStateChange(); | |
| 337 _state ^= _STREAM_CALLBACK; | |
| 338 } | |
| 339 | |
| 340 /** Calls [_onSubscriptionStateChange] while setting callback bit. */ | |
| 341 void _callOnSubscriptionStateChange() { | |
| 342 _state |= _STREAM_CALLBACK; | |
| 343 _onSubscriptionStateChange(); | |
| 344 _state ^= _STREAM_CALLBACK; | |
| 345 } | |
| 346 | |
| 312 /** | 347 /** |
| 313 * Called when the first subscriber requests a pause or the last a resume. | 348 * Called when the first subscriber requests a pause or the last a resume. |
| 314 * | 349 * |
| 315 * Read [isPaused] to see the new state. | 350 * Read [isPaused] to see the new state. |
| 316 */ | 351 */ |
| 317 void _onPauseStateChange() {} | 352 void _onPauseStateChange() {} |
| 318 | 353 |
| 319 /** | 354 /** |
| 320 * Called when the first listener subscribes or the last unsubscribes. | 355 * Called when the first listener subscribes or the last unsubscribes. |
| 321 * | 356 * |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 423 * * [_onPauseStateChange]: Called when entering or leaving paused mode. | 458 * * [_onPauseStateChange]: Called when entering or leaving paused mode. |
| 424 * * [_hasSubscribers]: Test whether there are currently any subscribers. | 459 * * [_hasSubscribers]: Test whether there are currently any subscribers. |
| 425 * * [_isPaused]: Test whether the stream is currently paused. | 460 * * [_isPaused]: Test whether the stream is currently paused. |
| 426 * The user should not add new events while the stream is paused, but if it | 461 * The user should not add new events while the stream is paused, but if it |
| 427 * happens anyway, the stream will enqueue the events just as when new events | 462 * happens anyway, the stream will enqueue the events just as when new events |
| 428 * arrive while still firing an old event. | 463 * arrive while still firing an old event. |
| 429 */ | 464 */ |
| 430 class _SingleStreamImpl<T> extends _StreamImpl<T> { | 465 class _SingleStreamImpl<T> extends _StreamImpl<T> { |
| 431 _StreamListener _subscriber = null; | 466 _StreamListener _subscriber = null; |
| 432 | 467 |
| 433 /** Whether one or more active subscribers have requested a pause. */ | 468 // A single-stream is considered paused when it has no subscriber. |
| 469 // Exception is when it's complete (which only matters for pause-state-change | |
| 470 // callbacks), where it's not considered paused. | |
| 434 bool get _isPaused => (!_hasSubscribers && !_isComplete) || super._isPaused; | 471 bool get _isPaused => (!_hasSubscribers && !_isComplete) || super._isPaused; |
| 435 | 472 |
| 473 | |
| 474 // A single-stream is considered paused when it has no subscriber. | |
|
Anders Johnsen
2013/02/20 12:42:02
Comment.
| |
| 475 bool get _canFireEvent => | |
| 476 _mayFireState && !_hasPendingEvent && _hasSubscribers; | |
| 477 | |
| 478 | |
| 436 /** Whether there is currently a subscriber on this [Stream]. */ | 479 /** Whether there is currently a subscriber on this [Stream]. */ |
| 437 bool get _hasSubscribers => _subscriber != null; | 480 bool get _hasSubscribers => _subscriber != null; |
| 438 | 481 |
| 439 // ------------------------------------------------------------------- | 482 // ------------------------------------------------------------------- |
| 440 // Internal implementation. | 483 // Internal implementation. |
| 441 | 484 |
| 442 /** | 485 /** |
| 443 * Create the new subscription object. | 486 * Create the new subscription object. |
| 444 */ | 487 */ |
| 445 _StreamSubscriptionImpl<T> _createSubscription( | 488 _StreamSubscriptionImpl<T> _createSubscription( |
| 446 void onData(T data), | 489 void onData(T data), |
| 447 void onError(AsyncError error), | 490 void onError(AsyncError error), |
| 448 void onDone(), | 491 void onDone(), |
| 449 bool unsubscribeOnError) { | 492 bool unsubscribeOnError) { |
| 450 return new _StreamSubscriptionImpl<T>( | 493 return new _StreamSubscriptionImpl<T>( |
| 451 this, onData, onError, onDone, unsubscribeOnError); | 494 this, onData, onError, onDone, unsubscribeOnError); |
| 452 } | 495 } |
| 453 | 496 |
| 454 void _addListener(_StreamListener subscription) { | 497 void _addListener(_StreamListener subscription) { |
| 455 if (_hasSubscribers) { | 498 if (_hasSubscribers) { |
| 456 throw new StateError("Stream already has subscriber."); | 499 throw new StateError("Stream already has subscriber."); |
| 457 } | 500 } |
| 458 _subscriber = subscription; | 501 _subscriber = subscription; |
| 459 subscription._setSubscribed(0); | 502 subscription._setSubscribed(0); |
| 460 _onSubscriptionStateChange(); | 503 _callOnSubscriptionStateChange(); |
| 461 if (_hasPendingEvent) { | 504 if (_hasPendingEvent) { |
| 462 _schedulePendingEvents(); | 505 _schedulePendingEvents(); |
| 463 } | 506 } |
| 464 } | 507 } |
| 465 | 508 |
| 466 /** | 509 /** |
| 467 * Handle a cancel requested from a [_StreamSubscriptionImpl]. | 510 * Handle a cancel requested from a [_StreamSubscriptionImpl]. |
| 468 * | 511 * |
| 469 * This method is called from [_StreamSubscriptionImpl.cancel]. | 512 * This method is called from [_StreamSubscriptionImpl.cancel]. |
| 470 * | 513 * |
| 471 * If an event is currently firing, the cancel is delayed | 514 * If an event is currently firing, the cancel is delayed |
| 472 * until after the subscriber has received the event. | 515 * until after the subscriber has received the event. |
| 473 */ | 516 */ |
| 474 void _cancel(_StreamListener subscriber) { | 517 void _cancel(_StreamListener subscriber) { |
| 475 assert(identical(subscriber._source, this)); | 518 assert(identical(subscriber._source, this)); |
| 476 // We allow unsubscribing the currently firing subscription during | 519 // We allow unsubscribing the currently firing subscription during |
| 477 // the event firing, because it is indistinguishable from delaying it since | 520 // the event firing, because it is indistinguishable from delaying it since |
| 478 // that event has already received the event. | 521 // that event has already received the event. |
| 479 if (!identical(_subscriber, subscriber)) { | 522 if (!identical(_subscriber, subscriber)) { |
| 480 // You may unsubscribe more than once, only the first one counts. | 523 // You may unsubscribe more than once, only the first one counts. |
| 481 return; | 524 return; |
| 482 } | 525 } |
| 483 _subscriber = null; | 526 _subscriber = null; |
| 484 // Unsubscribing a paused subscription also cancels its pauses. | 527 // Unsubscribing a paused subscription also cancels its pauses. |
| 485 int subscriptionPauseCount = subscriber._setUnsubscribed(); | 528 int subscriptionPauseCount = subscriber._setUnsubscribed(); |
| 486 _updatePauseCount(-subscriptionPauseCount); | 529 _updatePauseCount(-subscriptionPauseCount); |
| 487 if (!_isFiring) { | 530 if (!_isFiring) { |
| 488 if (subscriptionPauseCount > 0) { | 531 _callOnSubscriptionStateChange(); |
| 489 _onPauseStateChange(); | |
| 490 } | |
| 491 _onSubscriptionStateChange(); | |
| 492 } | 532 } |
| 493 } | 533 } |
| 494 | 534 |
| 495 void _forEachSubscriber( | 535 void _forEachSubscriber( |
| 496 void action(_StreamListener<T> subscription)) { | 536 void action(_StreamListener<T> subscription)) { |
| 497 assert(!_isPaused); | 537 assert(!_isPaused); |
| 498 _StreamListener subscription = _subscriber; | 538 _StreamListener subscription = _subscriber; |
| 499 assert(subscription != null); | 539 assert(subscription != null); |
| 500 _startFiring(); | 540 _startFiring(); |
| 501 action(subscription); | 541 action(subscription); |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 600 } | 640 } |
| 601 } | 641 } |
| 602 _endFiring(); | 642 _endFiring(); |
| 603 } | 643 } |
| 604 | 644 |
| 605 void _addListener(_StreamListener listener) { | 645 void _addListener(_StreamListener listener) { |
| 606 listener._setSubscribed(_currentEventIdBit); | 646 listener._setSubscribed(_currentEventIdBit); |
| 607 bool firstSubscriber = !_hasSubscribers; | 647 bool firstSubscriber = !_hasSubscribers; |
| 608 _InternalLinkList.add(this, listener); | 648 _InternalLinkList.add(this, listener); |
| 609 if (firstSubscriber) { | 649 if (firstSubscriber) { |
| 610 _onSubscriptionStateChange(); | 650 _callOnSubscriptionStateChange(); |
| 611 } | 651 } |
| 612 } | 652 } |
| 613 | 653 |
| 614 /** | 654 /** |
| 615 * Handle a cancel requested from a [_StreamListener]. | 655 * Handle a cancel requested from a [_StreamListener]. |
| 616 * | 656 * |
| 617 * This method is called from [_StreamListener.cancel]. | 657 * This method is called from [_StreamListener.cancel]. |
| 618 * | 658 * |
| 619 * If an event is currently firing, the cancel is delayed | 659 * If an event is currently firing, the cancel is delayed |
| 620 * until after the subscribers have received the event. | 660 * until after the subscribers have received the event. |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 633 // The listener has been notified of the event (or don't need to, | 673 // The listener has been notified of the event (or don't need to, |
| 634 // if it's still pending subscription) so it's safe to remove it. | 674 // if it's still pending subscription) so it's safe to remove it. |
| 635 _removeListener(listener); | 675 _removeListener(listener); |
| 636 } | 676 } |
| 637 // Pause and subscription state changes are reported when we end | 677 // Pause and subscription state changes are reported when we end |
| 638 // firing. | 678 // firing. |
| 639 } else { | 679 } else { |
| 640 bool wasPaused = _isPaused; | 680 bool wasPaused = _isPaused; |
| 641 _removeListener(listener); | 681 _removeListener(listener); |
| 642 if (wasPaused != _isPaused) _onPauseStateChange(); | 682 if (wasPaused != _isPaused) _onPauseStateChange(); |
| 643 if (!_hasSubscribers) _onSubscriptionStateChange(); | 683 if (!_hasSubscribers) _callOnSubscriptionStateChange(); |
| 644 } | 684 } |
| 645 } | 685 } |
| 646 | 686 |
| 647 /** | 687 /** |
| 648 * Removes a listener from this stream and cancels its pauses. | 688 * Removes a listener from this stream and cancels its pauses. |
| 649 * | 689 * |
| 650 * This is a low-level action that doesn't call [_onSubscriptionStateChange]. | 690 * This is a low-level action that doesn't call [_onSubscriptionStateChange]. |
| 651 * or [_onPauseStateChange]. | 691 * or [_callOnPauseStateChange]. |
| 652 */ | 692 */ |
| 653 void _removeListener(_StreamListener listener) { | 693 void _removeListener(_StreamListener listener) { |
| 654 int pauseCount = listener._setUnsubscribed(); | 694 int pauseCount = listener._setUnsubscribed(); |
| 655 _updatePauseCount(-pauseCount); | 695 _updatePauseCount(-pauseCount); |
| 656 _InternalLinkList.remove(listener); | 696 _InternalLinkList.remove(listener); |
| 657 } | 697 } |
| 658 } | 698 } |
| 659 | 699 |
| 660 | 700 |
| 661 /** Stream that generates its own events. */ | 701 /** Stream that generates its own events. */ |
| (...skipping 469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1131 _pauseCount = 0; | 1171 _pauseCount = 0; |
| 1132 } | 1172 } |
| 1133 } | 1173 } |
| 1134 | 1174 |
| 1135 class _SingleStreamMultiplexer<T> extends _MultiStreamImpl<T> { | 1175 class _SingleStreamMultiplexer<T> extends _MultiStreamImpl<T> { |
| 1136 final _SingleStreamImpl<T> _source; | 1176 final _SingleStreamImpl<T> _source; |
| 1137 StreamSubscription<T> _subscription; | 1177 StreamSubscription<T> _subscription; |
| 1138 | 1178 |
| 1139 _SingleStreamMultiplexer(this._source); | 1179 _SingleStreamMultiplexer(this._source); |
| 1140 | 1180 |
| 1141 void _onPauseStateChange() { | 1181 void _callOnPauseStateChange() { |
| 1142 if (_isPaused) { | 1182 if (_isPaused) { |
| 1143 if (_subscription != null) { | 1183 if (_subscription != null) { |
| 1144 _subscription.pause(); | 1184 _subscription.pause(); |
| 1145 } | 1185 } |
| 1146 } else { | 1186 } else { |
| 1147 if (_subscription != null) { | 1187 if (_subscription != null) { |
| 1148 _subscription.resume(); | 1188 _subscription.resume(); |
| 1149 } | 1189 } |
| 1150 } | 1190 } |
| 1151 } | 1191 } |
| 1152 | 1192 |
| 1153 /** | 1193 /** |
| 1154 * Subscribe or unsubscribe on [_source] depending on whether | 1194 * Subscribe or unsubscribe on [_source] depending on whether |
| 1155 * [_stream] has subscribers. | 1195 * [_stream] has subscribers. |
| 1156 */ | 1196 */ |
| 1157 void _onSubscriptionStateChange() { | 1197 void _onSubscriptionStateChange() { |
| 1158 if (_hasSubscribers) { | 1198 if (_hasSubscribers) { |
| 1159 assert(_subscription == null); | 1199 assert(_subscription == null); |
| 1160 _subscription = _source.listen(this._add, | 1200 _subscription = _source.listen(this._add, |
| 1161 onError: this._signalError, | 1201 onError: this._signalError, |
| 1162 onDone: this._close); | 1202 onDone: this._close); |
| 1163 } else { | 1203 } else { |
| 1164 // TODO(lrn): Check why this can happen. | 1204 // TODO(lrn): Check why this can happen. |
| 1165 if (_subscription == null) return; | 1205 if (_subscription == null) return; |
| 1166 _subscription.cancel(); | 1206 _subscription.cancel(); |
| 1167 _subscription = null; | 1207 _subscription = null; |
| 1168 } | 1208 } |
| 1169 } | 1209 } |
| 1170 } | 1210 } |
| OLD | NEW |