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