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

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

Issue 11862008: Make Streams also cosider a thrown AsyncError a rethrow. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address reciew comments. Created 7 years, 11 months 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
« no previous file with comments | « no previous file | sdk/lib/async/stream_controller.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
103 * Create a new stream that converts each element of this stream 103 * Create a new stream that converts each element of this stream
104 * to a new value using the [convert] function. 104 * to a new value using the [convert] function.
105 */ 105 */
106 Stream mappedBy(convert(T event)) { 106 Stream mappedBy(convert(T event)) {
107 return this.transform(new MapStream<T, dynamic>(convert)); 107 return this.transform(new MapStream<T, dynamic>(convert));
108 } 108 }
109 109
110 /** 110 /**
111 * Create a wrapper Stream that intercepts some errors from this stream. 111 * Create a wrapper Stream that intercepts some errors from this stream.
112 * 112 *
113 * If the handler returns null, the error is considered handled. 113 * If this stream sends an error that matches [test], then it is intercepted
114 * Otherwise the returned [AsyncError] is passed to the subscribers 114 * by the [handle] function.
115 * of the stream. 115 *
116 * An [AsyncError] [:e:] is matched by a test function if [:test(e):] returns
117 * true. If [test] is omitted, every error is considered matching.
118 *
119 * If the error is intercepted, the [handle] function can decide what to do
120 * with it. It can throw if it wants to raise a new (or the same) error,
121 * or simply return to make the stream forget the error.
116 */ 122 */
117 Stream handleError(AsyncError handle(AsyncError error)) { 123 Stream<T> handleError(void handle(AsyncError error), { bool test(error) }) {
118 return this.transform(new HandleErrorStream<T>(handle)); 124 return this.transform(new HandleErrorStream<T>(handle, test));
119 } 125 }
120 126
121 /** 127 /**
122 * Create a new stream from this stream that converts each element 128 * Create a new stream from this stream that converts each element
123 * into zero or more events. 129 * into zero or more events.
124 * 130 *
125 * Each incoming event is converted to an [Iterable] of new events, 131 * Each incoming event is converted to an [Iterable] of new events,
126 * and each of these new events are then sent by the returned stream 132 * and each of these new events are then sent by the returned stream
127 * in order. 133 * in order.
128 */ 134 */
(...skipping 18 matching lines...) Expand all
147 } 153 }
148 154
149 155
150 /** Reduces a sequence of values by repeatedly applying [combine]. */ 156 /** Reduces a sequence of values by repeatedly applying [combine]. */
151 Future reduce(var initialValue, combine(var previous, T element)) { 157 Future reduce(var initialValue, combine(var previous, T element)) {
152 _FutureImpl result = new _FutureImpl(); 158 _FutureImpl result = new _FutureImpl();
153 var value = initialValue; 159 var value = initialValue;
154 StreamSubscription subscription; 160 StreamSubscription subscription;
155 subscription = this.listen( 161 subscription = this.listen(
156 (T element) { 162 (T element) {
157 try { 163 _runUserCode(
158 value = combine(value, element); 164 () => combine(value, element),
159 } catch (e, s) { 165 (result) { value = result; },
160 subscription.cancel(); 166 _cancelAndError(subscription, result)
161 result._setError(new AsyncError(e, s)); 167 );
162 }
163 }, 168 },
164 onError: (AsyncError e) { 169 onError: (AsyncError e) {
165 result._setError(e); 170 result._setError(e);
166 }, 171 },
167 onDone: () { 172 onDone: () {
168 result._setValue(value); 173 result._setValue(value);
169 }, 174 },
170 unsubscribeOnError: true); 175 unsubscribeOnError: true);
171 return result; 176 return result;
172 } 177 }
(...skipping 19 matching lines...) Expand all
192 * Check whether [match] occurs in the elements provided by this stream. 197 * Check whether [match] occurs in the elements provided by this stream.
193 * 198 *
194 * Completes the [Future] when the answer is known. 199 * Completes the [Future] when the answer is known.
195 * If this stream reports an error, the [Future] will report that error. 200 * If this stream reports an error, the [Future] will report that error.
196 */ 201 */
197 Future<bool> contains(T match) { 202 Future<bool> contains(T match) {
198 _FutureImpl<bool> future = new _FutureImpl<bool>(); 203 _FutureImpl<bool> future = new _FutureImpl<bool>();
199 StreamSubscription subscription; 204 StreamSubscription subscription;
200 subscription = this.listen( 205 subscription = this.listen(
201 (T element) { 206 (T element) {
202 if (element == match) { 207 _runUserCode(
203 subscription.cancel(); 208 () => match(element),
204 future._setValue(true); 209 (bool isMatch) {
205 } 210 if (isMatch) {
211 subscription.cancel();
212 future._setValue(element);
213 }
214 },
215 _cancelAndError(subscription, future)
216 );
206 }, 217 },
207 onError: future._setError, 218 onError: future._setError,
208 onDone: () { 219 onDone: () {
209 future._setValue(false); 220 future._setValue(false);
210 }, 221 },
211 unsubscribeOnError: true); 222 unsubscribeOnError: true);
212 return future; 223 return future;
213 } 224 }
214 225
215 /** 226 /**
216 * Check whether [test] accepts all elements provided by this stream. 227 * Check whether [test] accepts all elements provided by this stream.
217 * 228 *
218 * Completes the [Future] when the answer is known. 229 * Completes the [Future] when the answer is known.
219 * If this stream reports an error, the [Future] will report that error. 230 * If this stream reports an error, the [Future] will report that error.
220 */ 231 */
221 Future<bool> every(bool test(T element)) { 232 Future<bool> every(bool test(T element)) {
222 _FutureImpl<bool> future = new _FutureImpl<bool>(); 233 _FutureImpl<bool> future = new _FutureImpl<bool>();
223 StreamSubscription subscription; 234 StreamSubscription subscription;
224 subscription = this.listen( 235 subscription = this.listen(
225 (T element) { 236 (T element) {
226 if (!test(element)) { 237 _runUserCode(
227 subscription.cancel(); 238 () => test(element),
228 future._setValue(false); 239 (bool isMatch) {
229 } 240 if (!isMatch) {
241 subscription.cancel();
242 future._setValue(false);
243 }
244 },
245 _cancelAndError(subscription, future)
246 );
230 }, 247 },
231 onError: future._setError, 248 onError: future._setError,
232 onDone: () { 249 onDone: () {
233 future._setValue(true); 250 future._setValue(true);
234 }, 251 },
235 unsubscribeOnError: true); 252 unsubscribeOnError: true);
236 return future; 253 return future;
237 } 254 }
238 255
239 /** 256 /**
240 * Check whether [test] accepts any element provided by this stream. 257 * Check whether [test] accepts any element provided by this stream.
241 * 258 *
242 * Completes the [Future] when the answer is known. 259 * Completes the [Future] when the answer is known.
243 * If this stream reports an error, the [Future] will report that error. 260 * If this stream reports an error, the [Future] will report that error.
244 */ 261 */
245 Future<bool> any(bool test(T element)) { 262 Future<bool> any(bool test(T element)) {
246 _FutureImpl<bool> future = new _FutureImpl<bool>(); 263 _FutureImpl<bool> future = new _FutureImpl<bool>();
247 StreamSubscription subscription; 264 StreamSubscription subscription;
248 subscription = this.listen( 265 subscription = this.listen(
249 (T element) { 266 (T element) {
250 if (test(element)) { 267 _runUserCode(
251 subscription.cancel(); 268 () => test(element),
252 future._setValue(true); 269 (bool isMatch) {
253 } 270 if (isMatch) {
271 subscription.cancel();
272 future._setValue(true);
273 }
274 },
275 _cancelAndError(subscription, future)
276 );
254 }, 277 },
255 onError: future._setError, 278 onError: future._setError,
256 onDone: () { 279 onDone: () {
257 future._setValue(false); 280 future._setValue(false);
258 }, 281 },
259 unsubscribeOnError: true); 282 unsubscribeOnError: true);
260 return future; 283 return future;
261 } 284 }
262 285
263 286
(...skipping 23 matching lines...) Expand all
287 */ 310 */
288 Future<T> min([int compare(T a, T b)]) { 311 Future<T> min([int compare(T a, T b)]) {
289 if (compare == null) compare = Comparable.compare; 312 if (compare == null) compare = Comparable.compare;
290 _FutureImpl<T> future = new _FutureImpl<T>(); 313 _FutureImpl<T> future = new _FutureImpl<T>();
291 StreamSubscription subscription; 314 StreamSubscription subscription;
292 T min = null; 315 T min = null;
293 subscription = this.listen( 316 subscription = this.listen(
294 (T value) { 317 (T value) {
295 min = value; 318 min = value;
296 subscription.onData((T value) { 319 subscription.onData((T value) {
297 if (compare(min, value) > 0) min = value; 320 _runUserCode(
321 () => compare(min, value) > 0,
322 (bool foundSmaller) {
323 if (foundSmaller) {
324 min = value;
325 }
326 },
327 _cancelAndError(subscription, future)
328 );
298 }); 329 });
299 }, 330 },
300 onError: future._setError, 331 onError: future._setError,
301 onDone: () { 332 onDone: () {
302 future._setValue(min); 333 future._setValue(min);
303 }, 334 },
304 unsubscribeOnError: true 335 unsubscribeOnError: true
305 ); 336 );
306 return future; 337 return future;
307 } 338 }
(...skipping 10 matching lines...) Expand all
318 */ 349 */
319 Future<T> max([int compare(T a, T b)]) { 350 Future<T> max([int compare(T a, T b)]) {
320 if (compare == null) compare = Comparable.compare; 351 if (compare == null) compare = Comparable.compare;
321 _FutureImpl<T> future = new _FutureImpl<T>(); 352 _FutureImpl<T> future = new _FutureImpl<T>();
322 StreamSubscription subscription; 353 StreamSubscription subscription;
323 T max = null; 354 T max = null;
324 subscription = this.listen( 355 subscription = this.listen(
325 (T value) { 356 (T value) {
326 max = value; 357 max = value;
327 subscription.onData((T value) { 358 subscription.onData((T value) {
328 if (compare(max, value) < 0) max = value; 359 _runUserCode(
360 () => compare(max, value) < 0,
361 (bool foundGreater) {
362 if (foundGreater) {
363 max = value;
364 }
365 },
366 _cancelAndError(subscription, future)
367 );
329 }); 368 });
330 }, 369 },
331 onError: future._setError, 370 onError: future._setError,
332 onDone: () { 371 onDone: () {
333 future._setValue(max); 372 future._setValue(max);
334 }, 373 },
335 unsubscribeOnError: true 374 unsubscribeOnError: true
336 ); 375 );
337 return future; 376 return future;
338 } 377 }
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after
539 * 578 *
540 * If an error occurs, or if this stream ends without finding a match and 579 * If an error occurs, or if this stream ends without finding a match and
541 * with no [defaultValue] function provided, the future will receive an 580 * with no [defaultValue] function provided, the future will receive an
542 * error. 581 * error.
543 */ 582 */
544 Future<T> firstMatching(bool test(T value), {T defaultValue()}) { 583 Future<T> firstMatching(bool test(T value), {T defaultValue()}) {
545 _FutureImpl<T> future = new _FutureImpl<T>(); 584 _FutureImpl<T> future = new _FutureImpl<T>();
546 StreamSubscription subscription; 585 StreamSubscription subscription;
547 subscription = this.listen( 586 subscription = this.listen(
548 (T value) { 587 (T value) {
549 bool matches; 588 _runUserCode(
550 try { 589 () => test(value),
551 matches = (true == test(value)); 590 (bool isMatch) {
552 } catch (e, s) { 591 if (isMatch) {
553 future._setError(new AsyncError(e, s)); 592 subscription.cancel();
554 subscription.cancel(); 593 future._setValue(value);
555 return; 594 }
556 } 595 },
557 if (matches) { 596 _cancelAndError(subscription, future)
558 future._setValue(value); 597 );
559 subscription.cancel();
560 }
561 }, 598 },
562 onError: future._setError, 599 onError: future._setError,
563 onDone: () { 600 onDone: () {
564 if (defaultValue != null) { 601 if (defaultValue != null) {
565 T value; 602 _runUserCode(defaultValue, future._setValue, future._setError);
566 try {
567 value = defaultValue();
568 } catch (e, s) {
569 future._setError(new AsyncError(e, s));
570 return;
571 }
572 future._setValue(value);
573 return; 603 return;
574 } 604 }
575 future._setError( 605 future._setError(
576 new AsyncError(new StateError("firstMatch ended without match"))); 606 new AsyncError(new StateError("firstMatch ended without match")));
577 }, 607 },
578 unsubscribeOnError: true); 608 unsubscribeOnError: true);
579 return future; 609 return future;
580 } 610 }
581 611
582 /** 612 /**
583 * Finds the last element in this stream matching [test]. 613 * Finds the last element in this stream matching [test].
584 * 614 *
585 * As [firstMatching], except that the last matching element is found. 615 * As [firstMatching], except that the last matching element is found.
586 * That means that the result cannot be provided before this stream 616 * That means that the result cannot be provided before this stream
587 * is done. 617 * is done.
588 */ 618 */
589 Future<T> lastMatching(bool test(T value), {T defaultValue()}) { 619 Future<T> lastMatching(bool test(T value), {T defaultValue()}) {
590 _FutureImpl<T> future = new _FutureImpl<T>(); 620 _FutureImpl<T> future = new _FutureImpl<T>();
591 T result = null; 621 T result = null;
592 bool foundResult = false; 622 bool foundResult = false;
593 StreamSubscription subscription; 623 StreamSubscription subscription;
594 subscription = this.listen( 624 subscription = this.listen(
595 (T value) { 625 (T value) {
596 bool matches; 626 _runUserCode(
597 try { 627 () => true == test(value),
598 matches = (true == test(value)); 628 (bool isMatch) {
599 } catch (e, s) { 629 if (isMatch) {
600 future._setError(new AsyncError(e, s)); 630 foundResult = true;
601 subscription.cancel(); 631 result = value;
602 return; 632 }
603 } 633 },
604 if (matches) { 634 _cancelAndError(subscription, future)
605 foundResult = true; 635 );
606 result = value;
607 }
608 }, 636 },
609 onError: future._setError, 637 onError: future._setError,
610 onDone: () { 638 onDone: () {
611 if (foundResult) { 639 if (foundResult) {
612 future._setValue(result); 640 future._setValue(result);
613 return; 641 return;
614 } 642 }
615 if (defaultValue != null) { 643 if (defaultValue != null) {
616 T value; 644 _runUserCode(defaultValue, future._setValue, future._setError);
617 try {
618 value = defaultValue();
619 } catch (e, s) {
620 future._setError(new AsyncError(e, s));
621 return;
622 }
623 future._setValue(value);
624 return; 645 return;
625 } 646 }
626 future._setError( 647 future._setError(
627 new AsyncError(new StateError("lastMatch ended without match"))); 648 new AsyncError(new StateError("lastMatch ended without match")));
628 }, 649 },
629 unsubscribeOnError: true); 650 unsubscribeOnError: true);
630 return future; 651 return future;
631 } 652 }
632 653
633 /** 654 /**
634 * Finds the single element in this stream matching [test]. 655 * Finds the single element in this stream matching [test].
635 * 656 *
636 * Like [lastMatch], except that it is an error if more than one 657 * Like [lastMatch], except that it is an error if more than one
637 * matching element occurs in the stream. 658 * matching element occurs in the stream.
638 */ 659 */
639 Future<T> singleMatching(bool test(T value)) { 660 Future<T> singleMatching(bool test(T value)) {
640 _FutureImpl<T> future = new _FutureImpl<T>(); 661 _FutureImpl<T> future = new _FutureImpl<T>();
641 T result = null; 662 T result = null;
642 bool foundResult = false; 663 bool foundResult = false;
643 StreamSubscription subscription; 664 StreamSubscription subscription;
644 subscription = this.listen( 665 subscription = this.listen(
645 (T value) { 666 (T value) {
646 bool matches; 667 _runUserCode(
647 try { 668 () => true == test(value),
648 matches = (true == test(value)); 669 (bool isMatch) {
649 } catch (e, s) { 670 if (isMatch) {
650 future._setError(new AsyncError(e, s)); 671 if (foundResult) {
651 subscription.cancel(); 672 subscription.cancel();
652 return; 673 future._setError(new AsyncError(
653 } 674 new StateError('Multiple matches for "single"')));
654 if (matches) { 675 return;
655 if (foundResult) { 676 }
656 future._setError(new AsyncError( 677 foundResult = true;
657 new StateError('Multiple matches for "single"'))); 678 result = value;
658 subscription.cancel(); 679 }
659 return; 680 },
660 } 681 _cancelAndError(subscription, future)
661 foundResult = true; 682 );
662 result = value;
663 }
664 }, 683 },
665 onError: future._setError, 684 onError: future._setError,
666 onDone: () { 685 onDone: () {
667 if (foundResult) { 686 if (foundResult) {
668 future._setValue(result); 687 future._setValue(result);
669 return; 688 return;
670 } 689 }
671 future._setError( 690 future._setError(
672 new AsyncError(new StateError("single ended without match"))); 691 new AsyncError(new StateError("single ended without match")));
673 }, 692 },
674 unsubscribeOnError: true); 693 unsubscribeOnError: true);
675 return future; 694 return future;
676 } 695 }
677 696
678 /** 697 /**
679 * Returns the value of the [index]th data event of this stream. 698 * Returns the value of the [index]th data event of this stream.
680 * 699 *
681 * If an error event occurs, the future will end with this error. 700 * If an error event occurs, the future will end with this error.
682 * 701 *
683 * If this stream provides fewer than [index] elements before closing, 702 * If this stream provides fewer than [index] elements before closing,
684 * an error is reported. 703 * an error is reported.
685 */ 704 */
686 Future<T> elementAt(int index) { 705 Future<T> elementAt(int index) {
706 if (index is! int || index < 0) throw new ArgumentError(index);
687 _FutureImpl<T> future = new _FutureImpl(); 707 _FutureImpl<T> future = new _FutureImpl();
688 StreamSubscription subscription; 708 StreamSubscription subscription;
689 subscription = this.listen( 709 subscription = this.listen(
690 (T value) { 710 (T value) {
691 if (index == 0) { 711 if (index == 0) {
692 future._setValue(value); 712 future._setValue(value);
693 subscription.cancel(); 713 subscription.cancel();
694 return; 714 return;
695 } 715 }
696 index -= 1; 716 index -= 1;
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
852 sink.signalError(error); 872 sink.signalError(error);
853 } 873 }
854 874
855 /** 875 /**
856 * Handle an incoming done event. 876 * Handle an incoming done event.
857 */ 877 */
858 void handleDone(StreamSink<T> sink) { 878 void handleDone(StreamSink<T> sink) {
859 sink.close(); 879 sink.close();
860 } 880 }
861 } 881 }
OLDNEW
« no previous file with comments | « no previous file | sdk/lib/async/stream_controller.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698