| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 library scheduled_test.scheduled_stream; | 5 library scheduled_test.scheduled_stream; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:collection'; | 8 import 'dart:collection'; |
| 9 | 9 |
| 10 import 'package:stack_trace/stack_trace.dart'; | 10 import 'package:stack_trace/stack_trace.dart'; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 33 /// | 33 /// |
| 34 /// If this is non-null, [_pendingValues] will always be empty, since any | 34 /// If this is non-null, [_pendingValues] will always be empty, since any |
| 35 /// value coming in will be passed to this completer. | 35 /// value coming in will be passed to this completer. |
| 36 Completer<T> _nextCompleter; | 36 Completer<T> _nextCompleter; |
| 37 | 37 |
| 38 /// The completer for emitting a value requested by [hasNext]. | 38 /// The completer for emitting a value requested by [hasNext]. |
| 39 Completer<bool> _hasNextCompleter; | 39 Completer<bool> _hasNextCompleter; |
| 40 | 40 |
| 41 /// The set of all streams forked from this one. | 41 /// The set of all streams forked from this one. |
| 42 final _forks = new Set<ScheduledStream<T>>(); | 42 final _forks = new Set<ScheduledStream<T>>(); |
| 43 final _forkControllers = new Set<StreamController<T>>(); |
| 43 | 44 |
| 44 /// The queue of values emitted by [_stream] but not yet emitted through | 45 /// The queue of values emitted by [_stream] but not yet emitted through |
| 45 /// [next]. | 46 /// [next]. |
| 46 final _pendingValues = new Queue<Fallible<T>>(); | 47 final _pendingValues = new Queue<Fallible<T>>(); |
| 47 | 48 |
| 48 /// All values emitted by this stream so far. | 49 /// All values emitted by this stream so far. |
| 49 /// | 50 /// |
| 50 /// This does not include values emitted by the underlying stream but not yet | 51 /// This does not include values emitted by the underlying stream but not yet |
| 51 /// emitted through [next]. | 52 /// emitted through [next]. |
| 52 List<T> get emittedValues => new UnmodifiableListView(_emittedValues); | 53 List<T> get emittedValues => new UnmodifiableListView(_emittedValues); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 65 /// Whether the wrapped stream has been closed. | 66 /// Whether the wrapped stream has been closed. |
| 66 bool _isDone = false; | 67 bool _isDone = false; |
| 67 | 68 |
| 68 /// Whether [next] has been called but has not yet returned. | 69 /// Whether [next] has been called but has not yet returned. |
| 69 /// | 70 /// |
| 70 /// This is distinct from `_nextCompleter != null` when [next] is called while | 71 /// This is distinct from `_nextCompleter != null` when [next] is called while |
| 71 /// there are pending values available, until the future it returns completes. | 72 /// there are pending values available, until the future it returns completes. |
| 72 bool _isNextPending = false; | 73 bool _isNextPending = false; |
| 73 | 74 |
| 74 /// Creates a new scheduled stream wrapping [stream]. | 75 /// Creates a new scheduled stream wrapping [stream]. |
| 75 ScheduledStream(Stream<T> stream) | 76 ScheduledStream(this._stream) { |
| 76 : _stream = stream.asBroadcastStream() { | |
| 77 _subscription = _stream.listen((value) { | 77 _subscription = _stream.listen((value) { |
| 78 for (var c in _forkControllers) { |
| 79 c.add(value); |
| 80 } |
| 78 if (_hasNextCompleter != null) { | 81 if (_hasNextCompleter != null) { |
| 79 _hasNextCompleter.complete(true); | 82 _hasNextCompleter.complete(true); |
| 80 _hasNextCompleter = null; | 83 _hasNextCompleter = null; |
| 81 } | 84 } |
| 82 | 85 |
| 83 if (_nextCompleter != null) { | 86 if (_nextCompleter != null) { |
| 84 _nextCompleter.complete(value); | 87 _nextCompleter.complete(value); |
| 85 _emittedValues.add(value); | 88 _emittedValues.add(value); |
| 86 _nextCompleter = null; | 89 _nextCompleter = null; |
| 87 _isNextPending = false; | 90 _isNextPending = false; |
| 88 } else { | 91 } else { |
| 89 _pendingValues.add(new Fallible.withValue(value)); | 92 _pendingValues.add(new Fallible.withValue(value)); |
| 90 } | 93 } |
| 91 }, onError: (error, stackTrace) { | 94 }, onError: (error, stackTrace) { |
| 95 for (var c in _forkControllers) { |
| 96 c.addError(error, stackTrace); |
| 97 } |
| 92 if (_hasNextCompleter != null) { | 98 if (_hasNextCompleter != null) { |
| 93 _hasNextCompleter.completeError(error, stackTrace); | 99 _hasNextCompleter.completeError(error, stackTrace); |
| 94 _hasNextCompleter = null; | 100 _hasNextCompleter = null; |
| 95 } | 101 } |
| 96 | 102 |
| 97 if (_nextCompleter != null) { | 103 if (_nextCompleter != null) { |
| 98 _nextCompleter.completeError(error, stackTrace); | 104 _nextCompleter.completeError(error, stackTrace); |
| 99 _nextCompleter = null; | 105 _nextCompleter = null; |
| 100 } else { | 106 } else { |
| 101 _pendingValues.add(new Fallible.withError(error, stackTrace)); | 107 _pendingValues.add(new Fallible.withError(error, stackTrace)); |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 198 /// closed at whatever point it's currently at. | 204 /// closed at whatever point it's currently at. |
| 199 ScheduledStream<T> fork() { | 205 ScheduledStream<T> fork() { |
| 200 var controller = new StreamController<T>(); | 206 var controller = new StreamController<T>(); |
| 201 for (var valueOrError in _pendingValues) { | 207 for (var valueOrError in _pendingValues) { |
| 202 if (valueOrError.hasValue) { | 208 if (valueOrError.hasValue) { |
| 203 controller.add(valueOrError.value); | 209 controller.add(valueOrError.value); |
| 204 } else { | 210 } else { |
| 205 controller.addError(valueOrError.error, valueOrError.stackTrace); | 211 controller.addError(valueOrError.error, valueOrError.stackTrace); |
| 206 } | 212 } |
| 207 } | 213 } |
| 208 | |
| 209 if (_isDone) { | 214 if (_isDone) { |
| 210 controller.close(); | 215 controller.close(); |
| 211 } else { | 216 } else { |
| 212 _stream.pipe(controller); | 217 _forkControllers.add(controller); |
| 213 } | 218 } |
| 214 | 219 |
| 215 var fork = new ScheduledStream<T>(controller.stream); | 220 var fork = new ScheduledStream<T>(controller.stream); |
| 216 _forks.add(fork); | 221 _forks.add(fork); |
| 217 return fork; | 222 return fork; |
| 218 } | 223 } |
| 219 | 224 |
| 220 /// Closes this stream. | 225 /// Closes this stream. |
| 221 /// | 226 /// |
| 222 /// This cancels the subscription to the underlying stream and acts as though | 227 /// This cancels the subscription to the underlying stream and acts as though |
| 223 /// [this] was closed immediately after the current position, regardless of | 228 /// [this] was closed immediately after the current position, regardless of |
| 224 /// whether the underlying stream has emitted additional events. | 229 /// whether the underlying stream has emitted additional events. |
| 225 void close() { | 230 void close() { |
| 226 _subscription.cancel(); | 231 _subscription.cancel(); |
| 227 _pendingValues.clear(); | 232 _pendingValues.clear(); |
| 228 | 233 |
| 229 for (var fork in _forks) { | 234 for (var fork in _forks) { |
| 230 fork.close(); | 235 fork.close(); |
| 231 } | 236 } |
| 232 _forks.clear(); | 237 _forks.clear(); |
| 233 | 238 |
| 234 if (!_isDone) _onDone(); | 239 if (!_isDone) _onDone(); |
| 235 } | 240 } |
| 236 | 241 |
| 237 /// Handles a "done" event from the underlying stream, as well as [this] being | 242 /// Handles a "done" event from the underlying stream, as well as [this] being |
| 238 /// closed. | 243 /// closed. |
| 239 void _onDone() { | 244 void _onDone() { |
| 245 for (var c in _forkControllers) { |
| 246 c.close(); |
| 247 } |
| 248 _forkControllers.clear(); |
| 249 |
| 240 if (_hasNextCompleter != null) { | 250 if (_hasNextCompleter != null) { |
| 241 _hasNextCompleter.complete(false); | 251 _hasNextCompleter.complete(false); |
| 242 _hasNextCompleter = null; | 252 _hasNextCompleter = null; |
| 243 } | 253 } |
| 244 | 254 |
| 245 if (_nextCompleter != null) { | 255 if (_nextCompleter != null) { |
| 246 _nextCompleter.completeError( | 256 _nextCompleter.completeError( |
| 247 new StateError("ScheduledStream has no more elements."), | 257 new StateError("ScheduledStream has no more elements."), |
| 248 new Chain.current()); | 258 new Chain.current()); |
| 249 _nextCompleter = null; | 259 _nextCompleter = null; |
| 250 _isNextPending = false; | 260 _isNextPending = false; |
| 251 } | 261 } |
| 252 | 262 |
| 253 _isDone = true; | 263 _isDone = true; |
| 254 } | 264 } |
| 255 } | 265 } |
| OLD | NEW |