Chromium Code Reviews| 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 631 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 642 return new _TakeStream(this, count); | 642 return new _TakeStream(this, count); |
| 643 } | 643 } |
| 644 | 644 |
| 645 /** | 645 /** |
| 646 * Forwards data events while [test] is successful. | 646 * Forwards data events while [test] is successful. |
| 647 * | 647 * |
| 648 * The returned stream provides the same events as this stream as long | 648 * The returned stream provides the same events as this stream as long |
| 649 * as [test] returns [:true:] for the event data. The stream is done | 649 * as [test] returns [:true:] for the event data. The stream is done |
| 650 * when either this stream is done, or when this stream first provides | 650 * when either this stream is done, or when this stream first provides |
| 651 * a value that [test] doesn't accept. | 651 * a value that [test] doesn't accept. |
| 652 * | 652 * |
| 653 * Stops listening to the stream after the accepted elements. | 653 * Stops listening to the stream after the accepted elements. |
| 654 * | 654 * |
| 655 * Internally the method cancels its subscription after these elements. This | 655 * Internally the method cancels its subscription after these elements. This |
| 656 * means that single-subscription (non-broadcast) streams are closed and | 656 * means that single-subscription (non-broadcast) streams are closed and |
| 657 * cannot be reused after a call to this method. | 657 * cannot be reused after a call to this method. |
| 658 */ | 658 */ |
| 659 Stream<T> takeWhile(bool test(T element)) { | 659 Stream<T> takeWhile(bool test(T element)) { |
| 660 return new _TakeWhileStream(this, test); | 660 return new _TakeWhileStream(this, test); |
| 661 } | 661 } |
| 662 | 662 |
| (...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 953 } | 953 } |
| 954 index -= 1; | 954 index -= 1; |
| 955 }, | 955 }, |
| 956 onError: future._completeError, | 956 onError: future._completeError, |
| 957 onDone: () { | 957 onDone: () { |
| 958 future._completeError(new RangeError.value(index)); | 958 future._completeError(new RangeError.value(index)); |
| 959 }, | 959 }, |
| 960 cancelOnError: true); | 960 cancelOnError: true); |
| 961 return future; | 961 return future; |
| 962 } | 962 } |
| 963 | |
| 964 /** | |
| 965 * Creates a new stream with the same events as this stream. | |
| 966 * | |
| 967 * Whenever more than [timeLimit] passes between two events from this stream, | |
| 968 * the [onTimeout] function is called. | |
| 969 * | |
| 970 * The countdown doesn't start until the returned stream is listened to. | |
| 971 * The countdown is reset every time an event is forwarded from this stream, | |
| 972 * or when the stream is paused and resumed. | |
| 973 * | |
| 974 * If the [onTimeout] function accepts one argument, it is called with an | |
| 975 * [EventSink] that allows putting events into the returned stream. | |
| 976 * This `EventSink` is only valid during the call to `onTimeout`. | |
| 977 * | |
| 978 * If the `onTimeout` function accepts two arguments, it is called with both | |
|
floitsch
2013/11/29 13:43:48
As discussed. Let's not do this.
Lasse Reichstein Nielsen
2013/11/29 13:58:03
Done.
| |
| 979 * the `EventSink` and a function that allows canceling the input stream | |
| 980 * subscription. This will stop any further events from reaching the output | |
| 981 * stream. | |
| 982 * | |
| 983 * If `onTimeout` is omitted, a timeout will just put a [TimeoutException] | |
| 984 * into the error channel of the returned stream. | |
| 985 */ | |
| 986 Stream timeout(Duration timeLimit, [Function onTimeout]) { | |
|
floitsch
2013/11/29 13:43:48
make it named.
Lasse Reichstein Nielsen
2013/11/29 13:58:03
Done.
| |
| 987 StreamSubscription<T> subscription; | |
| 988 _StreamController controller; | |
| 989 Timer timer; | |
| 990 Zone outerZone = Zone.current; | |
| 991 Function timeout; | |
| 992 if (onTimeout == null) { | |
| 993 timeout = () { | |
| 994 controller.addError(new TimeoutException(/*"No stream event",*/ | |
| 995 timeLimit)); | |
| 996 }; | |
| 997 } else { | |
| 998 Zone zone = outerZone.fork(); | |
|
floitsch
2013/11/29 13:43:48
no need to fork.
Lasse Reichstein Nielsen
2013/11/29 13:58:03
Done, by not doing!
| |
| 999 if (onTimeout is ZoneBinaryCallback) { | |
| 1000 onTimeout = zone.registerBinaryCallback(onTimeout); | |
| 1001 _ControllerEventSinkWrapper wrapper = | |
| 1002 new _ControllerEventSinkWrapper(null); | |
| 1003 timeout = () { | |
| 1004 wrapper._sink = controller; // Only valid during call. | |
| 1005 zone.runBinaryGuarded(onTimeout, wrapper, subscription.cancel); | |
| 1006 wrapper._sink = null; | |
| 1007 }; | |
| 1008 } else if (onTimeout is ZoneUnaryCallback) { | |
| 1009 onTimeout = zone.registerUnaryCallback(onTimeout); | |
| 1010 _ControllerEventSinkWrapper wrapper = | |
| 1011 new _ControllerEventSinkWrapper(null); | |
| 1012 timeout = () { | |
| 1013 wrapper._sink = controller; // Only valid during call. | |
| 1014 zone.runUnaryGuarded(onTimeout, wrapper); | |
| 1015 wrapper._sink = null; | |
| 1016 }; | |
| 1017 } else { | |
| 1018 onTimeout = zone.registerCallback(onTimeout); | |
|
floitsch
2013/11/29 13:43:48
I would put that up to the onTimeout == null.
Lasse Reichstein Nielsen
2013/11/29 13:58:03
What?
If onTimeout is null, why call registerCallb
| |
| 1019 timeout = () { zone.runGuarded(onTimeout); }; | |
| 1020 } | |
| 1021 } | |
| 1022 | |
| 1023 void onData(T event) { | |
| 1024 timer.cancel(); | |
|
floitsch
2013/11/29 13:43:48
This will be expensive.
For a first implementation
Lasse Reichstein Nielsen
2013/11/29 13:58:03
How will that work?
Have the initial timer run to
floitsch
2013/11/29 15:03:49
yes. something like that.
| |
| 1025 controller.add(event); | |
| 1026 timer = outerZone.createTimer(timeLimit, timeout); | |
| 1027 } | |
| 1028 void onError(error, StackTrace stackTrace) { | |
| 1029 timer.cancel(); | |
| 1030 controller.addError(error, stackTrace); | |
| 1031 timer = outerZone.createTimer(timeLimit, timeout); | |
| 1032 } | |
| 1033 void onDone() { | |
| 1034 timer.cancel(); | |
| 1035 controller.close(); | |
| 1036 } | |
| 1037 controller = new _SyncStreamController( | |
| 1038 () { | |
| 1039 subscription = this.listen(onData, onError: onError, onDone: onDone); | |
| 1040 timer = outerZone.createTimer(timeLimit, timeout); | |
| 1041 }, | |
| 1042 () { | |
| 1043 timer.cancel(); | |
| 1044 subscription.pause(); | |
| 1045 }, | |
| 1046 () { | |
| 1047 subscription.resume(); | |
| 1048 timer = outerZone.createTimer(timeLimit, timeout); | |
| 1049 }, | |
| 1050 () { | |
| 1051 timer.cancel(); | |
| 1052 Future result = subscription.cancel(); | |
| 1053 subscription = null; | |
| 1054 return result; | |
| 1055 }); | |
| 1056 return controller.stream; | |
| 1057 } | |
| 963 } | 1058 } |
| 964 | 1059 |
| 965 /** | 1060 /** |
| 966 * A control object for the subscription on a [Stream]. | 1061 * A control object for the subscription on a [Stream]. |
| 967 * | 1062 * |
| 968 * When you subscribe on a [Stream] using [Stream.listen], | 1063 * When you subscribe on a [Stream] using [Stream.listen], |
| 969 * a [StreamSubscription] object is returned. This object | 1064 * a [StreamSubscription] object is returned. This object |
| 970 * is used to later unsubscribe again, or to temporarily pause | 1065 * is used to later unsubscribe again, or to temporarily pause |
| 971 * the stream's events. | 1066 * the stream's events. |
| 972 */ | 1067 */ |
| (...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1275 * | 1370 * |
| 1276 * If you need to stop listening for values before the stream iterator is | 1371 * If you need to stop listening for values before the stream iterator is |
| 1277 * automatically closed, you must call [cancel] to ensure that the stream | 1372 * automatically closed, you must call [cancel] to ensure that the stream |
| 1278 * is properly closed. | 1373 * is properly closed. |
| 1279 * | 1374 * |
| 1280 * Returns a future if the cancel-operation is not completed synchronously. | 1375 * Returns a future if the cancel-operation is not completed synchronously. |
| 1281 * Otherwise returns `null`. | 1376 * Otherwise returns `null`. |
| 1282 */ | 1377 */ |
| 1283 Future cancel(); | 1378 Future cancel(); |
| 1284 } | 1379 } |
| 1380 | |
| 1381 | |
| 1382 /** | |
| 1383 * Wraps an [_EventSink] so it exposes only the [EventSink] interface. | |
|
floitsch
2013/11/29 13:43:48
Don't we already have something like this?
Lasse Reichstein Nielsen
2013/11/29 13:58:03
Not exactly, sadly. We have something that takes a
| |
| 1384 */ | |
| 1385 class _ControllerEventSinkWrapper<T> implements EventSink<T> { | |
| 1386 EventSink _sink; | |
| 1387 _ControllerEventSinkWrapper(this._sink); | |
| 1388 | |
| 1389 void add(T data) { _sink.add(data); } | |
| 1390 void addError(error, [StackTrace stackTrace]) { | |
| 1391 _sink.addError(error, stackTrace); | |
| 1392 } | |
| 1393 void close() { _sink.close(); } | |
| 1394 } | |
| OLD | NEW |