| 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, 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |