Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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, evert error is considered mathcing. | |
|
floitsch
2013/01/11 13:23:33
every ... matching
Lasse Reichstein Nielsen
2013/01/14 08:33:30
Done.
| |
| 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 20 matching lines...) Expand all Loading... | |
| 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 try { |
| 158 value = combine(value, element); | 164 value = combine(value, element); |
| 165 } on AsyncError catch (e) { | |
| 166 subscription.cancel(); | |
| 167 result._setError(e); | |
| 159 } catch (e, s) { | 168 } catch (e, s) { |
| 160 subscription.cancel(); | 169 subscription.cancel(); |
| 161 result._setError(new AsyncError(e, s)); | 170 result._setError(new AsyncError(e, s)); |
| 162 } | 171 } |
| 163 }, | 172 }, |
| 164 onError: (AsyncError e) { | 173 onError: (AsyncError e) { |
| 165 result._setError(e); | 174 result._setError(e); |
| 166 }, | 175 }, |
| 167 onDone: () { | 176 onDone: () { |
| 168 result._setValue(value); | 177 result._setValue(value); |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 192 * Check whether [match] occurs in the elements provided by this stream. | 201 * Check whether [match] occurs in the elements provided by this stream. |
| 193 * | 202 * |
| 194 * Completes the [Future] when the answer is known. | 203 * Completes the [Future] when the answer is known. |
| 195 * If this stream reports an error, the [Future] will report that error. | 204 * If this stream reports an error, the [Future] will report that error. |
| 196 */ | 205 */ |
| 197 Future<bool> contains(T match) { | 206 Future<bool> contains(T match) { |
| 198 _FutureImpl<bool> future = new _FutureImpl<bool>(); | 207 _FutureImpl<bool> future = new _FutureImpl<bool>(); |
| 199 StreamSubscription subscription; | 208 StreamSubscription subscription; |
| 200 subscription = this.listen( | 209 subscription = this.listen( |
| 201 (T element) { | 210 (T element) { |
| 202 if (element == match) { | 211 bool matches; |
| 212 try { | |
| 213 matches = (element == match); | |
| 214 } on AsyncError catch (e) { | |
|
floitsch
2013/01/11 13:23:33
This is repeated too often...
runUserCode(userCode
Lasse Reichstein Nielsen
2013/01/14 08:33:30
Done.
It's not pretty, but it's a little smaller
| |
| 215 subscription.cancel(); | |
| 216 future._setError(e); | |
| 217 return; | |
| 218 } catch (e, s) { | |
| 219 subscription.cancel(); | |
| 220 future._setError(new AsyncError(e, s)); | |
| 221 return; | |
| 222 } | |
| 223 if (matches) { | |
| 203 subscription.cancel(); | 224 subscription.cancel(); |
| 204 future._setValue(true); | 225 future._setValue(true); |
| 205 } | 226 } |
| 206 }, | 227 }, |
| 207 onError: future._setError, | 228 onError: future._setError, |
| 208 onDone: () { | 229 onDone: () { |
| 209 future._setValue(false); | 230 future._setValue(false); |
| 210 }, | 231 }, |
| 211 unsubscribeOnError: true); | 232 unsubscribeOnError: true); |
| 212 return future; | 233 return future; |
| 213 } | 234 } |
| 214 | 235 |
| 215 /** | 236 /** |
| 216 * Check whether [test] accepts all elements provided by this stream. | 237 * Check whether [test] accepts all elements provided by this stream. |
| 217 * | 238 * |
| 218 * Completes the [Future] when the answer is known. | 239 * Completes the [Future] when the answer is known. |
| 219 * If this stream reports an error, the [Future] will report that error. | 240 * If this stream reports an error, the [Future] will report that error. |
| 220 */ | 241 */ |
| 221 Future<bool> every(bool test(T element)) { | 242 Future<bool> every(bool test(T element)) { |
| 222 _FutureImpl<bool> future = new _FutureImpl<bool>(); | 243 _FutureImpl<bool> future = new _FutureImpl<bool>(); |
| 223 StreamSubscription subscription; | 244 StreamSubscription subscription; |
| 224 subscription = this.listen( | 245 subscription = this.listen( |
| 225 (T element) { | 246 (T element) { |
| 226 if (!test(element)) { | 247 bool matches; |
| 248 try { | |
| 249 matches = test(element); | |
| 250 } on AsyncError catch (e) { | |
| 251 subscription.cancel(); | |
| 252 future._setError(e); | |
| 253 return; | |
| 254 } catch (e, s) { | |
| 255 subscription.cancel(); | |
| 256 future._setError(new AsyncError(e, s)); | |
| 257 return; | |
| 258 } | |
| 259 if (!matches) { | |
| 227 subscription.cancel(); | 260 subscription.cancel(); |
| 228 future._setValue(false); | 261 future._setValue(false); |
| 229 } | 262 } |
| 230 }, | 263 }, |
| 231 onError: future._setError, | 264 onError: future._setError, |
| 232 onDone: () { | 265 onDone: () { |
| 233 future._setValue(true); | 266 future._setValue(true); |
| 234 }, | 267 }, |
| 235 unsubscribeOnError: true); | 268 unsubscribeOnError: true); |
| 236 return future; | 269 return future; |
| 237 } | 270 } |
| 238 | 271 |
| 239 /** | 272 /** |
| 240 * Check whether [test] accepts any element provided by this stream. | 273 * Check whether [test] accepts any element provided by this stream. |
| 241 * | 274 * |
| 242 * Completes the [Future] when the answer is known. | 275 * Completes the [Future] when the answer is known. |
| 243 * If this stream reports an error, the [Future] will report that error. | 276 * If this stream reports an error, the [Future] will report that error. |
| 244 */ | 277 */ |
| 245 Future<bool> any(bool test(T element)) { | 278 Future<bool> any(bool test(T element)) { |
| 246 _FutureImpl<bool> future = new _FutureImpl<bool>(); | 279 _FutureImpl<bool> future = new _FutureImpl<bool>(); |
| 247 StreamSubscription subscription; | 280 StreamSubscription subscription; |
| 248 subscription = this.listen( | 281 subscription = this.listen( |
| 249 (T element) { | 282 (T element) { |
| 250 if (test(element)) { | 283 bool matches; |
| 284 try { | |
| 285 matches = test(element); | |
| 286 } on AsyncError catch (e) { | |
| 287 subscription.cancel(); | |
| 288 future._setError(e); | |
| 289 return; | |
| 290 } catch (e, s) { | |
| 291 subscription.cancel(); | |
| 292 future._setError(new AsyncError(e, s)); | |
| 293 return; | |
| 294 } | |
| 295 if (matches) { | |
| 251 subscription.cancel(); | 296 subscription.cancel(); |
| 252 future._setValue(true); | 297 future._setValue(true); |
| 253 } | 298 } |
| 254 }, | 299 }, |
| 255 onError: future._setError, | 300 onError: future._setError, |
| 256 onDone: () { | 301 onDone: () { |
| 257 future._setValue(false); | 302 future._setValue(false); |
| 258 }, | 303 }, |
| 259 unsubscribeOnError: true); | 304 unsubscribeOnError: true); |
| 260 return future; | 305 return future; |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 287 */ | 332 */ |
| 288 Future<T> min([int compare(T a, T b)]) { | 333 Future<T> min([int compare(T a, T b)]) { |
| 289 if (compare == null) compare = Comparable.compare; | 334 if (compare == null) compare = Comparable.compare; |
| 290 _FutureImpl<T> future = new _FutureImpl<T>(); | 335 _FutureImpl<T> future = new _FutureImpl<T>(); |
| 291 StreamSubscription subscription; | 336 StreamSubscription subscription; |
| 292 T min = null; | 337 T min = null; |
| 293 subscription = this.listen( | 338 subscription = this.listen( |
| 294 (T value) { | 339 (T value) { |
| 295 min = value; | 340 min = value; |
| 296 subscription.onData((T value) { | 341 subscription.onData((T value) { |
| 297 if (compare(min, value) > 0) min = value; | 342 bool foundSmaller; |
| 343 try { | |
| 344 foundSmaller = (compare(min, value) > 0); | |
| 345 } on AsyncError catch (e) { | |
| 346 subscription.cancel(); | |
| 347 future._setError(e); | |
| 348 return; | |
| 349 } catch (e, s) { | |
| 350 subscription.cancel(); | |
| 351 future._setError(new AsyncError(e, s)); | |
| 352 return; | |
| 353 } | |
| 354 if (foundSmaller) min = value; | |
| 298 }); | 355 }); |
| 299 }, | 356 }, |
| 300 onError: future._setError, | 357 onError: future._setError, |
| 301 onDone: () { | 358 onDone: () { |
| 302 future._setValue(min); | 359 future._setValue(min); |
| 303 }, | 360 }, |
| 304 unsubscribeOnError: true | 361 unsubscribeOnError: true |
| 305 ); | 362 ); |
| 306 return future; | 363 return future; |
| 307 } | 364 } |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 318 */ | 375 */ |
| 319 Future<T> max([int compare(T a, T b)]) { | 376 Future<T> max([int compare(T a, T b)]) { |
| 320 if (compare == null) compare = Comparable.compare; | 377 if (compare == null) compare = Comparable.compare; |
| 321 _FutureImpl<T> future = new _FutureImpl<T>(); | 378 _FutureImpl<T> future = new _FutureImpl<T>(); |
| 322 StreamSubscription subscription; | 379 StreamSubscription subscription; |
| 323 T max = null; | 380 T max = null; |
| 324 subscription = this.listen( | 381 subscription = this.listen( |
| 325 (T value) { | 382 (T value) { |
| 326 max = value; | 383 max = value; |
| 327 subscription.onData((T value) { | 384 subscription.onData((T value) { |
| 328 if (compare(max, value) < 0) max = value; | 385 bool foundGreater; |
| 386 try { | |
| 387 foundGreater = (compare(min, value) < 0); | |
| 388 } on AsyncError catch (e) { | |
| 389 subscription.cancel(); | |
| 390 future._setError(e); | |
| 391 return; | |
| 392 } catch (e, s) { | |
| 393 subscription.cancel(); | |
| 394 future._setError(new AsyncError(e, s)); | |
| 395 return; | |
| 396 } | |
| 397 if (foundGreater) min = value; | |
| 329 }); | 398 }); |
| 330 }, | 399 }, |
| 331 onError: future._setError, | 400 onError: future._setError, |
| 332 onDone: () { | 401 onDone: () { |
| 333 future._setValue(max); | 402 future._setValue(max); |
| 334 }, | 403 }, |
| 335 unsubscribeOnError: true | 404 unsubscribeOnError: true |
| 336 ); | 405 ); |
| 337 return future; | 406 return future; |
| 338 } | 407 } |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 542 * error. | 611 * error. |
| 543 */ | 612 */ |
| 544 Future<T> firstMatching(bool test(T value), {T defaultValue()}) { | 613 Future<T> firstMatching(bool test(T value), {T defaultValue()}) { |
| 545 _FutureImpl<T> future = new _FutureImpl<T>(); | 614 _FutureImpl<T> future = new _FutureImpl<T>(); |
| 546 StreamSubscription subscription; | 615 StreamSubscription subscription; |
| 547 subscription = this.listen( | 616 subscription = this.listen( |
| 548 (T value) { | 617 (T value) { |
| 549 bool matches; | 618 bool matches; |
| 550 try { | 619 try { |
| 551 matches = (true == test(value)); | 620 matches = (true == test(value)); |
| 621 } on AsyncError catch (e) { | |
| 622 subscription.cancel(); | |
| 623 future._setError(e); | |
| 624 return; | |
| 552 } catch (e, s) { | 625 } catch (e, s) { |
| 626 subscription.cancel(); | |
| 553 future._setError(new AsyncError(e, s)); | 627 future._setError(new AsyncError(e, s)); |
| 554 subscription.cancel(); | |
| 555 return; | 628 return; |
| 556 } | 629 } |
| 557 if (matches) { | 630 if (matches) { |
| 631 subscription.cancel(); | |
| 558 future._setValue(value); | 632 future._setValue(value); |
| 559 subscription.cancel(); | |
| 560 } | 633 } |
| 561 }, | 634 }, |
| 562 onError: future._setError, | 635 onError: future._setError, |
| 563 onDone: () { | 636 onDone: () { |
| 564 if (defaultValue != null) { | 637 if (defaultValue != null) { |
| 565 T value; | 638 T value; |
| 566 try { | 639 try { |
| 567 value = defaultValue(); | 640 value = defaultValue(); |
| 641 } on AsyncError catch (e) { | |
| 642 future._setError(e); | |
| 643 return; | |
| 568 } catch (e, s) { | 644 } catch (e, s) { |
| 569 future._setError(new AsyncError(e, s)); | 645 future._setError(new AsyncError(e, s)); |
| 570 return; | 646 return; |
| 571 } | 647 } |
| 572 future._setValue(value); | 648 future._setValue(value); |
| 573 return; | 649 return; |
| 574 } | 650 } |
| 575 future._setError( | 651 future._setError( |
| 576 new AsyncError(new StateError("firstMatch ended without match"))); | 652 new AsyncError(new StateError("firstMatch ended without match"))); |
| 577 }, | 653 }, |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 589 Future<T> lastMatching(bool test(T value), {T defaultValue()}) { | 665 Future<T> lastMatching(bool test(T value), {T defaultValue()}) { |
| 590 _FutureImpl<T> future = new _FutureImpl<T>(); | 666 _FutureImpl<T> future = new _FutureImpl<T>(); |
| 591 T result = null; | 667 T result = null; |
| 592 bool foundResult = false; | 668 bool foundResult = false; |
| 593 StreamSubscription subscription; | 669 StreamSubscription subscription; |
| 594 subscription = this.listen( | 670 subscription = this.listen( |
| 595 (T value) { | 671 (T value) { |
| 596 bool matches; | 672 bool matches; |
| 597 try { | 673 try { |
| 598 matches = (true == test(value)); | 674 matches = (true == test(value)); |
| 675 } on AsyncError catch (e) { | |
| 676 subscription.cancel(); | |
| 677 future._setError(e); | |
| 678 return; | |
| 599 } catch (e, s) { | 679 } catch (e, s) { |
| 680 subscription.cancel(); | |
| 600 future._setError(new AsyncError(e, s)); | 681 future._setError(new AsyncError(e, s)); |
| 601 subscription.cancel(); | |
| 602 return; | 682 return; |
| 603 } | 683 } |
| 604 if (matches) { | 684 if (matches) { |
| 605 foundResult = true; | 685 foundResult = true; |
| 606 result = value; | 686 result = value; |
| 607 } | 687 } |
| 608 }, | 688 }, |
| 609 onError: future._setError, | 689 onError: future._setError, |
| 610 onDone: () { | 690 onDone: () { |
| 611 if (foundResult) { | 691 if (foundResult) { |
| 612 future._setValue(result); | 692 future._setValue(result); |
| 613 return; | 693 return; |
| 614 } | 694 } |
| 615 if (defaultValue != null) { | 695 if (defaultValue != null) { |
| 616 T value; | 696 T value; |
| 617 try { | 697 try { |
| 618 value = defaultValue(); | 698 value = defaultValue(); |
| 699 } on AsyncError catch (e) { | |
| 700 future._setError(e); | |
| 701 return; | |
| 619 } catch (e, s) { | 702 } catch (e, s) { |
| 620 future._setError(new AsyncError(e, s)); | 703 future._setError(new AsyncError(e, s)); |
| 621 return; | 704 return; |
| 622 } | 705 } |
| 623 future._setValue(value); | 706 future._setValue(value); |
| 624 return; | 707 return; |
| 625 } | 708 } |
| 626 future._setError( | 709 future._setError( |
| 627 new AsyncError(new StateError("lastMatch ended without match"))); | 710 new AsyncError(new StateError("lastMatch ended without match"))); |
| 628 }, | 711 }, |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 639 Future<T> singleMatching(bool test(T value)) { | 722 Future<T> singleMatching(bool test(T value)) { |
| 640 _FutureImpl<T> future = new _FutureImpl<T>(); | 723 _FutureImpl<T> future = new _FutureImpl<T>(); |
| 641 T result = null; | 724 T result = null; |
| 642 bool foundResult = false; | 725 bool foundResult = false; |
| 643 StreamSubscription subscription; | 726 StreamSubscription subscription; |
| 644 subscription = this.listen( | 727 subscription = this.listen( |
| 645 (T value) { | 728 (T value) { |
| 646 bool matches; | 729 bool matches; |
| 647 try { | 730 try { |
| 648 matches = (true == test(value)); | 731 matches = (true == test(value)); |
| 732 } on AsyncError catch (e) { | |
| 733 subscription.cancel(); | |
| 734 future._setError(e); | |
| 735 return; | |
| 649 } catch (e, s) { | 736 } catch (e, s) { |
| 737 subscription.cancel(); | |
| 650 future._setError(new AsyncError(e, s)); | 738 future._setError(new AsyncError(e, s)); |
| 651 subscription.cancel(); | |
| 652 return; | 739 return; |
| 653 } | 740 } |
| 654 if (matches) { | 741 if (matches) { |
| 655 if (foundResult) { | 742 if (foundResult) { |
| 743 subscription.cancel(); | |
| 656 future._setError(new AsyncError( | 744 future._setError(new AsyncError( |
| 657 new StateError('Multiple matches for "single"'))); | 745 new StateError('Multiple matches for "single"'))); |
| 658 subscription.cancel(); | |
| 659 return; | 746 return; |
| 660 } | 747 } |
| 661 foundResult = true; | 748 foundResult = true; |
| 662 result = value; | 749 result = value; |
| 663 } | 750 } |
| 664 }, | 751 }, |
| 665 onError: future._setError, | 752 onError: future._setError, |
| 666 onDone: () { | 753 onDone: () { |
| 667 if (foundResult) { | 754 if (foundResult) { |
| 668 future._setValue(result); | 755 future._setValue(result); |
| 669 return; | 756 return; |
| 670 } | 757 } |
| 671 future._setError( | 758 future._setError( |
| 672 new AsyncError(new StateError("single ended without match"))); | 759 new AsyncError(new StateError("single ended without match"))); |
| 673 }, | 760 }, |
| 674 unsubscribeOnError: true); | 761 unsubscribeOnError: true); |
| 675 return future; | 762 return future; |
| 676 } | 763 } |
| 677 | 764 |
| 678 /** | 765 /** |
| 679 * Returns the value of the [index]th data event of this stream. | 766 * Returns the value of the [index]th data event of this stream. |
| 680 * | 767 * |
| 681 * If an error event occurs, the future will end with this error. | 768 * If an error event occurs, the future will end with this error. |
| 682 * | 769 * |
| 683 * If this stream provides fewer than [index] elements before closing, | 770 * If this stream provides fewer than [index] elements before closing, |
| 684 * an error is reported. | 771 * an error is reported. |
| 685 */ | 772 */ |
| 686 Future<T> elementAt(int index) { | 773 Future<T> elementAt(int index) { |
| 774 if (0 > index) throw new ArgumentError(index); | |
|
floitsch
2013/01/11 13:23:33
No. If you don't want to check for int, don't chec
Lasse Reichstein Nielsen
2013/01/14 08:33:30
Done.
| |
| 687 _FutureImpl<T> future = new _FutureImpl(); | 775 _FutureImpl<T> future = new _FutureImpl(); |
| 688 StreamSubscription subscription; | 776 StreamSubscription subscription; |
| 689 subscription = this.listen( | 777 subscription = this.listen( |
| 690 (T value) { | 778 (T value) { |
| 691 if (index == 0) { | 779 if (index == 0) { |
| 692 future._setValue(value); | 780 future._setValue(value); |
| 693 subscription.cancel(); | 781 subscription.cancel(); |
| 694 return; | 782 return; |
| 695 } | 783 } |
| 696 index -= 1; | 784 index -= 1; |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 852 sink.signalError(error); | 940 sink.signalError(error); |
| 853 } | 941 } |
| 854 | 942 |
| 855 /** | 943 /** |
| 856 * Handle an incoming done event. | 944 * Handle an incoming done event. |
| 857 */ | 945 */ |
| 858 void handleDone(StreamSink<T> sink) { | 946 void handleDone(StreamSink<T> sink) { |
| 859 sink.close(); | 947 sink.close(); |
| 860 } | 948 } |
| 861 } | 949 } |
| OLD | NEW |