| 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 part of dart.async; | 5 part of dart.async; |
| 6 | 6 |
| 7 // ------------------------------------------------------------------- | 7 // ------------------------------------------------------------------- |
| 8 // Core Stream types | 8 // Core Stream types |
| 9 // ------------------------------------------------------------------- | 9 // ------------------------------------------------------------------- |
| 10 | 10 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 42 * itself when the listener is unsubscribed, even if the stream wasn't done. | 42 * itself when the listener is unsubscribed, even if the stream wasn't done. |
| 43 * | 43 * |
| 44 * Single-subscription streams are generally used for streaming parts of | 44 * Single-subscription streams are generally used for streaming parts of |
| 45 * contiguous data like file I/O. | 45 * contiguous data like file I/O. |
| 46 * | 46 * |
| 47 * A broadcast stream allows any number of listeners, and it fires | 47 * A broadcast stream allows any number of listeners, and it fires |
| 48 * its events when they are ready, whether there are listeners or not. | 48 * its events when they are ready, whether there are listeners or not. |
| 49 * | 49 * |
| 50 * Broadcast streams are used for independent events/observers. | 50 * Broadcast streams are used for independent events/observers. |
| 51 * | 51 * |
| 52 * Stream transformations, such as [where] and [skip], always return | 52 * Stream transformations, such as [where] and [skip], |
| 53 * non-broadcast streams. If several listeners want to listen to the returned | 53 * return the same type of stream as the one the method was called on, |
| 54 * unless otherwise noted. |
| 55 * |
| 56 * If several listeners want to listen to the returned |
| 54 * stream, use [asBroadcastStream] to create a broadcast stream on top of the | 57 * stream, use [asBroadcastStream] to create a broadcast stream on top of the |
| 55 * non-broadcast stream. | 58 * non-broadcast stream. |
| 56 * | 59 * |
| 57 * The default implementation of [isBroadcast] returns false. | 60 * The default implementation of [isBroadcast] returns false. |
| 58 * A broadcast stream inheriting from [Stream] must override [isBroadcast] | 61 * A broadcast stream inheriting from [Stream] must override [isBroadcast] |
| 59 * to return [:true:]. | 62 * to return [:true:]. |
| 60 */ | 63 */ |
| 61 abstract class Stream<T> { | 64 abstract class Stream<T> { |
| 62 Stream(); | 65 Stream(); |
| 63 | 66 |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 196 } | 199 } |
| 197 | 200 |
| 198 /** | 201 /** |
| 199 * Reports whether this stream is a broadcast stream. | 202 * Reports whether this stream is a broadcast stream. |
| 200 */ | 203 */ |
| 201 bool get isBroadcast => false; | 204 bool get isBroadcast => false; |
| 202 | 205 |
| 203 /** | 206 /** |
| 204 * Returns a multi-subscription stream that produces the same events as this. | 207 * Returns a multi-subscription stream that produces the same events as this. |
| 205 * | 208 * |
| 206 * If this stream is already a broadcast stream, it is returned unmodified. | 209 * The returned stream will subscribe to this stream when its first |
| 207 * | |
| 208 * If this stream is single-subscription, return a new stream that allows | |
| 209 * multiple subscribers. It will subscribe to this stream when its first | |
| 210 * subscriber is added, and will stay subscribed until this stream ends, | 210 * subscriber is added, and will stay subscribed until this stream ends, |
| 211 * or a callback cancels the subscription. | 211 * or a callback cancels the subscription. |
| 212 * | 212 * |
| 213 * If [onListen] is provided, it is called with a subscription-like object | 213 * If [onListen] is provided, it is called with a subscription-like object |
| 214 * that represents the underlying subscription to this stream. It is | 214 * that represents the underlying subscription to this stream. It is |
| 215 * possible to pause, resume or cancel the subscription during the call | 215 * possible to pause, resume or cancel the subscription during the call |
| 216 * to [onListen]. It is not possible to change the event handlers, including | 216 * to [onListen]. It is not possible to change the event handlers, including |
| 217 * using [StreamSubscription.asFuture]. | 217 * using [StreamSubscription.asFuture]. |
| 218 * | 218 * |
| 219 * If [onCancel] is provided, it is called in a similar way to [onListen] | 219 * If [onCancel] is provided, it is called in a similar way to [onListen] |
| 220 * when the returned stream stops having listener. If it later gets | 220 * when the returned stream stops having listener. If it later gets |
| 221 * a new listener, the [onListen] function is called again. | 221 * a new listener, the [onListen] function is called again. |
| 222 * | 222 * |
| 223 * Use the callbacks, for example, for pausing the underlying subscription | 223 * Use the callbacks, for example, for pausing the underlying subscription |
| 224 * while having no subscribers to prevent losing events, or canceling the | 224 * while having no subscribers to prevent losing events, or canceling the |
| 225 * subscription when there are no listeners. | 225 * subscription when there are no listeners. |
| 226 */ | 226 */ |
| 227 Stream<T> asBroadcastStream({ | 227 Stream<T> asBroadcastStream({ |
| 228 void onListen(StreamSubscription<T> subscription), | 228 void onListen(StreamSubscription<T> subscription), |
| 229 void onCancel(StreamSubscription<T> subscription) }) { | 229 void onCancel(StreamSubscription<T> subscription) }) { |
| 230 if (isBroadcast) return this; | |
| 231 return new _AsBroadcastStream<T>(this, onListen, onCancel); | 230 return new _AsBroadcastStream<T>(this, onListen, onCancel); |
| 232 } | 231 } |
| 233 | 232 |
| 234 /** | 233 /** |
| 235 * Adds a subscription to this stream. | 234 * Adds a subscription to this stream. |
| 236 * | 235 * |
| 237 * On each data event from this stream, the subscriber's [onData] handler | 236 * On each data event from this stream, the subscriber's [onData] handler |
| 238 * is called. If [onData] is null, nothing happens. | 237 * is called. If [onData] is null, nothing happens. |
| 239 * | 238 * |
| 240 * On errors from this stream, the [onError] handler is given a | 239 * On errors from this stream, the [onError] handler is given a |
| (...skipping 14 matching lines...) Expand all Loading... |
| 255 { Function onError, | 254 { Function onError, |
| 256 void onDone(), | 255 void onDone(), |
| 257 bool cancelOnError}); | 256 bool cancelOnError}); |
| 258 | 257 |
| 259 /** | 258 /** |
| 260 * Creates a new stream from this stream that discards some data events. | 259 * Creates a new stream from this stream that discards some data events. |
| 261 * | 260 * |
| 262 * The new stream sends the same error and done events as this stream, | 261 * The new stream sends the same error and done events as this stream, |
| 263 * but it only sends the data events that satisfy the [test]. | 262 * but it only sends the data events that satisfy the [test]. |
| 264 * | 263 * |
| 265 * The returned stream is not a broadcast stream, even if this stream is. | 264 * The returned stream is a broadcast stream if this stream is. |
| 266 */ | 265 */ |
| 267 Stream<T> where(bool test(T event)) { | 266 Stream<T> where(bool test(T event)) { |
| 268 return new _WhereStream<T>(this, test); | 267 return new _WhereStream<T>(this, test); |
| 269 } | 268 } |
| 270 | 269 |
| 271 /** | 270 /** |
| 272 * Creates a new stream that converts each element of this stream | 271 * Creates a new stream that converts each element of this stream |
| 273 * to a new value using the [convert] function. | 272 * to a new value using the [convert] function. |
| 274 * | 273 * |
| 275 * The returned stream is not a broadcast stream, even if this stream is. | 274 * The returned stream is a broadcast stream if this stream is. |
| 276 */ | 275 */ |
| 277 Stream map(convert(T event)) { | 276 Stream map(convert(T event)) { |
| 278 return new _MapStream<T, dynamic>(this, convert); | 277 return new _MapStream<T, dynamic>(this, convert); |
| 279 } | 278 } |
| 280 | 279 |
| 281 /** | 280 /** |
| 282 * Creates a new stream with each data event of this stream asynchronously | 281 * Creates a new stream with each data event of this stream asynchronously |
| 283 * mapped to a new event. | 282 * mapped to a new event. |
| 284 * | 283 * |
| 285 * This acts like [map], except that [convert] may return a [Future], | 284 * This acts like [map], except that [convert] may return a [Future], |
| 286 * and in that case, the stream waits for that future to complete before | 285 * and in that case, the stream waits for that future to complete before |
| 287 * continuing with its result. | 286 * continuing with its result. |
| 287 * |
| 288 * The returned stream is a broadcast stream if this stream is. |
| 288 */ | 289 */ |
| 289 Stream asyncMap(convert(T event)) { | 290 Stream asyncMap(convert(T event)) { |
| 290 StreamController controller; | 291 StreamController controller; |
| 291 StreamSubscription subscription; | 292 StreamSubscription subscription; |
| 292 controller = new StreamController( | 293 void onListen () { |
| 293 onListen: () { | 294 var add = controller.add; |
| 294 var add = controller.add; | 295 var addError = controller.addError; |
| 295 var addError = controller.addError; | 296 subscription = this.listen( |
| 296 subscription = this.listen( | 297 (T event) { |
| 297 (T event) { | 298 var newValue; |
| 298 var newValue; | 299 try { |
| 299 try { | 300 newValue = convert(event); |
| 300 newValue = convert(event); | 301 } catch (e, s) { |
| 301 } catch (e, s) { | 302 controller.addError(e, s); |
| 302 controller.addError(e, s); | 303 return; |
| 303 return; | 304 } |
| 304 } | 305 if (newValue is Future) { |
| 305 if (newValue is Future) { | 306 subscription.pause(); |
| 306 subscription.pause(); | 307 newValue.then(add, onError: addError) |
| 307 newValue.then(add, onError: addError) | 308 .whenComplete(subscription.resume); |
| 308 .whenComplete(subscription.resume); | 309 } else { |
| 309 } else { | 310 controller.add(newValue); |
| 310 controller.add(newValue); | 311 } |
| 311 } | 312 }, |
| 312 }, | 313 onError: addError, |
| 313 onError: addError, | 314 onDone: controller.close |
| 314 onDone: controller.close | 315 ); |
| 315 ); | 316 } |
| 316 }, | 317 if (this.isBroadcast) { |
| 317 onPause: () { subscription.pause(); }, | 318 controller = new StreamController.broadcast( |
| 318 onResume: () { subscription.resume(); }, | 319 onListen: onListen, |
| 319 onCancel: () { subscription.cancel(); }, | 320 onCancel: () { subscription.cancel(); }, |
| 320 sync: true | 321 sync: true |
| 321 ); | 322 ); |
| 323 } else { |
| 324 controller = new StreamController( |
| 325 onListen: onListen, |
| 326 onPause: () { subscription.pause(); }, |
| 327 onResume: () { subscription.resume(); }, |
| 328 onCancel: () { subscription.cancel(); }, |
| 329 sync: true |
| 330 ); |
| 331 } |
| 322 return controller.stream; | 332 return controller.stream; |
| 323 } | 333 } |
| 324 | 334 |
| 325 /** | 335 /** |
| 326 * Creates a new stream with the events of a stream per original event. | 336 * Creates a new stream with the events of a stream per original event. |
| 327 * | 337 * |
| 328 * This acts like [expand], except that [convert] returns a [Stream] | 338 * This acts like [expand], except that [convert] returns a [Stream] |
| 329 * instead of an [Iterable]. | 339 * instead of an [Iterable]. |
| 330 * The events of the returned stream becomes the events of the returned | 340 * The events of the returned stream becomes the events of the returned |
| 331 * stream, in the order they are produced. | 341 * stream, in the order they are produced. |
| 332 * | 342 * |
| 333 * If [convert] returns `null`, no value is put on the output stream, | 343 * If [convert] returns `null`, no value is put on the output stream, |
| 334 * just as if it returned an empty stream. | 344 * just as if it returned an empty stream. |
| 345 * |
| 346 * The returned stream is a broadcast stream if this stream is. |
| 335 */ | 347 */ |
| 336 Stream asyncExpand(Stream convert(T event)) { | 348 Stream asyncExpand(Stream convert(T event)) { |
| 337 StreamController controller; | 349 StreamController controller; |
| 338 StreamSubscription subscription; | 350 StreamSubscription subscription; |
| 339 controller = new StreamController( | 351 void onListen() { |
| 340 onListen: () { | 352 subscription = this.listen( |
| 341 subscription = this.listen( | 353 (T event) { |
| 342 (T event) { | 354 Stream newStream; |
| 343 Stream newStream; | 355 try { |
| 344 try { | 356 newStream = convert(event); |
| 345 newStream = convert(event); | 357 } catch (e, s) { |
| 346 } catch (e, s) { | 358 controller.addError(e, s); |
| 347 controller.addError(e, s); | 359 return; |
| 348 return; | 360 } |
| 349 } | 361 if (newStream != null) { |
| 350 if (newStream != null) { | 362 subscription.pause(); |
| 351 subscription.pause(); | 363 controller.addStream(newStream) |
| 352 controller.addStream(newStream) | 364 .whenComplete(subscription.resume); |
| 353 .whenComplete(subscription.resume); | 365 } |
| 354 } | 366 }, |
| 355 }, | 367 onError: controller.addError, |
| 356 onError: controller.addError, | 368 onDone: controller.close |
| 357 onDone: controller.close | 369 ); |
| 358 ); | 370 } |
| 359 }, | 371 if (this.isBroadcast) { |
| 360 onPause: () { subscription.pause(); }, | 372 controller = new StreamController.broadcast( |
| 361 onResume: () { subscription.resume(); }, | 373 onListen: onListen, |
| 362 onCancel: () { subscription.cancel(); }, | 374 onCancel: () { subscription.cancel(); }, |
| 363 sync: true | 375 sync: true |
| 364 ); | 376 ); |
| 377 } else { |
| 378 controller = new StreamController( |
| 379 onListen: onListen, |
| 380 onPause: () { subscription.pause(); }, |
| 381 onResume: () { subscription.resume(); }, |
| 382 onCancel: () { subscription.cancel(); }, |
| 383 sync: true |
| 384 ); |
| 385 } |
| 365 return controller.stream; | 386 return controller.stream; |
| 366 } | 387 } |
| 367 | 388 |
| 368 /** | 389 /** |
| 369 * Creates a wrapper Stream that intercepts some errors from this stream. | 390 * Creates a wrapper Stream that intercepts some errors from this stream. |
| 370 * | 391 * |
| 371 * If this stream sends an error that matches [test], then it is intercepted | 392 * If this stream sends an error that matches [test], then it is intercepted |
| 372 * by the [handle] function. | 393 * by the [handle] function. |
| 373 * | 394 * |
| 374 * The [onError] callback must be of type `void onError(error)` or | 395 * The [onError] callback must be of type `void onError(error)` or |
| 375 * `void onError(error, StackTrace stackTrace)`. Depending on the function | 396 * `void onError(error, StackTrace stackTrace)`. Depending on the function |
| 376 * type the the stream either invokes [onError] with or without a stack | 397 * type the the stream either invokes [onError] with or without a stack |
| 377 * trace. The stack trace argument might be `null` if the stream itself | 398 * trace. The stack trace argument might be `null` if the stream itself |
| 378 * received an error without stack trace. | 399 * received an error without stack trace. |
| 379 * | 400 * |
| 380 * An asynchronous error [:e:] is matched by a test function if [:test(e):] | 401 * An asynchronous error [:e:] is matched by a test function if [:test(e):] |
| 381 * returns true. If [test] is omitted, every error is considered matching. | 402 * returns true. If [test] is omitted, every error is considered matching. |
| 382 * | 403 * |
| 383 * If the error is intercepted, the [handle] function can decide what to do | 404 * If the error is intercepted, the [handle] function can decide what to do |
| 384 * with it. It can throw if it wants to raise a new (or the same) error, | 405 * with it. It can throw if it wants to raise a new (or the same) error, |
| 385 * or simply return to make the stream forget the error. | 406 * or simply return to make the stream forget the error. |
| 386 * | 407 * |
| 387 * If you need to transform an error into a data event, use the more generic | 408 * If you need to transform an error into a data event, use the more generic |
| 388 * [Stream.transform] to handle the event by writing a data event to | 409 * [Stream.transform] to handle the event by writing a data event to |
| 389 * the output sink | 410 * the output sink |
| 390 * | 411 * |
| 391 * The returned stream is not a broadcast stream, even if this stream is. | 412 * The returned stream is a broadcast stream if this stream is. |
| 392 */ | 413 */ |
| 393 Stream<T> handleError(Function onError, { bool test(error) }) { | 414 Stream<T> handleError(Function onError, { bool test(error) }) { |
| 394 return new _HandleErrorStream<T>(this, onError, test); | 415 return new _HandleErrorStream<T>(this, onError, test); |
| 395 } | 416 } |
| 396 | 417 |
| 397 /** | 418 /** |
| 398 * Creates a new stream from this stream that converts each element | 419 * Creates a new stream from this stream that converts each element |
| 399 * into zero or more events. | 420 * into zero or more events. |
| 400 * | 421 * |
| 401 * Each incoming event is converted to an [Iterable] of new events, | 422 * Each incoming event is converted to an [Iterable] of new events, |
| 402 * and each of these new events are then sent by the returned stream | 423 * and each of these new events are then sent by the returned stream |
| 403 * in order. | 424 * in order. |
| 404 * | 425 * |
| 405 * The returned stream is not a broadcast stream, even if this stream is. | 426 * The returned stream is a broadcast stream if this stream is. |
| 406 */ | 427 */ |
| 407 Stream expand(Iterable convert(T value)) { | 428 Stream expand(Iterable convert(T value)) { |
| 408 return new _ExpandStream<T, dynamic>(this, convert); | 429 return new _ExpandStream<T, dynamic>(this, convert); |
| 409 } | 430 } |
| 410 | 431 |
| 411 /** | 432 /** |
| 412 * Binds this stream as the input of the provided [StreamConsumer]. | 433 * Binds this stream as the input of the provided [StreamConsumer]. |
| 413 */ | 434 */ |
| 414 Future pipe(StreamConsumer<T> streamConsumer) { | 435 Future pipe(StreamConsumer<T> streamConsumer) { |
| 415 return streamConsumer.addStream(this).then((_) => streamConsumer.close()); | 436 return streamConsumer.addStream(this).then((_) => streamConsumer.close()); |
| 416 } | 437 } |
| 417 | 438 |
| 418 /** | 439 /** |
| 419 * Chains this stream as the input of the provided [StreamTransformer]. | 440 * Chains this stream as the input of the provided [StreamTransformer]. |
| 420 * | 441 * |
| 421 * Returns the result of [:streamTransformer.bind:] itself. | 442 * Returns the result of [:streamTransformer.bind:] itself. |
| 443 * |
| 444 * The `streamTransformer` can decide whether it wants to return a |
| 445 * broadcast stream or not. |
| 422 */ | 446 */ |
| 423 Stream transform(StreamTransformer<T, dynamic> streamTransformer) { | 447 Stream transform(StreamTransformer<T, dynamic> streamTransformer) { |
| 424 return streamTransformer.bind(this); | 448 return streamTransformer.bind(this); |
| 425 } | 449 } |
| 426 | 450 |
| 427 /** | 451 /** |
| 428 * Reduces a sequence of values by repeatedly applying [combine]. | 452 * Reduces a sequence of values by repeatedly applying [combine]. |
| 429 */ | 453 */ |
| 430 Future<T> reduce(T combine(T previous, T element)) { | 454 Future<T> reduce(T combine(T previous, T element)) { |
| 431 _Future<T> result = new _Future<T>(); | 455 _Future<T> result = new _Future<T>(); |
| (...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 731 * If this stream produces fewer than [count] values before it's done, | 755 * If this stream produces fewer than [count] values before it's done, |
| 732 * so will the returned stream. | 756 * so will the returned stream. |
| 733 * | 757 * |
| 734 * Stops listening to the stream after the first [n] elements have been | 758 * Stops listening to the stream after the first [n] elements have been |
| 735 * received. | 759 * received. |
| 736 * | 760 * |
| 737 * Internally the method cancels its subscription after these elements. This | 761 * Internally the method cancels its subscription after these elements. This |
| 738 * means that single-subscription (non-broadcast) streams are closed and | 762 * means that single-subscription (non-broadcast) streams are closed and |
| 739 * cannot be reused after a call to this method. | 763 * cannot be reused after a call to this method. |
| 740 * | 764 * |
| 741 * The returned stream is not a broadcast stream, even if this stream is. | 765 * The returned stream is a broadcast stream if this stream is. |
| 742 */ | 766 */ |
| 743 Stream<T> take(int count) { | 767 Stream<T> take(int count) { |
| 744 return new _TakeStream(this, count); | 768 return new _TakeStream(this, count); |
| 745 } | 769 } |
| 746 | 770 |
| 747 /** | 771 /** |
| 748 * Forwards data events while [test] is successful. | 772 * Forwards data events while [test] is successful. |
| 749 * | 773 * |
| 750 * The returned stream provides the same events as this stream as long | 774 * The returned stream provides the same events as this stream as long |
| 751 * as [test] returns [:true:] for the event data. The stream is done | 775 * as [test] returns [:true:] for the event data. The stream is done |
| 752 * when either this stream is done, or when this stream first provides | 776 * when either this stream is done, or when this stream first provides |
| 753 * a value that [test] doesn't accept. | 777 * a value that [test] doesn't accept. |
| 754 * | 778 * |
| 755 * Stops listening to the stream after the accepted elements. | 779 * Stops listening to the stream after the accepted elements. |
| 756 * | 780 * |
| 757 * Internally the method cancels its subscription after these elements. This | 781 * Internally the method cancels its subscription after these elements. This |
| 758 * means that single-subscription (non-broadcast) streams are closed and | 782 * means that single-subscription (non-broadcast) streams are closed and |
| 759 * cannot be reused after a call to this method. | 783 * cannot be reused after a call to this method. |
| 760 * | 784 * |
| 761 * The returned stream is not a broadcast stream, even if this stream is. | 785 * The returned stream is a broadcast stream if this stream is. |
| 762 */ | 786 */ |
| 763 Stream<T> takeWhile(bool test(T element)) { | 787 Stream<T> takeWhile(bool test(T element)) { |
| 764 return new _TakeWhileStream(this, test); | 788 return new _TakeWhileStream(this, test); |
| 765 } | 789 } |
| 766 | 790 |
| 767 /** | 791 /** |
| 768 * Skips the first [count] data events from this stream. | 792 * Skips the first [count] data events from this stream. |
| 769 * | 793 * |
| 770 * The returned stream is not a broadcast stream, even if this stream is. | 794 * The returned stream is a broadcast stream if this stream is. |
| 771 */ | 795 */ |
| 772 Stream<T> skip(int count) { | 796 Stream<T> skip(int count) { |
| 773 return new _SkipStream(this, count); | 797 return new _SkipStream(this, count); |
| 774 } | 798 } |
| 775 | 799 |
| 776 /** | 800 /** |
| 777 * Skip data events from this stream while they are matched by [test]. | 801 * Skip data events from this stream while they are matched by [test]. |
| 778 * | 802 * |
| 779 * Error and done events are provided by the returned stream unmodified. | 803 * Error and done events are provided by the returned stream unmodified. |
| 780 * | 804 * |
| 781 * Starting with the first data event where [test] returns false for the | 805 * Starting with the first data event where [test] returns false for the |
| 782 * event data, the returned stream will have the same events as this stream. | 806 * event data, the returned stream will have the same events as this stream. |
| 783 * | 807 * |
| 784 * The returned stream is not a broadcast stream, even if this stream is. | 808 * The returned stream is a broadcast stream if this stream is. |
| 785 */ | 809 */ |
| 786 Stream<T> skipWhile(bool test(T element)) { | 810 Stream<T> skipWhile(bool test(T element)) { |
| 787 return new _SkipWhileStream(this, test); | 811 return new _SkipWhileStream(this, test); |
| 788 } | 812 } |
| 789 | 813 |
| 790 /** | 814 /** |
| 791 * Skips data events if they are equal to the previous data event. | 815 * Skips data events if they are equal to the previous data event. |
| 792 * | 816 * |
| 793 * The returned stream provides the same events as this stream, except | 817 * The returned stream provides the same events as this stream, except |
| 794 * that it never provides two consequtive data events that are equal. | 818 * that it never provides two consequtive data events that are equal. |
| 795 * | 819 * |
| 796 * Equality is determined by the provided [equals] method. If that is | 820 * Equality is determined by the provided [equals] method. If that is |
| 797 * omitted, the '==' operator on the last provided data element is used. | 821 * omitted, the '==' operator on the last provided data element is used. |
| 798 * | 822 * |
| 799 * The returned stream is not a broadcast stream, even if this stream is. | 823 * The returned stream is a broadcast stream if this stream is. |
| 800 */ | 824 */ |
| 801 Stream<T> distinct([bool equals(T previous, T next)]) { | 825 Stream<T> distinct([bool equals(T previous, T next)]) { |
| 802 return new _DistinctStream(this, equals); | 826 return new _DistinctStream(this, equals); |
| 803 } | 827 } |
| 804 | 828 |
| 805 /** | 829 /** |
| 806 * Returns the first element of the stream. | 830 * Returns the first element of the stream. |
| 807 * | 831 * |
| 808 * Stops listening to the stream after the first element has been received. | 832 * Stops listening to the stream after the first element has been received. |
| 809 * | 833 * |
| (...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1081 * The countdown is reset every time an event is forwarded from this stream, | 1105 * The countdown is reset every time an event is forwarded from this stream, |
| 1082 * or when the stream is paused and resumed. | 1106 * or when the stream is paused and resumed. |
| 1083 * | 1107 * |
| 1084 * The [onTimeout] function is called with one argument: an | 1108 * The [onTimeout] function is called with one argument: an |
| 1085 * [EventSink] that allows putting events into the returned stream. | 1109 * [EventSink] that allows putting events into the returned stream. |
| 1086 * This `EventSink` is only valid during the call to `onTimeout`. | 1110 * This `EventSink` is only valid during the call to `onTimeout`. |
| 1087 * | 1111 * |
| 1088 * If `onTimeout` is omitted, a timeout will just put a [TimeoutException] | 1112 * If `onTimeout` is omitted, a timeout will just put a [TimeoutException] |
| 1089 * into the error channel of the returned stream. | 1113 * into the error channel of the returned stream. |
| 1090 * | 1114 * |
| 1091 * The returned stream is not a broadcast stream, even if this stream is. | 1115 * The returned stream is a broadcast stream if this stream is. |
| 1092 */ | 1116 */ |
| 1093 Stream timeout(Duration timeLimit, {void onTimeout(EventSink sink)}) { | 1117 Stream timeout(Duration timeLimit, {void onTimeout(EventSink sink)}) { |
| 1118 StreamController controller; |
| 1119 // The following variables are set on listen. |
| 1094 StreamSubscription<T> subscription; | 1120 StreamSubscription<T> subscription; |
| 1095 _StreamController controller; | |
| 1096 // The following variables are set on listen. | |
| 1097 Timer timer; | 1121 Timer timer; |
| 1098 Zone zone; | 1122 Zone zone; |
| 1099 Function timeout; | 1123 Function timeout; |
| 1100 | 1124 |
| 1101 void onData(T event) { | 1125 void onData(T event) { |
| 1102 timer.cancel(); | 1126 timer.cancel(); |
| 1103 controller.add(event); | 1127 controller.add(event); |
| 1104 timer = zone.createTimer(timeLimit, timeout); | 1128 timer = zone.createTimer(timeLimit, timeout); |
| 1105 } | 1129 } |
| 1106 void onError(error, StackTrace stackTrace) { | 1130 void onError(error, StackTrace stackTrace) { |
| 1107 timer.cancel(); | 1131 timer.cancel(); |
| 1108 controller.addError(error, stackTrace); | 1132 controller.addError(error, stackTrace); |
| 1109 timer = zone.createTimer(timeLimit, timeout); | 1133 timer = zone.createTimer(timeLimit, timeout); |
| 1110 } | 1134 } |
| 1111 void onDone() { | 1135 void onDone() { |
| 1112 timer.cancel(); | 1136 timer.cancel(); |
| 1113 controller.close(); | 1137 controller.close(); |
| 1114 } | 1138 } |
| 1115 controller = new _SyncStreamController( | 1139 void onListen() { |
| 1116 () { | 1140 // This is the onListen callback for of controller. |
| 1117 // This is the onListen callback for of controller. | 1141 // It runs in the same zone that the subscription was created in. |
| 1118 // It runs in the same zone that the subscription was created in. | 1142 // Use that zone for creating timers and running the onTimeout |
| 1119 // Use that zone for creating timers and running the onTimeout | 1143 // callback. |
| 1120 // callback. | 1144 zone = Zone.current; |
| 1121 zone = Zone.current; | 1145 if (onTimeout == null) { |
| 1122 if (onTimeout == null) { | 1146 timeout = () { |
| 1123 timeout = () { | 1147 controller.addError(new TimeoutException("No stream event", |
| 1124 controller.addError(new TimeoutException("No stream event", | 1148 timeLimit)); |
| 1125 timeLimit)); | 1149 }; |
| 1126 }; | 1150 } else { |
| 1127 } else { | 1151 onTimeout = zone.registerUnaryCallback(onTimeout); |
| 1128 onTimeout = zone.registerUnaryCallback(onTimeout); | 1152 _ControllerEventSinkWrapper wrapper = |
| 1129 _ControllerEventSinkWrapper wrapper = | 1153 new _ControllerEventSinkWrapper(null); |
| 1130 new _ControllerEventSinkWrapper(null); | 1154 timeout = () { |
| 1131 timeout = () { | 1155 wrapper._sink = controller; // Only valid during call. |
| 1132 wrapper._sink = controller; // Only valid during call. | 1156 zone.runUnaryGuarded(onTimeout, wrapper); |
| 1133 zone.runUnaryGuarded(onTimeout, wrapper); | 1157 wrapper._sink = null; |
| 1134 wrapper._sink = null; | 1158 }; |
| 1135 }; | 1159 } |
| 1136 } | |
| 1137 | 1160 |
| 1138 subscription = this.listen(onData, onError: onError, onDone: onDone); | 1161 subscription = this.listen(onData, onError: onError, onDone: onDone); |
| 1139 timer = zone.createTimer(timeLimit, timeout); | 1162 timer = zone.createTimer(timeLimit, timeout); |
| 1140 }, | 1163 } |
| 1141 () { | 1164 Future onCancel() { |
| 1142 timer.cancel(); | 1165 timer.cancel(); |
| 1143 subscription.pause(); | 1166 Future result = subscription.cancel(); |
| 1144 }, | 1167 subscription = null; |
| 1145 () { | 1168 return result; |
| 1146 subscription.resume(); | 1169 } |
| 1147 timer = zone.createTimer(timeLimit, timeout); | 1170 controller = isBroadcast |
| 1148 }, | 1171 ? new _SyncBroadcastStreamController(onListen, onCancel) |
| 1149 () { | 1172 : new _SyncStreamController( |
| 1150 timer.cancel(); | 1173 onListen, |
| 1151 Future result = subscription.cancel(); | 1174 () { |
| 1152 subscription = null; | 1175 // Don't null the timer, onCancel may call cancel again. |
| 1153 return result; | 1176 timer.cancel(); |
| 1154 }); | 1177 subscription.pause(); |
| 1178 }, |
| 1179 () { |
| 1180 subscription.resume(); |
| 1181 timer = zone.createTimer(timeLimit, timeout); |
| 1182 }, |
| 1183 onCancel); |
| 1155 return controller.stream; | 1184 return controller.stream; |
| 1156 } | 1185 } |
| 1157 } | 1186 } |
| 1158 | 1187 |
| 1159 /** | 1188 /** |
| 1160 * A control object for the subscription on a [Stream]. | 1189 * A control object for the subscription on a [Stream]. |
| 1161 * | 1190 * |
| 1162 * When you subscribe on a [Stream] using [Stream.listen], | 1191 * When you subscribe on a [Stream] using [Stream.listen], |
| 1163 * a [StreamSubscription] object is returned. This object | 1192 * a [StreamSubscription] object is returned. This object |
| 1164 * is used to later unsubscribe again, or to temporarily pause | 1193 * is used to later unsubscribe again, or to temporarily pause |
| (...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1489 class _ControllerEventSinkWrapper<T> implements EventSink<T> { | 1518 class _ControllerEventSinkWrapper<T> implements EventSink<T> { |
| 1490 EventSink _sink; | 1519 EventSink _sink; |
| 1491 _ControllerEventSinkWrapper(this._sink); | 1520 _ControllerEventSinkWrapper(this._sink); |
| 1492 | 1521 |
| 1493 void add(T data) { _sink.add(data); } | 1522 void add(T data) { _sink.add(data); } |
| 1494 void addError(error, [StackTrace stackTrace]) { | 1523 void addError(error, [StackTrace stackTrace]) { |
| 1495 _sink.addError(error, stackTrace); | 1524 _sink.addError(error, stackTrace); |
| 1496 } | 1525 } |
| 1497 void close() { _sink.close(); } | 1526 void close() { _sink.close(); } |
| 1498 } | 1527 } |
| OLD | NEW |