Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(282)

Side by Side Diff: sdk/lib/async/stream.dart

Issue 96473003: Add Stream.timeout method. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Updated documentation. Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | tests/lib/async/stream_timeout_test.dart » ('j') | tests/lib/async/stream_timeout_test.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698