| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 part of dart.async; | |
| 6 | |
| 7 // ------------------------------------------------------------------- | |
| 8 // Core Stream types | |
| 9 // ------------------------------------------------------------------- | |
| 10 | |
| 11 /** | |
| 12 * A source of asynchronous data events. | |
| 13 * | |
| 14 * A Stream provides a way to receive a sequence of events. | |
| 15 * Each event is either a data event or an error event, | |
| 16 * representing the result of a single computation. | |
| 17 * When the events provided by a Stream have all been sent, | |
| 18 * a single "done" event will mark the end. | |
| 19 * | |
| 20 * You can [listen] on a stream to make it start generating events, | |
| 21 * and to set up listeners that receive the events. | |
| 22 * When you listen, you receive a [StreamSubscription] object | |
| 23 * which is the active object providing the events, | |
| 24 * and which can be used to stop listening again, | |
| 25 * or to temporarily pause events from the subscription. | |
| 26 * | |
| 27 * There are two kinds of streams: "Single-subscription" streams and | |
| 28 * "broadcast" streams. | |
| 29 * | |
| 30 * *A single-subscription stream* allows only a single listener during the whole | |
| 31 * lifetime of the stream. | |
| 32 * It doesn't start generating events until it has a listener, | |
| 33 * and it stops sending events when the listener is unsubscribed, | |
| 34 * even if the source of events could still provide more. | |
| 35 * | |
| 36 * Listening twice on a single-subscription stream is not allowed, even after | |
| 37 * the first subscription has been canceled. | |
| 38 * | |
| 39 * Single-subscription streams are generally used for streaming chunks of | |
| 40 * larger contiguous data like file I/O. | |
| 41 * | |
| 42 * *A broadcast stream* allows any number of listeners, and it fires | |
| 43 * its events when they are ready, whether there are listeners or not. | |
| 44 * | |
| 45 * Broadcast streams are used for independent events/observers. | |
| 46 * | |
| 47 * If several listeners want to listen to a single subscription stream, | |
| 48 * use [asBroadcastStream] to create a broadcast stream on top of the | |
| 49 * non-broadcast stream. | |
| 50 * | |
| 51 * On either kind of stream, stream transformationss, such as [where] and | |
| 52 * [skip], return the same type of stream as the one the method was called on, | |
| 53 * unless otherwise noted. | |
| 54 * | |
| 55 * When an event is fired, the listener(s) at that time will receive the event. | |
| 56 * If a listener is added to a broadcast stream while an event is being fired, | |
| 57 * that listener will not receive the event currently being fired. | |
| 58 * If a listener is canceled, it immediately stops receiving events. | |
| 59 * | |
| 60 * When the "done" event is fired, subscribers are unsubscribed before | |
| 61 * receiving the event. After the event has been sent, the stream has no | |
| 62 * subscribers. Adding new subscribers to a broadcast stream after this point | |
| 63 * is allowed, but they will just receive a new "done" event as soon | |
| 64 * as possible. | |
| 65 * | |
| 66 * Stream subscriptions always respect "pause" requests. If necessary they need | |
| 67 * to buffer their input, but often, and preferably, they can simply request | |
| 68 * their input to pause too. | |
| 69 * | |
| 70 * The default implementation of [isBroadcast] returns false. | |
| 71 * A broadcast stream inheriting from [Stream] must override [isBroadcast] | |
| 72 * to return `true`. | |
| 73 */ | |
| 74 abstract class Stream<T> { | |
| 75 Stream(); | |
| 76 | |
| 77 /** | |
| 78 * Creates a new single-subscription stream from the future. | |
| 79 * | |
| 80 * When the future completes, the stream will fire one event, either | |
| 81 * data or error, and then close with a done-event. | |
| 82 */ | |
| 83 factory Stream.fromFuture(Future<T> future) { | |
| 84 // Use the controller's buffering to fill in the value even before | |
| 85 // the stream has a listener. For a single value, it's not worth it | |
| 86 // to wait for a listener before doing the `then` on the future. | |
| 87 _StreamController<T> controller = | |
| 88 new StreamController<T>(sync: true) as _StreamController<T>; | |
| 89 future.then((value) { | |
| 90 controller._add(value); | |
| 91 controller._closeUnchecked(); | |
| 92 }, | |
| 93 onError: (error, stackTrace) { | |
| 94 controller._addError(error, stackTrace); | |
| 95 controller._closeUnchecked(); | |
| 96 }); | |
| 97 return controller.stream; | |
| 98 } | |
| 99 | |
| 100 /** | |
| 101 * Creates a single-subscription stream that gets its data from [data]. | |
| 102 * | |
| 103 * The iterable is iterated when the stream receives a listener, and stops | |
| 104 * iterating if the listener cancels the subscription. | |
| 105 * | |
| 106 * If iterating [data] throws an error, the stream ends immediately with | |
| 107 * that error. No done event will be sent (iteration is not complete), but no | |
| 108 * further data events will be generated either, since iteration cannot | |
| 109 * continue. | |
| 110 */ | |
| 111 factory Stream.fromIterable(Iterable<T> data) { | |
| 112 return new _GeneratedStreamImpl<T>( | |
| 113 () => new _IterablePendingEvents<T>(data)); | |
| 114 } | |
| 115 | |
| 116 /** | |
| 117 * Creates a stream that repeatedly emits events at [period] intervals. | |
| 118 * | |
| 119 * The event values are computed by invoking [computation]. The argument to | |
| 120 * this callback is an integer that starts with 0 and is incremented for | |
| 121 * every event. | |
| 122 * | |
| 123 * If [computation] is omitted the event values will all be `null`. | |
| 124 */ | |
| 125 factory Stream.periodic(Duration period, | |
| 126 [T computation(int computationCount)]) { | |
| 127 if (computation == null) computation = ((i) => null); | |
| 128 | |
| 129 Timer timer; | |
| 130 int computationCount = 0; | |
| 131 StreamController<T> controller; | |
| 132 // Counts the time that the Stream was running (and not paused). | |
| 133 Stopwatch watch = new Stopwatch(); | |
| 134 | |
| 135 void sendEvent() { | |
| 136 watch.reset(); | |
| 137 T data = computation(computationCount++); | |
| 138 controller.add(data); | |
| 139 } | |
| 140 | |
| 141 void startPeriodicTimer() { | |
| 142 assert(timer == null); | |
| 143 timer = new Timer.periodic(period, (Timer timer) { | |
| 144 sendEvent(); | |
| 145 }); | |
| 146 } | |
| 147 | |
| 148 controller = new StreamController<T>(sync: true, | |
| 149 onListen: () { | |
| 150 watch.start(); | |
| 151 startPeriodicTimer(); | |
| 152 }, | |
| 153 onPause: () { | |
| 154 timer.cancel(); | |
| 155 timer = null; | |
| 156 watch.stop(); | |
| 157 }, | |
| 158 onResume: () { | |
| 159 assert(timer == null); | |
| 160 Duration elapsed = watch.elapsed; | |
| 161 watch.start(); | |
| 162 timer = new Timer(period - elapsed, () { | |
| 163 timer = null; | |
| 164 startPeriodicTimer(); | |
| 165 sendEvent(); | |
| 166 }); | |
| 167 }, | |
| 168 onCancel: () { | |
| 169 if (timer != null) timer.cancel(); | |
| 170 timer = null; | |
| 171 }); | |
| 172 return controller.stream; | |
| 173 } | |
| 174 | |
| 175 /** | |
| 176 * Creates a stream where all events of an existing stream are piped through | |
| 177 * a sink-transformation. | |
| 178 * | |
| 179 * The given [mapSink] closure is invoked when the returned stream is | |
| 180 * listened to. All events from the [source] are added into the event sink | |
| 181 * that is returned from the invocation. The transformation puts all | |
| 182 * transformed events into the sink the [mapSink] closure received during | |
| 183 * its invocation. Conceptually the [mapSink] creates a transformation pipe | |
| 184 * with the input sink being the returned [EventSink] and the output sink | |
| 185 * being the sink it received. | |
| 186 * | |
| 187 * This constructor is frequently used to build transformers. | |
| 188 * | |
| 189 * Example use for a duplicating transformer: | |
| 190 * | |
| 191 * class DuplicationSink implements EventSink<String> { | |
| 192 * final EventSink<String> _outputSink; | |
| 193 * DuplicationSink(this._outputSink); | |
| 194 * | |
| 195 * void add(String data) { | |
| 196 * _outputSink.add(data); | |
| 197 * _outputSink.add(data); | |
| 198 * } | |
| 199 * | |
| 200 * void addError(e, [st]) => _outputSink(e, st); | |
| 201 * void close() => _outputSink.close(); | |
| 202 * } | |
| 203 * | |
| 204 * class DuplicationTransformer implements StreamTransformer<String, Strin
g> { | |
| 205 * // Some generic types ommitted for brevety. | |
| 206 * Stream bind(Stream stream) => new Stream<String>.eventTransform( | |
| 207 * stream, | |
| 208 * (EventSink sink) => new DuplicationSink(sink)); | |
| 209 * } | |
| 210 * | |
| 211 * stringStream.transform(new DuplicationTransformer()); | |
| 212 * | |
| 213 * The resulting stream is a broadcast stream if [source] is. | |
| 214 */ | |
| 215 factory Stream.eventTransformed(Stream source, | |
| 216 EventSink mapSink(EventSink<T> sink)) { | |
| 217 return new _BoundSinkStream(source, mapSink); | |
| 218 } | |
| 219 | |
| 220 /** | |
| 221 * Reports whether this stream is a broadcast stream. | |
| 222 */ | |
| 223 bool get isBroadcast => false; | |
| 224 | |
| 225 /** | |
| 226 * Returns a multi-subscription stream that produces the same events as this. | |
| 227 * | |
| 228 * The returned stream will subscribe to this stream when its first | |
| 229 * subscriber is added, and will stay subscribed until this stream ends, | |
| 230 * or a callback cancels the subscription. | |
| 231 * | |
| 232 * If [onListen] is provided, it is called with a subscription-like object | |
| 233 * that represents the underlying subscription to this stream. It is | |
| 234 * possible to pause, resume or cancel the subscription during the call | |
| 235 * to [onListen]. It is not possible to change the event handlers, including | |
| 236 * using [StreamSubscription.asFuture]. | |
| 237 * | |
| 238 * If [onCancel] is provided, it is called in a similar way to [onListen] | |
| 239 * when the returned stream stops having listener. If it later gets | |
| 240 * a new listener, the [onListen] function is called again. | |
| 241 * | |
| 242 * Use the callbacks, for example, for pausing the underlying subscription | |
| 243 * while having no subscribers to prevent losing events, or canceling the | |
| 244 * subscription when there are no listeners. | |
| 245 */ | |
| 246 Stream<T> asBroadcastStream({ | |
| 247 void onListen(StreamSubscription<T> subscription), | |
| 248 void onCancel(StreamSubscription<T> subscription) }) { | |
| 249 return new _AsBroadcastStream<T>(this, onListen, onCancel); | |
| 250 } | |
| 251 | |
| 252 /** | |
| 253 * Adds a subscription to this stream. | |
| 254 * | |
| 255 * On each data event from this stream, the subscriber's [onData] handler | |
| 256 * is called. If [onData] is null, nothing happens. | |
| 257 * | |
| 258 * On errors from this stream, the [onError] handler is given a | |
| 259 * object describing the error. | |
| 260 * | |
| 261 * The [onError] callback must be of type `void onError(error)` or | |
| 262 * `void onError(error, StackTrace stackTrace)`. If [onError] accepts | |
| 263 * two arguments it is called with the stack trace (which could be `null` if | |
| 264 * the stream itself received an error without stack trace). | |
| 265 * Otherwise it is called with just the error object. | |
| 266 * | |
| 267 * If this stream closes, the [onDone] handler is called. | |
| 268 * | |
| 269 * If [cancelOnError] is true, the subscription is ended when | |
| 270 * the first error is reported. The default is false. | |
| 271 */ | |
| 272 StreamSubscription<T> listen(void onData(T event), | |
| 273 { Function onError, | |
| 274 void onDone(), | |
| 275 bool cancelOnError}); | |
| 276 | |
| 277 /** | |
| 278 * Creates a new stream from this stream that discards some data events. | |
| 279 * | |
| 280 * The new stream sends the same error and done events as this stream, | |
| 281 * but it only sends the data events that satisfy the [test]. | |
| 282 * | |
| 283 * The returned stream is a broadcast stream if this stream is. | |
| 284 * If a broadcast stream is listened to more than once, each subscription | |
| 285 * will individually perform the `test`. | |
| 286 */ | |
| 287 Stream<T> where(bool test(T event)) { | |
| 288 return new _WhereStream<T>(this, test); | |
| 289 } | |
| 290 | |
| 291 /** | |
| 292 * Creates a new stream that converts each element of this stream | |
| 293 * to a new value using the [convert] function. | |
| 294 * | |
| 295 * The returned stream is a broadcast stream if this stream is. | |
| 296 * If a broadcast stream is listened to more than once, each subscription | |
| 297 * will individually execute `map` for each event. | |
| 298 */ | |
| 299 Stream map(convert(T event)) { | |
| 300 return new _MapStream<T, dynamic>(this, convert); | |
| 301 } | |
| 302 | |
| 303 /** | |
| 304 * Creates a new stream with each data event of this stream asynchronously | |
| 305 * mapped to a new event. | |
| 306 * | |
| 307 * This acts like [map], except that [convert] may return a [Future], | |
| 308 * and in that case, the stream waits for that future to complete before | |
| 309 * continuing with its result. | |
| 310 * | |
| 311 * The returned stream is a broadcast stream if this stream is. | |
| 312 */ | |
| 313 Stream asyncMap(convert(T event)) { | |
| 314 StreamController controller; | |
| 315 StreamSubscription subscription; | |
| 316 void onListen () { | |
| 317 final add = controller.add; | |
| 318 assert(controller is _StreamController || | |
| 319 controller is _BroadcastStreamController); | |
| 320 final eventSink = controller; | |
| 321 final addError = eventSink._addError; | |
| 322 subscription = this.listen( | |
| 323 (T event) { | |
| 324 var newValue; | |
| 325 try { | |
| 326 newValue = convert(event); | |
| 327 } catch (e, s) { | |
| 328 controller.addError(e, s); | |
| 329 return; | |
| 330 } | |
| 331 if (newValue is Future) { | |
| 332 subscription.pause(); | |
| 333 newValue.then(add, onError: addError) | |
| 334 .whenComplete(subscription.resume); | |
| 335 } else { | |
| 336 controller.add(newValue); | |
| 337 } | |
| 338 }, | |
| 339 onError: addError, | |
| 340 onDone: controller.close | |
| 341 ); | |
| 342 } | |
| 343 if (this.isBroadcast) { | |
| 344 controller = new StreamController.broadcast( | |
| 345 onListen: onListen, | |
| 346 onCancel: () { subscription.cancel(); }, | |
| 347 sync: true | |
| 348 ); | |
| 349 } else { | |
| 350 controller = new StreamController( | |
| 351 onListen: onListen, | |
| 352 onPause: () { subscription.pause(); }, | |
| 353 onResume: () { subscription.resume(); }, | |
| 354 onCancel: () { subscription.cancel(); }, | |
| 355 sync: true | |
| 356 ); | |
| 357 } | |
| 358 return controller.stream; | |
| 359 } | |
| 360 | |
| 361 /** | |
| 362 * Creates a new stream with the events of a stream per original event. | |
| 363 * | |
| 364 * This acts like [expand], except that [convert] returns a [Stream] | |
| 365 * instead of an [Iterable]. | |
| 366 * The events of the returned stream becomes the events of the returned | |
| 367 * stream, in the order they are produced. | |
| 368 * | |
| 369 * If [convert] returns `null`, no value is put on the output stream, | |
| 370 * just as if it returned an empty stream. | |
| 371 * | |
| 372 * The returned stream is a broadcast stream if this stream is. | |
| 373 */ | |
| 374 Stream asyncExpand(Stream convert(T event)) { | |
| 375 StreamController controller; | |
| 376 StreamSubscription subscription; | |
| 377 void onListen() { | |
| 378 assert(controller is _StreamController || | |
| 379 controller is _BroadcastStreamController); | |
| 380 final eventSink = controller; | |
| 381 subscription = this.listen( | |
| 382 (T event) { | |
| 383 Stream newStream; | |
| 384 try { | |
| 385 newStream = convert(event); | |
| 386 } catch (e, s) { | |
| 387 controller.addError(e, s); | |
| 388 return; | |
| 389 } | |
| 390 if (newStream != null) { | |
| 391 subscription.pause(); | |
| 392 controller.addStream(newStream) | |
| 393 .whenComplete(subscription.resume); | |
| 394 } | |
| 395 }, | |
| 396 onError: eventSink._addError, // Avoid Zone error replacement. | |
| 397 onDone: controller.close | |
| 398 ); | |
| 399 } | |
| 400 if (this.isBroadcast) { | |
| 401 controller = new StreamController.broadcast( | |
| 402 onListen: onListen, | |
| 403 onCancel: () { subscription.cancel(); }, | |
| 404 sync: true | |
| 405 ); | |
| 406 } else { | |
| 407 controller = new StreamController( | |
| 408 onListen: onListen, | |
| 409 onPause: () { subscription.pause(); }, | |
| 410 onResume: () { subscription.resume(); }, | |
| 411 onCancel: () { subscription.cancel(); }, | |
| 412 sync: true | |
| 413 ); | |
| 414 } | |
| 415 return controller.stream; | |
| 416 } | |
| 417 | |
| 418 /** | |
| 419 * Creates a wrapper Stream that intercepts some errors from this stream. | |
| 420 * | |
| 421 * If this stream sends an error that matches [test], then it is intercepted | |
| 422 * by the [handle] function. | |
| 423 * | |
| 424 * The [onError] callback must be of type `void onError(error)` or | |
| 425 * `void onError(error, StackTrace stackTrace)`. Depending on the function | |
| 426 * type the the stream either invokes [onError] with or without a stack | |
| 427 * trace. The stack trace argument might be `null` if the stream itself | |
| 428 * received an error without stack trace. | |
| 429 * | |
| 430 * An asynchronous error [:e:] is matched by a test function if [:test(e):] | |
| 431 * returns true. If [test] is omitted, every error is considered matching. | |
| 432 * | |
| 433 * If the error is intercepted, the [handle] function can decide what to do | |
| 434 * with it. It can throw if it wants to raise a new (or the same) error, | |
| 435 * or simply return to make the stream forget the error. | |
| 436 * | |
| 437 * If you need to transform an error into a data event, use the more generic | |
| 438 * [Stream.transform] to handle the event by writing a data event to | |
| 439 * the output sink. | |
| 440 * | |
| 441 * The returned stream is a broadcast stream if this stream is. | |
| 442 * If a broadcast stream is listened to more than once, each subscription | |
| 443 * will individually perform the `test` and handle the error. | |
| 444 */ | |
| 445 Stream<T> handleError(Function onError, { bool test(error) }) { | |
| 446 return new _HandleErrorStream<T>(this, onError, test); | |
| 447 } | |
| 448 | |
| 449 /** | |
| 450 * Creates a new stream from this stream that converts each element | |
| 451 * into zero or more events. | |
| 452 * | |
| 453 * Each incoming event is converted to an [Iterable] of new events, | |
| 454 * and each of these new events are then sent by the returned stream | |
| 455 * in order. | |
| 456 * | |
| 457 * The returned stream is a broadcast stream if this stream is. | |
| 458 * If a broadcast stream is listened to more than once, each subscription | |
| 459 * will individually call `convert` and expand the events. | |
| 460 */ | |
| 461 Stream expand(Iterable convert(T value)) { | |
| 462 return new _ExpandStream<T, dynamic>(this, convert); | |
| 463 } | |
| 464 | |
| 465 /** | |
| 466 * Binds this stream as the input of the provided [StreamConsumer]. | |
| 467 * | |
| 468 * The `streamConsumer` is closed when the stream has been added to it. | |
| 469 * | |
| 470 * Returns a future which completes when the stream has been consumed | |
| 471 * and the consumer has been closed. | |
| 472 */ | |
| 473 Future pipe(StreamConsumer<T> streamConsumer) { | |
| 474 return streamConsumer.addStream(this).then((_) => streamConsumer.close()); | |
| 475 } | |
| 476 | |
| 477 /** | |
| 478 * Chains this stream as the input of the provided [StreamTransformer]. | |
| 479 * | |
| 480 * Returns the result of [:streamTransformer.bind:] itself. | |
| 481 * | |
| 482 * The `streamTransformer` can decide whether it wants to return a | |
| 483 * broadcast stream or not. | |
| 484 */ | |
| 485 Stream transform(StreamTransformer<T, dynamic> streamTransformer) { | |
| 486 return streamTransformer.bind(this); | |
| 487 } | |
| 488 | |
| 489 /** | |
| 490 * Reduces a sequence of values by repeatedly applying [combine]. | |
| 491 */ | |
| 492 Future<T> reduce(T combine(T previous, T element)) { | |
| 493 _Future<T> result = new _Future<T>(); | |
| 494 bool seenFirst = false; | |
| 495 T value; | |
| 496 StreamSubscription subscription; | |
| 497 subscription = this.listen( | |
| 498 (T element) { | |
| 499 if (seenFirst) { | |
| 500 _runUserCode(() => combine(value, element), | |
| 501 (T newValue) { value = newValue; }, | |
| 502 _cancelAndErrorClosure(subscription, result)); | |
| 503 } else { | |
| 504 value = element; | |
| 505 seenFirst = true; | |
| 506 } | |
| 507 }, | |
| 508 onError: result._completeError, | |
| 509 onDone: () { | |
| 510 if (!seenFirst) { | |
| 511 try { | |
| 512 throw IterableElementError.noElement(); | |
| 513 } catch (e, s) { | |
| 514 _completeWithErrorCallback(result, e, s); | |
| 515 } | |
| 516 } else { | |
| 517 result._complete(value); | |
| 518 } | |
| 519 }, | |
| 520 cancelOnError: true | |
| 521 ); | |
| 522 return result; | |
| 523 } | |
| 524 | |
| 525 /** Reduces a sequence of values by repeatedly applying [combine]. */ | |
| 526 Future fold(var initialValue, combine(var previous, T element)) { | |
| 527 _Future result = new _Future(); | |
| 528 var value = initialValue; | |
| 529 StreamSubscription subscription; | |
| 530 subscription = this.listen( | |
| 531 (T element) { | |
| 532 _runUserCode( | |
| 533 () => combine(value, element), | |
| 534 (newValue) { value = newValue; }, | |
| 535 _cancelAndErrorClosure(subscription, result) | |
| 536 ); | |
| 537 }, | |
| 538 onError: (e, st) { | |
| 539 result._completeError(e, st); | |
| 540 }, | |
| 541 onDone: () { | |
| 542 result._complete(value); | |
| 543 }, | |
| 544 cancelOnError: true); | |
| 545 return result; | |
| 546 } | |
| 547 | |
| 548 /** | |
| 549 * Collects string of data events' string representations. | |
| 550 * | |
| 551 * If [separator] is provided, it is inserted between any two | |
| 552 * elements. | |
| 553 * | |
| 554 * Any error in the stream causes the future to complete with that | |
| 555 * error. Otherwise it completes with the collected string when | |
| 556 * the "done" event arrives. | |
| 557 */ | |
| 558 Future<String> join([String separator = ""]) { | |
| 559 _Future<String> result = new _Future<String>(); | |
| 560 StringBuffer buffer = new StringBuffer(); | |
| 561 StreamSubscription subscription; | |
| 562 bool first = true; | |
| 563 subscription = this.listen( | |
| 564 (T element) { | |
| 565 if (!first) { | |
| 566 buffer.write(separator); | |
| 567 } | |
| 568 first = false; | |
| 569 try { | |
| 570 buffer.write(element); | |
| 571 } catch (e, s) { | |
| 572 _cancelAndErrorWithReplacement(subscription, result, e, s); | |
| 573 } | |
| 574 }, | |
| 575 onError: (e) { | |
| 576 result._completeError(e); | |
| 577 }, | |
| 578 onDone: () { | |
| 579 result._complete(buffer.toString()); | |
| 580 }, | |
| 581 cancelOnError: true); | |
| 582 return result; | |
| 583 } | |
| 584 | |
| 585 /** | |
| 586 * Checks whether [needle] occurs in the elements provided by this stream. | |
| 587 * | |
| 588 * Completes the [Future] when the answer is known. | |
| 589 * If this stream reports an error, the [Future] will report that error. | |
| 590 */ | |
| 591 Future<bool> contains(Object needle) { | |
| 592 _Future<bool> future = new _Future<bool>(); | |
| 593 StreamSubscription subscription; | |
| 594 subscription = this.listen( | |
| 595 (T element) { | |
| 596 _runUserCode( | |
| 597 () => (element == needle), | |
| 598 (bool isMatch) { | |
| 599 if (isMatch) { | |
| 600 _cancelAndValue(subscription, future, true); | |
| 601 } | |
| 602 }, | |
| 603 _cancelAndErrorClosure(subscription, future) | |
| 604 ); | |
| 605 }, | |
| 606 onError: future._completeError, | |
| 607 onDone: () { | |
| 608 future._complete(false); | |
| 609 }, | |
| 610 cancelOnError: true); | |
| 611 return future; | |
| 612 } | |
| 613 | |
| 614 /** | |
| 615 * Executes [action] on each data event of the stream. | |
| 616 * | |
| 617 * Completes the returned [Future] when all events of the stream | |
| 618 * have been processed. Completes the future with an error if the | |
| 619 * stream has an error event, or if [action] throws. | |
| 620 */ | |
| 621 Future forEach(void action(T element)) { | |
| 622 _Future future = new _Future(); | |
| 623 StreamSubscription subscription; | |
| 624 subscription = this.listen( | |
| 625 (T element) { | |
| 626 _runUserCode( | |
| 627 () => action(element), | |
| 628 (_) {}, | |
| 629 _cancelAndErrorClosure(subscription, future) | |
| 630 ); | |
| 631 }, | |
| 632 onError: future._completeError, | |
| 633 onDone: () { | |
| 634 future._complete(null); | |
| 635 }, | |
| 636 cancelOnError: true); | |
| 637 return future; | |
| 638 } | |
| 639 | |
| 640 /** | |
| 641 * Checks whether [test] accepts all elements provided by this stream. | |
| 642 * | |
| 643 * Completes the [Future] when the answer is known. | |
| 644 * If this stream reports an error, the [Future] will report that error. | |
| 645 */ | |
| 646 Future<bool> every(bool test(T element)) { | |
| 647 _Future<bool> future = new _Future<bool>(); | |
| 648 StreamSubscription subscription; | |
| 649 subscription = this.listen( | |
| 650 (T element) { | |
| 651 _runUserCode( | |
| 652 () => test(element), | |
| 653 (bool isMatch) { | |
| 654 if (!isMatch) { | |
| 655 _cancelAndValue(subscription, future, false); | |
| 656 } | |
| 657 }, | |
| 658 _cancelAndErrorClosure(subscription, future) | |
| 659 ); | |
| 660 }, | |
| 661 onError: future._completeError, | |
| 662 onDone: () { | |
| 663 future._complete(true); | |
| 664 }, | |
| 665 cancelOnError: true); | |
| 666 return future; | |
| 667 } | |
| 668 | |
| 669 /** | |
| 670 * Checks whether [test] accepts any element provided by this stream. | |
| 671 * | |
| 672 * Completes the [Future] when the answer is known. | |
| 673 * | |
| 674 * If this stream reports an error, the [Future] reports that error. | |
| 675 * | |
| 676 * Stops listening to the stream after the first matching element has been | |
| 677 * found. | |
| 678 * | |
| 679 * Internally the method cancels its subscription after this element. This | |
| 680 * means that single-subscription (non-broadcast) streams are closed and | |
| 681 * cannot be reused after a call to this method. | |
| 682 */ | |
| 683 Future<bool> any(bool test(T element)) { | |
| 684 _Future<bool> future = new _Future<bool>(); | |
| 685 StreamSubscription subscription; | |
| 686 subscription = this.listen( | |
| 687 (T element) { | |
| 688 _runUserCode( | |
| 689 () => test(element), | |
| 690 (bool isMatch) { | |
| 691 if (isMatch) { | |
| 692 _cancelAndValue(subscription, future, true); | |
| 693 } | |
| 694 }, | |
| 695 _cancelAndErrorClosure(subscription, future) | |
| 696 ); | |
| 697 }, | |
| 698 onError: future._completeError, | |
| 699 onDone: () { | |
| 700 future._complete(false); | |
| 701 }, | |
| 702 cancelOnError: true); | |
| 703 return future; | |
| 704 } | |
| 705 | |
| 706 | |
| 707 /** Counts the elements in the stream. */ | |
| 708 Future<int> get length { | |
| 709 _Future<int> future = new _Future<int>(); | |
| 710 int count = 0; | |
| 711 this.listen( | |
| 712 (_) { count++; }, | |
| 713 onError: future._completeError, | |
| 714 onDone: () { | |
| 715 future._complete(count); | |
| 716 }, | |
| 717 cancelOnError: true); | |
| 718 return future; | |
| 719 } | |
| 720 | |
| 721 /** | |
| 722 * Reports whether this stream contains any elements. | |
| 723 * | |
| 724 * Stops listening to the stream after the first element has been received. | |
| 725 * | |
| 726 * Internally the method cancels its subscription after the first element. | |
| 727 * This means that single-subscription (non-broadcast) streams are closed and | |
| 728 * cannot be reused after a call to this getter. | |
| 729 */ | |
| 730 Future<bool> get isEmpty { | |
| 731 _Future<bool> future = new _Future<bool>(); | |
| 732 StreamSubscription subscription; | |
| 733 subscription = this.listen( | |
| 734 (_) { | |
| 735 _cancelAndValue(subscription, future, false); | |
| 736 }, | |
| 737 onError: future._completeError, | |
| 738 onDone: () { | |
| 739 future._complete(true); | |
| 740 }, | |
| 741 cancelOnError: true); | |
| 742 return future; | |
| 743 } | |
| 744 | |
| 745 /** Collects the data of this stream in a [List]. */ | |
| 746 Future<List<T>> toList() { | |
| 747 List<T> result = <T>[]; | |
| 748 _Future<List<T>> future = new _Future<List<T>>(); | |
| 749 this.listen( | |
| 750 (T data) { | |
| 751 result.add(data); | |
| 752 }, | |
| 753 onError: future._completeError, | |
| 754 onDone: () { | |
| 755 future._complete(result); | |
| 756 }, | |
| 757 cancelOnError: true); | |
| 758 return future; | |
| 759 } | |
| 760 | |
| 761 /** | |
| 762 * Collects the data of this stream in a [Set]. | |
| 763 * | |
| 764 * The returned set is the same type as returned by `new Set<T>()`. | |
| 765 * If another type of set is needed, either use [forEach] to add each | |
| 766 * element to the set, or use | |
| 767 * `toList().then((list) => new SomeOtherSet.from(list))` | |
| 768 * to create the set. | |
| 769 */ | |
| 770 Future<Set<T>> toSet() { | |
| 771 Set<T> result = new Set<T>(); | |
| 772 _Future<Set<T>> future = new _Future<Set<T>>(); | |
| 773 this.listen( | |
| 774 (T data) { | |
| 775 result.add(data); | |
| 776 }, | |
| 777 onError: future._completeError, | |
| 778 onDone: () { | |
| 779 future._complete(result); | |
| 780 }, | |
| 781 cancelOnError: true); | |
| 782 return future; | |
| 783 } | |
| 784 | |
| 785 /** | |
| 786 * Discards all data on the stream, but signals when it's done or an error | |
| 787 * occured. | |
| 788 * | |
| 789 * When subscribing using [drain], cancelOnError will be true. This means | |
| 790 * that the future will complete with the first error on the stream and then | |
| 791 * cancel the subscription. | |
| 792 * | |
| 793 * In case of a `done` event the future completes with the given | |
| 794 * [futureValue]. | |
| 795 */ | |
| 796 Future drain([var futureValue]) => listen(null, cancelOnError: true) | |
| 797 .asFuture(futureValue); | |
| 798 | |
| 799 /** | |
| 800 * Provides at most the first [n] values of this stream. | |
| 801 * | |
| 802 * Forwards the first [n] data events of this stream, and all error | |
| 803 * events, to the returned stream, and ends with a done event. | |
| 804 * | |
| 805 * If this stream produces fewer than [count] values before it's done, | |
| 806 * so will the returned stream. | |
| 807 * | |
| 808 * Stops listening to the stream after the first [n] elements have been | |
| 809 * received. | |
| 810 * | |
| 811 * Internally the method cancels its subscription after these elements. This | |
| 812 * means that single-subscription (non-broadcast) streams are closed and | |
| 813 * cannot be reused after a call to this method. | |
| 814 * | |
| 815 * The returned stream is a broadcast stream if this stream is. | |
| 816 * For a broadcast stream, the events are only counted from the time | |
| 817 * the returned stream is listened to. | |
| 818 */ | |
| 819 Stream<T> take(int count) { | |
| 820 return new _TakeStream(this, count); | |
| 821 } | |
| 822 | |
| 823 /** | |
| 824 * Forwards data events while [test] is successful. | |
| 825 * | |
| 826 * The returned stream provides the same events as this stream as long | |
| 827 * as [test] returns [:true:] for the event data. The stream is done | |
| 828 * when either this stream is done, or when this stream first provides | |
| 829 * a value that [test] doesn't accept. | |
| 830 * | |
| 831 * Stops listening to the stream after the accepted elements. | |
| 832 * | |
| 833 * Internally the method cancels its subscription after these elements. This | |
| 834 * means that single-subscription (non-broadcast) streams are closed and | |
| 835 * cannot be reused after a call to this method. | |
| 836 * | |
| 837 * The returned stream is a broadcast stream if this stream is. | |
| 838 * For a broadcast stream, the events are only tested from the time | |
| 839 * the returned stream is listened to. | |
| 840 */ | |
| 841 Stream<T> takeWhile(bool test(T element)) { | |
| 842 return new _TakeWhileStream(this, test); | |
| 843 } | |
| 844 | |
| 845 /** | |
| 846 * Skips the first [count] data events from this stream. | |
| 847 * | |
| 848 * The returned stream is a broadcast stream if this stream is. | |
| 849 * For a broadcast stream, the events are only counted from the time | |
| 850 * the returned stream is listened to. | |
| 851 */ | |
| 852 Stream<T> skip(int count) { | |
| 853 return new _SkipStream(this, count); | |
| 854 } | |
| 855 | |
| 856 /** | |
| 857 * Skip data events from this stream while they are matched by [test]. | |
| 858 * | |
| 859 * Error and done events are provided by the returned stream unmodified. | |
| 860 * | |
| 861 * Starting with the first data event where [test] returns false for the | |
| 862 * event data, the returned stream will have the same events as this stream. | |
| 863 * | |
| 864 * The returned stream is a broadcast stream if this stream is. | |
| 865 * For a broadcast stream, the events are only tested from the time | |
| 866 * the returned stream is listened to. | |
| 867 */ | |
| 868 Stream<T> skipWhile(bool test(T element)) { | |
| 869 return new _SkipWhileStream(this, test); | |
| 870 } | |
| 871 | |
| 872 /** | |
| 873 * Skips data events if they are equal to the previous data event. | |
| 874 * | |
| 875 * The returned stream provides the same events as this stream, except | |
| 876 * that it never provides two consequtive data events that are equal. | |
| 877 * | |
| 878 * Equality is determined by the provided [equals] method. If that is | |
| 879 * omitted, the '==' operator on the last provided data element is used. | |
| 880 * | |
| 881 * The returned stream is a broadcast stream if this stream is. | |
| 882 * If a broadcast stream is listened to more than once, each subscription | |
| 883 * will individually perform the `equals` test. | |
| 884 */ | |
| 885 Stream<T> distinct([bool equals(T previous, T next)]) { | |
| 886 return new _DistinctStream(this, equals); | |
| 887 } | |
| 888 | |
| 889 /** | |
| 890 * Returns the first element of the stream. | |
| 891 * | |
| 892 * Stops listening to the stream after the first element has been received. | |
| 893 * | |
| 894 * Internally the method cancels its subscription after the first element. | |
| 895 * This means that single-subscription (non-broadcast) streams are closed | |
| 896 * and cannot be reused after a call to this getter. | |
| 897 * | |
| 898 * If an error event occurs before the first data event, the resulting future | |
| 899 * is completed with that error. | |
| 900 * | |
| 901 * If this stream is empty (a done event occurs before the first data event), | |
| 902 * the resulting future completes with a [StateError]. | |
| 903 * | |
| 904 * Except for the type of the error, this method is equivalent to | |
| 905 * [:this.elementAt(0):]. | |
| 906 */ | |
| 907 Future<T> get first { | |
| 908 _Future<T> future = new _Future<T>(); | |
| 909 StreamSubscription subscription; | |
| 910 subscription = this.listen( | |
| 911 (T value) { | |
| 912 _cancelAndValue(subscription, future, value); | |
| 913 }, | |
| 914 onError: future._completeError, | |
| 915 onDone: () { | |
| 916 try { | |
| 917 throw IterableElementError.noElement(); | |
| 918 } catch (e, s) { | |
| 919 _completeWithErrorCallback(future, e, s); | |
| 920 } | |
| 921 }, | |
| 922 cancelOnError: true); | |
| 923 return future; | |
| 924 } | |
| 925 | |
| 926 /** | |
| 927 * Returns the last element of the stream. | |
| 928 * | |
| 929 * If an error event occurs before the first data event, the resulting future | |
| 930 * is completed with that error. | |
| 931 * | |
| 932 * If this stream is empty (a done event occurs before the first data event), | |
| 933 * the resulting future completes with a [StateError]. | |
| 934 */ | |
| 935 Future<T> get last { | |
| 936 _Future<T> future = new _Future<T>(); | |
| 937 T result = null; | |
| 938 bool foundResult = false; | |
| 939 StreamSubscription subscription; | |
| 940 subscription = this.listen( | |
| 941 (T value) { | |
| 942 foundResult = true; | |
| 943 result = value; | |
| 944 }, | |
| 945 onError: future._completeError, | |
| 946 onDone: () { | |
| 947 if (foundResult) { | |
| 948 future._complete(result); | |
| 949 return; | |
| 950 } | |
| 951 try { | |
| 952 throw IterableElementError.noElement(); | |
| 953 } catch (e, s) { | |
| 954 _completeWithErrorCallback(future, e, s); | |
| 955 } | |
| 956 }, | |
| 957 cancelOnError: true); | |
| 958 return future; | |
| 959 } | |
| 960 | |
| 961 /** | |
| 962 * Returns the single element. | |
| 963 * | |
| 964 * If an error event occurs before or after the first data event, the | |
| 965 * resulting future is completed with that error. | |
| 966 * | |
| 967 * If [this] is empty or has more than one element throws a [StateError]. | |
| 968 */ | |
| 969 Future<T> get single { | |
| 970 _Future<T> future = new _Future<T>(); | |
| 971 T result = null; | |
| 972 bool foundResult = false; | |
| 973 StreamSubscription subscription; | |
| 974 subscription = this.listen( | |
| 975 (T value) { | |
| 976 if (foundResult) { | |
| 977 // This is the second element we get. | |
| 978 try { | |
| 979 throw IterableElementError.tooMany(); | |
| 980 } catch (e, s) { | |
| 981 _cancelAndErrorWithReplacement(subscription, future, e, s); | |
| 982 } | |
| 983 return; | |
| 984 } | |
| 985 foundResult = true; | |
| 986 result = value; | |
| 987 }, | |
| 988 onError: future._completeError, | |
| 989 onDone: () { | |
| 990 if (foundResult) { | |
| 991 future._complete(result); | |
| 992 return; | |
| 993 } | |
| 994 try { | |
| 995 throw IterableElementError.noElement(); | |
| 996 } catch (e, s) { | |
| 997 _completeWithErrorCallback(future, e, s); | |
| 998 } | |
| 999 }, | |
| 1000 cancelOnError: true); | |
| 1001 return future; | |
| 1002 } | |
| 1003 | |
| 1004 /** | |
| 1005 * Finds the first element of this stream matching [test]. | |
| 1006 * | |
| 1007 * Returns a future that is filled with the first element of this stream | |
| 1008 * that [test] returns true for. | |
| 1009 * | |
| 1010 * If no such element is found before this stream is done, and a | |
| 1011 * [defaultValue] function is provided, the result of calling [defaultValue] | |
| 1012 * becomes the value of the future. | |
| 1013 * | |
| 1014 * Stops listening to the stream after the first matching element has been | |
| 1015 * received. | |
| 1016 * | |
| 1017 * Internally the method cancels its subscription after the first element that | |
| 1018 * matches the predicate. This means that single-subscription (non-broadcast) | |
| 1019 * streams are closed and cannot be reused after a call to this method. | |
| 1020 * | |
| 1021 * If an error occurs, or if this stream ends without finding a match and | |
| 1022 * with no [defaultValue] function provided, the future will receive an | |
| 1023 * error. | |
| 1024 */ | |
| 1025 Future<dynamic> firstWhere(bool test(T element), {Object defaultValue()}) { | |
| 1026 _Future<dynamic> future = new _Future(); | |
| 1027 StreamSubscription subscription; | |
| 1028 subscription = this.listen( | |
| 1029 (T value) { | |
| 1030 _runUserCode( | |
| 1031 () => test(value), | |
| 1032 (bool isMatch) { | |
| 1033 if (isMatch) { | |
| 1034 _cancelAndValue(subscription, future, value); | |
| 1035 } | |
| 1036 }, | |
| 1037 _cancelAndErrorClosure(subscription, future) | |
| 1038 ); | |
| 1039 }, | |
| 1040 onError: future._completeError, | |
| 1041 onDone: () { | |
| 1042 if (defaultValue != null) { | |
| 1043 _runUserCode(defaultValue, future._complete, future._completeError); | |
| 1044 return; | |
| 1045 } | |
| 1046 try { | |
| 1047 throw IterableElementError.noElement(); | |
| 1048 } catch (e, s) { | |
| 1049 _completeWithErrorCallback(future, e, s); | |
| 1050 } | |
| 1051 }, | |
| 1052 cancelOnError: true); | |
| 1053 return future; | |
| 1054 } | |
| 1055 | |
| 1056 /** | |
| 1057 * Finds the last element in this stream matching [test]. | |
| 1058 * | |
| 1059 * As [firstWhere], except that the last matching element is found. | |
| 1060 * That means that the result cannot be provided before this stream | |
| 1061 * is done. | |
| 1062 */ | |
| 1063 Future<dynamic> lastWhere(bool test(T element), {Object defaultValue()}) { | |
| 1064 _Future<dynamic> future = new _Future(); | |
| 1065 T result = null; | |
| 1066 bool foundResult = false; | |
| 1067 StreamSubscription subscription; | |
| 1068 subscription = this.listen( | |
| 1069 (T value) { | |
| 1070 _runUserCode( | |
| 1071 () => true == test(value), | |
| 1072 (bool isMatch) { | |
| 1073 if (isMatch) { | |
| 1074 foundResult = true; | |
| 1075 result = value; | |
| 1076 } | |
| 1077 }, | |
| 1078 _cancelAndErrorClosure(subscription, future) | |
| 1079 ); | |
| 1080 }, | |
| 1081 onError: future._completeError, | |
| 1082 onDone: () { | |
| 1083 if (foundResult) { | |
| 1084 future._complete(result); | |
| 1085 return; | |
| 1086 } | |
| 1087 if (defaultValue != null) { | |
| 1088 _runUserCode(defaultValue, future._complete, future._completeError); | |
| 1089 return; | |
| 1090 } | |
| 1091 try { | |
| 1092 throw IterableElementError.noElement(); | |
| 1093 } catch (e, s) { | |
| 1094 _completeWithErrorCallback(future, e, s); | |
| 1095 } | |
| 1096 }, | |
| 1097 cancelOnError: true); | |
| 1098 return future; | |
| 1099 } | |
| 1100 | |
| 1101 /** | |
| 1102 * Finds the single element in this stream matching [test]. | |
| 1103 * | |
| 1104 * Like [lastMatch], except that it is an error if more than one | |
| 1105 * matching element occurs in the stream. | |
| 1106 */ | |
| 1107 Future<T> singleWhere(bool test(T element)) { | |
| 1108 _Future<T> future = new _Future<T>(); | |
| 1109 T result = null; | |
| 1110 bool foundResult = false; | |
| 1111 StreamSubscription subscription; | |
| 1112 subscription = this.listen( | |
| 1113 (T value) { | |
| 1114 _runUserCode( | |
| 1115 () => true == test(value), | |
| 1116 (bool isMatch) { | |
| 1117 if (isMatch) { | |
| 1118 if (foundResult) { | |
| 1119 try { | |
| 1120 throw IterableElementError.tooMany(); | |
| 1121 } catch (e, s) { | |
| 1122 _cancelAndErrorWithReplacement(subscription, future, e, s); | |
| 1123 } | |
| 1124 return; | |
| 1125 } | |
| 1126 foundResult = true; | |
| 1127 result = value; | |
| 1128 } | |
| 1129 }, | |
| 1130 _cancelAndErrorClosure(subscription, future) | |
| 1131 ); | |
| 1132 }, | |
| 1133 onError: future._completeError, | |
| 1134 onDone: () { | |
| 1135 if (foundResult) { | |
| 1136 future._complete(result); | |
| 1137 return; | |
| 1138 } | |
| 1139 try { | |
| 1140 throw IterableElementError.noElement(); | |
| 1141 } catch (e, s) { | |
| 1142 _completeWithErrorCallback(future, e, s); | |
| 1143 } | |
| 1144 }, | |
| 1145 cancelOnError: true); | |
| 1146 return future; | |
| 1147 } | |
| 1148 | |
| 1149 /** | |
| 1150 * Returns the value of the [index]th data event of this stream. | |
| 1151 * | |
| 1152 * Stops listening to the stream after the [index]th data event has been | |
| 1153 * received. | |
| 1154 * | |
| 1155 * Internally the method cancels its subscription after these elements. This | |
| 1156 * means that single-subscription (non-broadcast) streams are closed and | |
| 1157 * cannot be reused after a call to this method. | |
| 1158 * | |
| 1159 * If an error event occurs before the value is found, the future completes | |
| 1160 * with this error. | |
| 1161 * | |
| 1162 * If a done event occurs before the value is found, the future completes | |
| 1163 * with a [RangeError]. | |
| 1164 */ | |
| 1165 Future<T> elementAt(int index) { | |
| 1166 if (index is! int || index < 0) throw new ArgumentError(index); | |
| 1167 _Future<T> future = new _Future<T>(); | |
| 1168 StreamSubscription subscription; | |
| 1169 int elementIndex = 0; | |
| 1170 subscription = this.listen( | |
| 1171 (T value) { | |
| 1172 if (index == elementIndex) { | |
| 1173 _cancelAndValue(subscription, future, value); | |
| 1174 return; | |
| 1175 } | |
| 1176 elementIndex += 1; | |
| 1177 }, | |
| 1178 onError: future._completeError, | |
| 1179 onDone: () { | |
| 1180 future._completeError( | |
| 1181 new RangeError.index(index, this, "index", null, elementIndex)); | |
| 1182 }, | |
| 1183 cancelOnError: true); | |
| 1184 return future; | |
| 1185 } | |
| 1186 | |
| 1187 /** | |
| 1188 * Creates a new stream with the same events as this stream. | |
| 1189 * | |
| 1190 * Whenever more than [timeLimit] passes between two events from this stream, | |
| 1191 * the [onTimeout] function is called. | |
| 1192 * | |
| 1193 * The countdown doesn't start until the returned stream is listened to. | |
| 1194 * The countdown is reset every time an event is forwarded from this stream, | |
| 1195 * or when the stream is paused and resumed. | |
| 1196 * | |
| 1197 * The [onTimeout] function is called with one argument: an | |
| 1198 * [EventSink] that allows putting events into the returned stream. | |
| 1199 * This `EventSink` is only valid during the call to `onTimeout`. | |
| 1200 * | |
| 1201 * If `onTimeout` is omitted, a timeout will just put a [TimeoutException] | |
| 1202 * into the error channel of the returned stream. | |
| 1203 * | |
| 1204 * The returned stream is a broadcast stream if this stream is. | |
| 1205 * If a broadcast stream is listened to more than once, each subscription | |
| 1206 * will have its individually timer that starts counting on listen, | |
| 1207 * and the subscriptions' timers can be paused individually. | |
| 1208 */ | |
| 1209 Stream timeout(Duration timeLimit, {void onTimeout(EventSink sink)}) { | |
| 1210 StreamController controller; | |
| 1211 // The following variables are set on listen. | |
| 1212 StreamSubscription<T> subscription; | |
| 1213 Timer timer; | |
| 1214 Zone zone; | |
| 1215 Function timeout; | |
| 1216 | |
| 1217 void onData(T event) { | |
| 1218 timer.cancel(); | |
| 1219 controller.add(event); | |
| 1220 timer = zone.createTimer(timeLimit, timeout); | |
| 1221 } | |
| 1222 void onError(error, StackTrace stackTrace) { | |
| 1223 timer.cancel(); | |
| 1224 assert(controller is _StreamController || | |
| 1225 controller is _BroadcastStreamController); | |
| 1226 var eventSink = controller; | |
| 1227 eventSink._addError(error, stackTrace); // Avoid Zone error replacement. | |
| 1228 timer = zone.createTimer(timeLimit, timeout); | |
| 1229 } | |
| 1230 void onDone() { | |
| 1231 timer.cancel(); | |
| 1232 controller.close(); | |
| 1233 } | |
| 1234 void onListen() { | |
| 1235 // This is the onListen callback for of controller. | |
| 1236 // It runs in the same zone that the subscription was created in. | |
| 1237 // Use that zone for creating timers and running the onTimeout | |
| 1238 // callback. | |
| 1239 zone = Zone.current; | |
| 1240 if (onTimeout == null) { | |
| 1241 timeout = () { | |
| 1242 controller.addError(new TimeoutException("No stream event", | |
| 1243 timeLimit), null); | |
| 1244 }; | |
| 1245 } else { | |
| 1246 onTimeout = zone.registerUnaryCallback(onTimeout); | |
| 1247 _ControllerEventSinkWrapper wrapper = | |
| 1248 new _ControllerEventSinkWrapper(null); | |
| 1249 timeout = () { | |
| 1250 wrapper._sink = controller; // Only valid during call. | |
| 1251 zone.runUnaryGuarded(onTimeout, wrapper); | |
| 1252 wrapper._sink = null; | |
| 1253 }; | |
| 1254 } | |
| 1255 | |
| 1256 subscription = this.listen(onData, onError: onError, onDone: onDone); | |
| 1257 timer = zone.createTimer(timeLimit, timeout); | |
| 1258 } | |
| 1259 Future onCancel() { | |
| 1260 timer.cancel(); | |
| 1261 Future result = subscription.cancel(); | |
| 1262 subscription = null; | |
| 1263 return result; | |
| 1264 } | |
| 1265 controller = isBroadcast | |
| 1266 ? new _SyncBroadcastStreamController(onListen, onCancel) | |
| 1267 : new _SyncStreamController( | |
| 1268 onListen, | |
| 1269 () { | |
| 1270 // Don't null the timer, onCancel may call cancel again. | |
| 1271 timer.cancel(); | |
| 1272 subscription.pause(); | |
| 1273 }, | |
| 1274 () { | |
| 1275 subscription.resume(); | |
| 1276 timer = zone.createTimer(timeLimit, timeout); | |
| 1277 }, | |
| 1278 onCancel); | |
| 1279 return controller.stream; | |
| 1280 } | |
| 1281 } | |
| 1282 | |
| 1283 /** | |
| 1284 * A subscritption on events from a [Stream]. | |
| 1285 * | |
| 1286 * When you listen on a [Stream] using [Stream.listen], | |
| 1287 * a [StreamSubscription] object is returned. | |
| 1288 * | |
| 1289 * The subscription provides events to the listener, | |
| 1290 * and holds the callbacks used to handle the events. | |
| 1291 * The subscription can also be used to unsubscribe from the events, | |
| 1292 * or to temporarily pause the events from the stream. | |
| 1293 */ | |
| 1294 abstract class StreamSubscription<T> { | |
| 1295 /** | |
| 1296 * Cancels this subscription. It will no longer receive events. | |
| 1297 * | |
| 1298 * May return a future which completes when the stream is done cleaning up. | |
| 1299 * This can be used if the stream needs to release some resources | |
| 1300 * that are needed for a following operation, | |
| 1301 * for example a file being read, that should be deleted afterwards. | |
| 1302 * In that case, the file may not be able to be deleted successfully | |
| 1303 * until the returned future has completed. | |
| 1304 * | |
| 1305 * The future will be completed with a `null` value. | |
| 1306 * If the cleanup throws, which it really shouldn't, the returned future | |
| 1307 * will be completed with that error. | |
| 1308 * | |
| 1309 * Returns `null` if there is no need to wait. | |
| 1310 */ | |
| 1311 Future cancel(); | |
| 1312 | |
| 1313 /** | |
| 1314 * Set or override the data event handler of this subscription. | |
| 1315 * | |
| 1316 * This method overrides the handler that has been set at the invocation of | |
| 1317 * [Stream.listen]. | |
| 1318 */ | |
| 1319 void onData(void handleData(T data)); | |
| 1320 | |
| 1321 /** | |
| 1322 * Set or override the error event handler of this subscription. | |
| 1323 * | |
| 1324 * This method overrides the handler that has been set at the invocation of | |
| 1325 * [Stream.listen] or by calling [asFuture]. | |
| 1326 */ | |
| 1327 void onError(Function handleError); | |
| 1328 | |
| 1329 /** | |
| 1330 * Set or override the done event handler of this subscription. | |
| 1331 * | |
| 1332 * This method overrides the handler that has been set at the invocation of | |
| 1333 * [Stream.listen] or by calling [asFuture]. | |
| 1334 */ | |
| 1335 void onDone(void handleDone()); | |
| 1336 | |
| 1337 /** | |
| 1338 * Request that the stream pauses events until further notice. | |
| 1339 * | |
| 1340 * While paused, the subscription will not fire any events. | |
| 1341 * If it receives events from its source, they will be buffered until | |
| 1342 * the subscription is resumed. | |
| 1343 * The underlying source is usually informed about the pause, | |
| 1344 * so it can stop generating events until the subscription is resumed. | |
| 1345 * | |
| 1346 * To avoid buffering events on a broadcast stream, it is better to | |
| 1347 * cancel this subscription, and start to listen again when events | |
| 1348 * are needed. | |
| 1349 * | |
| 1350 * If [resumeSignal] is provided, the stream will undo the pause | |
| 1351 * when the future completes. If the future completes with an error, | |
| 1352 * the stream will resume, but the error will not be handled! | |
| 1353 * | |
| 1354 * A call to [resume] will also undo a pause. | |
| 1355 * | |
| 1356 * If the subscription is paused more than once, an equal number | |
| 1357 * of resumes must be performed to resume the stream. | |
| 1358 * | |
| 1359 * Currently DOM streams silently drop events when the stream is paused. This | |
| 1360 * is a bug and will be fixed. | |
| 1361 */ | |
| 1362 void pause([Future resumeSignal]); | |
| 1363 | |
| 1364 /** | |
| 1365 * Resume after a pause. | |
| 1366 */ | |
| 1367 void resume(); | |
| 1368 | |
| 1369 /** | |
| 1370 * Returns true if the [StreamSubscription] is paused. | |
| 1371 */ | |
| 1372 bool get isPaused; | |
| 1373 | |
| 1374 /** | |
| 1375 * Returns a future that handles the [onDone] and [onError] callbacks. | |
| 1376 * | |
| 1377 * This method *overwrites* the existing [onDone] and [onError] callbacks | |
| 1378 * with new ones that complete the returned future. | |
| 1379 * | |
| 1380 * In case of an error the subscription will automatically cancel (even | |
| 1381 * when it was listening with `cancelOnError` set to `false`). | |
| 1382 * | |
| 1383 * In case of a `done` event the future completes with the given | |
| 1384 * [futureValue]. | |
| 1385 */ | |
| 1386 Future asFuture([var futureValue]); | |
| 1387 } | |
| 1388 | |
| 1389 | |
| 1390 /** | |
| 1391 * An interface that abstracts creation or handling of [Stream] events. | |
| 1392 */ | |
| 1393 abstract class EventSink<T> implements Sink<T> { | |
| 1394 /** Send a data event to a stream. */ | |
| 1395 void add(T event); | |
| 1396 | |
| 1397 /** Send an async error to a stream. */ | |
| 1398 void addError(errorEvent, [StackTrace stackTrace]); | |
| 1399 | |
| 1400 /** Close the sink. No further events can be added after closing. */ | |
| 1401 void close(); | |
| 1402 } | |
| 1403 | |
| 1404 | |
| 1405 /** [Stream] wrapper that only exposes the [Stream] interface. */ | |
| 1406 class StreamView<T> extends Stream<T> { | |
| 1407 Stream<T> _stream; | |
| 1408 | |
| 1409 StreamView(this._stream); | |
| 1410 | |
| 1411 bool get isBroadcast => _stream.isBroadcast; | |
| 1412 | |
| 1413 Stream<T> asBroadcastStream({void onListen(StreamSubscription<T> subscription)
, | |
| 1414 void onCancel(StreamSubscription<T> subscription)
}) | |
| 1415 => _stream.asBroadcastStream(onListen: onListen, onCancel: onCancel); | |
| 1416 | |
| 1417 StreamSubscription<T> listen(void onData(T value), | |
| 1418 { Function onError, | |
| 1419 void onDone(), | |
| 1420 bool cancelOnError }) { | |
| 1421 return _stream.listen(onData, onError: onError, onDone: onDone, | |
| 1422 cancelOnError: cancelOnError); | |
| 1423 } | |
| 1424 } | |
| 1425 | |
| 1426 | |
| 1427 /** | |
| 1428 * The target of a [Stream.pipe] call. | |
| 1429 * | |
| 1430 * The [Stream.pipe] call will pass itself to this object, and then return | |
| 1431 * the resulting [Future]. The pipe should complete the future when it's | |
| 1432 * done. | |
| 1433 */ | |
| 1434 abstract class StreamConsumer<S> { | |
| 1435 /** | |
| 1436 * Consumes the elements of [stream]. | |
| 1437 * | |
| 1438 * Listens on [stream] and does something for each event. | |
| 1439 * | |
| 1440 * The consumer may stop listening after an error, or it may consume | |
| 1441 * all the errors and only stop at a done event. | |
| 1442 */ | |
| 1443 Future addStream(Stream<S> stream); | |
| 1444 | |
| 1445 /** | |
| 1446 * Tell the consumer that no futher streams will be added. | |
| 1447 * | |
| 1448 * Returns a future that is completed when the consumer is done handling | |
| 1449 * events. | |
| 1450 */ | |
| 1451 Future close(); | |
| 1452 } | |
| 1453 | |
| 1454 | |
| 1455 /** | |
| 1456 * A [StreamSink] unifies the asynchronous methods from [StreamConsumer] and | |
| 1457 * the synchronous methods from [EventSink]. | |
| 1458 * | |
| 1459 * The [EventSink] methods can't be used while the [addStream] is called. | |
| 1460 * As soon as the [addStream]'s [Future] completes with a value, the | |
| 1461 * [EventSink] methods can be used again. | |
| 1462 * | |
| 1463 * If [addStream] is called after any of the [EventSink] methods, it'll | |
| 1464 * be delayed until the underlying system has consumed the data added by the | |
| 1465 * [EventSink] methods. | |
| 1466 * | |
| 1467 * When [EventSink] methods are used, the [done] [Future] can be used to | |
| 1468 * catch any errors. | |
| 1469 * | |
| 1470 * When [close] is called, it will return the [done] [Future]. | |
| 1471 */ | |
| 1472 abstract class StreamSink<S> implements StreamConsumer<S>, EventSink<S> { | |
| 1473 /** | |
| 1474 * As [EventSink.close], but returns a future. | |
| 1475 * | |
| 1476 * Returns the same future as [done]. | |
| 1477 */ | |
| 1478 Future close(); | |
| 1479 | |
| 1480 /** | |
| 1481 * Return a future which is completed when the [StreamSink] is finished. | |
| 1482 * | |
| 1483 * If the `StreamSink` fails with an error, | |
| 1484 * perhaps in response to adding events using [add], [addError] or [close], | |
| 1485 * the [done] future will complete with that error. | |
| 1486 * | |
| 1487 * Otherwise, the returned future will complete when either: | |
| 1488 * | |
| 1489 * * all events have been processed and the sink has been closed, or | |
| 1490 * * the sink has otherwise been stopped from handling more events | |
| 1491 * (for example by cancelling a stream subscription). | |
| 1492 */ | |
| 1493 Future get done; | |
| 1494 } | |
| 1495 | |
| 1496 | |
| 1497 /** | |
| 1498 * The target of a [Stream.transform] call. | |
| 1499 * | |
| 1500 * The [Stream.transform] call will pass itself to this object and then return | |
| 1501 * the resulting stream. | |
| 1502 * | |
| 1503 * It is good practice to write transformers that can be used multiple times. | |
| 1504 */ | |
| 1505 abstract class StreamTransformer<S, T> { | |
| 1506 /** | |
| 1507 * Creates a [StreamTransformer]. | |
| 1508 * | |
| 1509 * The returned instance takes responsibility of implementing ([bind]). | |
| 1510 * When the user invokes `bind` it returns a new "bound" stream. Only when | |
| 1511 * the user starts listening to the bound stream, the `listen` method | |
| 1512 * invokes the given closure [transformer]. | |
| 1513 * | |
| 1514 * The [transformer] closure receives the stream, that was bound, as argument | |
| 1515 * and returns a [StreamSubscription]. In almost all cases the closure | |
| 1516 * listens itself to the stream that is given as argument. | |
| 1517 * | |
| 1518 * The result of invoking the [transformer] closure is a [StreamSubscription]. | |
| 1519 * The bound stream-transformer (created by the `bind` method above) then sets | |
| 1520 * the handlers it received as part of the `listen` call. | |
| 1521 * | |
| 1522 * Conceptually this can be summarized as follows: | |
| 1523 * | |
| 1524 * 1. `var transformer = new StreamTransformer(transformerClosure);` | |
| 1525 * creates a `StreamTransformer` that supports the `bind` method. | |
| 1526 * 2. `var boundStream = stream.transform(transformer);` binds the `stream` | |
| 1527 * and returns a bound stream that has a pointer to `stream`. | |
| 1528 * 3. `boundStream.listen(f1, onError: f2, onDone: f3, cancelOnError: b)` | |
| 1529 * starts the listening and transformation. This is accomplished | |
| 1530 * in 2 steps: first the `boundStream` invokes the `transformerClosure` with | |
| 1531 * the `stream` it captured: `transformerClosure(stream, b)`. | |
| 1532 * The result `subscription`, a [StreamSubscription], is then | |
| 1533 * updated to receive its handlers: `subscription.onData(f1)`, | |
| 1534 * `subscription.onError(f2)`, `subscription(f3)`. Finally the subscription | |
| 1535 * is returned as result of the `listen` call. | |
| 1536 * | |
| 1537 * There are two common ways to create a StreamSubscription: | |
| 1538 * | |
| 1539 * 1. by creating a new class that implements [StreamSubscription]. | |
| 1540 * Note that the subscription should run callbacks in the [Zone] the | |
| 1541 * stream was listened to. | |
| 1542 * 2. by allocating a [StreamController] and to return the result of | |
| 1543 * listening to its stream. | |
| 1544 * | |
| 1545 * Example use of a duplicating transformer: | |
| 1546 * | |
| 1547 * stringStream.transform(new StreamTransformer<String, String>( | |
| 1548 * (Stream<String> input, bool cancelOnError) { | |
| 1549 * StreamController<String> controller; | |
| 1550 * StreamSubscription<String> subscription; | |
| 1551 * controller = new StreamController<String>( | |
| 1552 * onListen: () { | |
| 1553 * subscription = input.listen((data) { | |
| 1554 * // Duplicate the data. | |
| 1555 * controller.add(data); | |
| 1556 * controller.add(data); | |
| 1557 * }, | |
| 1558 * onError: controller.addError, | |
| 1559 * onDone: controller.close, | |
| 1560 * cancelOnError: cancelOnError); | |
| 1561 * }, | |
| 1562 * onPause: subscription.pause, | |
| 1563 * onResume: subscription.resume, | |
| 1564 * onCancel: subscription.cancel, | |
| 1565 * sync: true); | |
| 1566 * return controller.stream.listen(null); | |
| 1567 * }); | |
| 1568 */ | |
| 1569 const factory StreamTransformer( | |
| 1570 StreamSubscription<T> transformer(Stream<S> stream, bool cancelOnError)) | |
| 1571 = _StreamSubscriptionTransformer; | |
| 1572 | |
| 1573 /** | |
| 1574 * Creates a [StreamTransformer] that delegates events to the given functions. | |
| 1575 * | |
| 1576 * Example use of a duplicating transformer: | |
| 1577 * | |
| 1578 * stringStream.transform(new StreamTransformer<String, String>.fromHandle
rs( | |
| 1579 * handleData: (String value, EventSink<String> sink) { | |
| 1580 * sink.add(value); | |
| 1581 * sink.add(value); // Duplicate the incoming events. | |
| 1582 * })); | |
| 1583 */ | |
| 1584 factory StreamTransformer.fromHandlers({ | |
| 1585 void handleData(S data, EventSink<T> sink), | |
| 1586 void handleError(Object error, StackTrace stackTrace, EventSink<T> sink), | |
| 1587 void handleDone(EventSink<T> sink)}) | |
| 1588 = _StreamHandlerTransformer; | |
| 1589 | |
| 1590 /** | |
| 1591 * Transform the incoming [stream]'s events. | |
| 1592 * | |
| 1593 * Creates a new stream. | |
| 1594 * When this stream is listened to, it will start listening on [stream], | |
| 1595 * and generate events on the new stream based on the events from [stream]. | |
| 1596 * | |
| 1597 * Subscriptions on the returned stream should propagate pause state | |
| 1598 * to the subscription on [stream]. | |
| 1599 */ | |
| 1600 Stream<T> bind(Stream<S> stream); | |
| 1601 } | |
| 1602 | |
| 1603 /** | |
| 1604 * An [Iterable] like interface for the values of a [Stream]. | |
| 1605 * | |
| 1606 * This wraps a [Stream] and a subscription on the stream. It listens | |
| 1607 * on the stream, and completes the future returned by [moveNext] when the | |
| 1608 * next value becomes available. | |
| 1609 */ | |
| 1610 abstract class StreamIterator<T> { | |
| 1611 | |
| 1612 /** Create a [StreamIterator] on [stream]. */ | |
| 1613 factory StreamIterator(Stream<T> stream) | |
| 1614 // TODO(lrn): use redirecting factory constructor when type | |
| 1615 // arguments are supported. | |
| 1616 => new _StreamIteratorImpl<T>(stream); | |
| 1617 | |
| 1618 /** | |
| 1619 * Wait for the next stream value to be available. | |
| 1620 * | |
| 1621 * It is not allowed to call this function again until the future has | |
| 1622 * completed. If the returned future completes with anything except `true`, | |
| 1623 * the iterator is done, and no new value will ever be available. | |
| 1624 * | |
| 1625 * The future may complete with an error, if the stream produces an error. | |
| 1626 */ | |
| 1627 Future<bool> moveNext(); | |
| 1628 | |
| 1629 /** | |
| 1630 * The current value of the stream. | |
| 1631 * | |
| 1632 * Only valid when the future returned by [moveNext] completes with `true` | |
| 1633 * as value, and only until the next call to [moveNext]. | |
| 1634 */ | |
| 1635 T get current; | |
| 1636 | |
| 1637 /** | |
| 1638 * Cancels the stream iterator (and the underlying stream subscription) early. | |
| 1639 * | |
| 1640 * The stream iterator is automatically canceled if the [moveNext] future | |
| 1641 * completes with either `false` or an error. | |
| 1642 * | |
| 1643 * If a [moveNext] call has been made, it will complete with `false` as value, | |
| 1644 * as will all further calls to [moveNext]. | |
| 1645 * | |
| 1646 * If you need to stop listening for values before the stream iterator is | |
| 1647 * automatically closed, you must call [cancel] to ensure that the stream | |
| 1648 * is properly closed. | |
| 1649 * | |
| 1650 * Returns a future if the cancel-operation is not completed synchronously. | |
| 1651 * Otherwise returns `null`. | |
| 1652 */ | |
| 1653 Future cancel(); | |
| 1654 } | |
| 1655 | |
| 1656 | |
| 1657 /** | |
| 1658 * Wraps an [_EventSink] so it exposes only the [EventSink] interface. | |
| 1659 */ | |
| 1660 class _ControllerEventSinkWrapper<T> implements EventSink<T> { | |
| 1661 EventSink _sink; | |
| 1662 _ControllerEventSinkWrapper(this._sink); | |
| 1663 | |
| 1664 void add(T data) { _sink.add(data); } | |
| 1665 void addError(error, [StackTrace stackTrace]) { | |
| 1666 _sink.addError(error, stackTrace); | |
| 1667 } | |
| 1668 void close() { _sink.close(); } | |
| 1669 } | |
| OLD | NEW |