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

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

Issue 11953103: Add public-facing method and class that allows intercepting stream events. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Added more documentation Created 7 years, 10 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
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 /** Utility function to create an [AsyncError] if [error] isn't one already. */ 7 /** Utility function to create an [AsyncError] if [error] isn't one already. */
8 AsyncError _asyncError(Object error, Object stackTrace, [AsyncError cause]) { 8 AsyncError _asyncError(Object error, Object stackTrace, [AsyncError cause]) {
9 if (error is AsyncError) return error; 9 if (error is AsyncError) return error;
10 if (cause == null) return new AsyncError(error, stackTrace); 10 if (cause == null) return new AsyncError(error, stackTrace);
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
46 * 46 *
47 * This class is intended for internal use only. 47 * This class is intended for internal use only.
48 */ 48 */
49 abstract class _ForwardingStream<S, T> extends Stream<T> { 49 abstract class _ForwardingStream<S, T> extends Stream<T> {
50 final Stream<S> _source; 50 final Stream<S> _source;
51 51
52 _ForwardingStream(this._source); 52 _ForwardingStream(this._source);
53 53
54 bool get isBroadcast => _source.isBroadcast; 54 bool get isBroadcast => _source.isBroadcast;
55 55
56 bool asBroadcastStream() => _source.asBroadcastStream; 56 StreamSubscription<T> listen(void onData(T value),
57 57 { void onError(AsyncError error),
58 StreamSubscription listen(void onData(T value), 58 void onDone(),
59 { void onError(AsyncError error), 59 bool unsubscribeOnError }) {
60 void onDone(),
61 bool unsubscribeOnError }) {
62 if (onData == null) onData = _nullDataHandler; 60 if (onData == null) onData = _nullDataHandler;
63 if (onError == null) onError = _nullErrorHandler; 61 if (onError == null) onError = _nullErrorHandler;
64 if (onDone == null) onDone = _nullDoneHandler; 62 if (onDone == null) onDone = _nullDoneHandler;
65 unsubscribeOnError = identical(true, unsubscribeOnError); 63 unsubscribeOnError = identical(true, unsubscribeOnError);
66 StreamSubscription subscription = 64 return _createSubscription(onData, onError, onDone, unsubscribeOnError);
67 new _ForwardingStreamSubscription<S, T>( 65 }
68 this, onData, onError, onDone, unsubscribeOnError); 66
69 return subscription; 67 StreamSubscription<T> _createSubscription(void onData(T value),
68 void onError(AsyncError error),
69 void onDone(),
70 bool unsubscribeOnError) {
71 return new _ForwardingStreamSubscription<S, T>(
72 this, onData, onError, onDone, unsubscribeOnError);
70 } 73 }
71 74
72 // Override the following methods in subclasses to change the behavior. 75 // Override the following methods in subclasses to change the behavior.
73 76
74 void _handleData(S data, _StreamOutputSink<T> sink) { 77 void _handleData(S data, _StreamOutputSink<T> sink) {
75 var outputData = data; 78 var outputData = data;
76 sink._sendData(outputData); 79 sink._sendData(outputData);
77 } 80 }
78 81
79 void _handleError(AsyncError error, _StreamOutputSink<T> sink) { 82 void _handleError(AsyncError error, _StreamOutputSink<T> sink) {
80 sink._sendError(error); 83 sink._sendError(error);
81 } 84 }
82 85
83 void _handleDone(_StreamOutputSink<T> sink) { 86 void _handleDone(_StreamOutputSink<T> sink) {
84 sink._sendDone(); 87 sink._sendDone();
85 } 88 }
86 } 89 }
87 90
88 /** 91 /**
89 * Abstract superclass for subscriptions that forward to other subscriptions. 92 * Basic implemnetation of the handler features of a [StreamSubscription].
floitsch 2013/01/28 14:45:09 implementation. I don't understand the sentence.
Lasse Reichstein Nielsen 2013/01/29 08:42:54 Rewritten.
93 *
94 * Supports storing and updating of event handlers on a subscription.
90 */ 95 */
91 class _ForwardingStreamSubscription<S, T> 96 abstract class _BaseStreamSubscription<T> implements StreamSubscription<T> {
92 implements StreamSubscription<T>, _StreamOutputSink<T> {
93 final _ForwardingStream<S, T> _stream;
94 // TODO(ahe): Restore type when feature is implemented in dart2js 97 // TODO(ahe): Restore type when feature is implemented in dart2js
95 // checked mode. http://dartbug.com/7733 98 // checked mode. http://dartbug.com/7733
96 var /* _DataHandler<T> */ _onData; 99 var /* _DataHandler<T> */ _onData;
97 _ErrorHandler _onError; 100 _ErrorHandler _onError;
98 _DoneHandler _onDone; 101 _DoneHandler _onDone;
99 102
100 StreamSubscription<S> _subscription; 103 _BaseStreamSubscription(this._onData,
101 104 this._onError,
102 _ForwardingStreamSubscription(this._stream, 105 this._onDone) {
103 this._onData, 106 if (_onData == null) _onData = _nullDataHandler;
104 this._onError, 107 if (_onError == null) _onError = _nullErrorHandler;
105 this._onDone, 108 if (_onDone == null) _onDone = _nullDoneHandler;
106 bool unsubscribeOnError) {
107 _subscription =
108 _stream._source.listen(_handleData,
109 onError: _handleError,
110 onDone: _handleDone,
111 unsubscribeOnError: unsubscribeOnError);
112 } 109 }
113 110
114 // StreamSubscription interface. 111 // StreamSubscription interface.
115
116 void onData(void handleData(T event)) { 112 void onData(void handleData(T event)) {
117 if (handleData == null) handleData = _nullDataHandler; 113 if (handleData == null) handleData = _nullDataHandler;
118 _onData = handleData; 114 _onData = handleData;
119 } 115 }
120 116
121 void onError(void handleError(AsyncError error)) { 117 void onError(void handleError(AsyncError error)) {
122 if (handleError == null) handleError = _nullErrorHandler; 118 if (handleError == null) handleError = _nullErrorHandler;
123 _onError = handleError; 119 _onError = handleError;
124 } 120 }
125 121
126 void onDone(void handleDone()) { 122 void onDone(void handleDone()) {
127 if (handleDone == null) handleDone = _nullDoneHandler; 123 if (handleDone == null) handleDone = _nullDoneHandler;
128 _onDone = handleDone; 124 _onDone = handleDone;
129 } 125 }
130 126
127 void pause([Future resumeSignal]);
128
129 void resume();
130
131 void cancel();
132 }
133
134
135 /**
136 * Abstract superclass for subscriptions that forward to other subscriptions.
137 */
138 class _ForwardingStreamSubscription<S, T>
139 extends _BaseStreamSubscription<T> implements _StreamOutputSink<T> {
140 final _ForwardingStream<S, T> _stream;
141 final bool _unsubscribeOnError;
142
143 StreamSubscription<S> _subscription;
144
145 _ForwardingStreamSubscription(this._stream,
146 void onData(T data),
147 void onError(AsyncError error),
148 void onDone(),
149 this._unsubscribeOnError)
150 : super(onData, onError, onDone) {
151 // Don't unsubscribe on incoming error, only if we send an error forwards.
floitsch 2013/01/28 14:45:09 Took me way too long to understand the comment...
152 _subscription =
153 _stream._source.listen(_handleData,
154 onError: _handleError,
155 onDone: _handleDone);
156 }
157
158 // StreamSubscription interface.
159
131 void pause([Future resumeSignal]) { 160 void pause([Future resumeSignal]) {
132 if (_subscription == null) { 161 if (_subscription == null) {
133 throw new StateError("Subscription has been unsubscribed"); 162 throw new StateError("Subscription has been unsubscribed");
134 } 163 }
135 _subscription.pause(resumeSignal); 164 _subscription.pause(resumeSignal);
136 } 165 }
137 166
138 void resume() { 167 void resume() {
139 if (_subscription == null) { 168 if (_subscription == null) {
140 throw new StateError("Subscription has been unsubscribed"); 169 throw new StateError("Subscription has been unsubscribed");
(...skipping 10 matching lines...) Expand all
151 } 180 }
152 181
153 // _StreamOutputSink interface. Sends data to this subscription. 182 // _StreamOutputSink interface. Sends data to this subscription.
154 183
155 void _sendData(T data) { 184 void _sendData(T data) {
156 _onData(data); 185 _onData(data);
157 } 186 }
158 187
159 void _sendError(AsyncError error) { 188 void _sendError(AsyncError error) {
160 _onError(error); 189 _onError(error);
190 if (_unsubscribeOnError) {
191 _subscription.cancel();
192 _subscription = null;
193 }
161 } 194 }
162 195
163 void _sendDone() { 196 void _sendDone() {
164 // If the transformation sends a done signal, we stop the subscription. 197 // If the transformation sends a done signal, we stop the subscription.
165 if (_subscription != null) { 198 if (_subscription != null) {
166 _subscription.cancel(); 199 _subscription.cancel();
167 _subscription = null; 200 _subscription = null;
168 } 201 }
169 _onDone(); 202 _onDone();
170 } 203 }
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after
419 return null; 452 return null;
420 } 453 }
421 if (!isEqual) { 454 if (!isEqual) {
422 sink._sendData(inputEvent); 455 sink._sendData(inputEvent);
423 _previous = inputEvent; 456 _previous = inputEvent;
424 } 457 }
425 } 458 }
426 } 459 }
427 } 460 }
428 461
462 // Stream transformations and event transformations.
429 463
430 typedef void _TransformDataHandler<S, T>(S data, StreamSink<T> sink); 464 typedef void _TransformDataHandler<S, T>(S data, StreamSink<T> sink);
431 typedef void _TransformErrorHandler<T>(AsyncError data, StreamSink<T> sink); 465 typedef void _TransformErrorHandler<T>(AsyncError data, StreamSink<T> sink);
432 typedef void _TransformDoneHandler<T>(StreamSink<T> sink); 466 typedef void _TransformDoneHandler<T>(StreamSink<T> sink);
433 467
468 /** Default data handler forwards all data. */
469 void _defaultHandleData(var data, StreamSink sink) {
470 sink.add(data);
471 }
472
473 /** Default error handler forwards all errors. */
474 void _defaultHandleError(AsyncError error, StreamSink sink) {
475 sink.signalError(error);
476 }
477
478 /** Default done handler forwards done. */
479 void _defaultHandleDone(StreamSink sink) {
480 sink.close();
481 }
482
483
434 /** 484 /**
435 * A stream transformer that intercepts all events and can generate any event as 485 * A stream transformer that intercepts all events and can generate any event as
436 * output. 486 * output.
437 * 487 *
438 * Each incoming event on the source stream is passed to the corresponding 488 * Each incoming event on the source stream is passed to the corresponding
439 * provided event handler, along with a [StreamSink] linked to the output 489 * provided event handler, along with a [StreamSink] linked to the output
440 * Stream. 490 * Stream.
441 * The handler can then decide exactly which events to send to the output. 491 * The handler can then decide exactly which events to send to the output.
442 */ 492 */
443 class _StreamTransformerImpl<S, T> implements StreamTransformer<S, T> { 493 class _StreamTransformerImpl<S, T> implements StreamTransformer<S, T> {
(...skipping 14 matching lines...) Expand all
458 // Cache a Sink object to avoid creating a new one for each event. 508 // Cache a Sink object to avoid creating a new one for each event.
459 _sink = new _StreamImplSink(stream); 509 _sink = new _StreamImplSink(stream);
460 source.listen(_handleData, onError: _handleError, onDone: _handleDone); 510 source.listen(_handleData, onError: _handleError, onDone: _handleDone);
461 return stream; 511 return stream;
462 } 512 }
463 513
464 void _handleData(S data) { 514 void _handleData(S data) {
465 try { 515 try {
466 _onData(data, _sink); 516 _onData(data, _sink);
467 } catch (e, s) { 517 } catch (e, s) {
468 _stream._signalError(_asyncError(e, s)); 518 _sink.signalError(_asyncError(e, s));
469 } 519 }
470 } 520 }
471 521
472 void _handleError(AsyncError error) { 522 void _handleError(AsyncError error) {
473 try { 523 try {
474 _onError(error, _sink); 524 _onError(error, _sink);
475 } catch (e, s) { 525 } catch (e, s) {
476 _stream._signalError(_asyncError(e, s, error)); 526 _sink.signalError(_asyncError(e, s, error));
477 } 527 }
478 } 528 }
479 529
480 void _handleDone() { 530 void _handleDone() {
481 try { 531 try {
482 _onDone(_sink); 532 _onDone(_sink);
483 } catch (e, s) { 533 } catch (e, s) {
484 _stream._signalError(_asyncError(e, s)); 534 _sink.signalError(_asyncError(e, s));
485 } 535 }
486 } 536 }
487
488 /** Default data handler forwards all data. */
489 static void _defaultHandleData(var data, StreamSink sink) {
490 sink.add(data);
491 }
492 /** Default error handler forwards all errors. */
493 static void _defaultHandleError(AsyncError error, StreamSink sink) {
494 sink.signalError(error);
495 }
496 /** Default done handler forwards done. */
497 static void _defaultHandleDone(StreamSink sink) {
498 sink.close();
499 }
500 } 537 }
501 538
502 /** Creates a [StreamSink] from a [_StreamImpl]'s input methods. */ 539 /** Creates a [StreamSink] from a [_StreamImpl]'s input methods. */
503 class _StreamImplSink<T> implements StreamSink<T> { 540 class _StreamImplSink<T> implements StreamSink<T> {
504 _StreamImpl<T> _target; 541 _StreamImpl<T> _target;
505 _StreamImplSink(this._target); 542 _StreamImplSink(this._target);
506 void add(T data) { _target._add(data); } 543 void add(T data) { _target._add(data); }
507 void signalError(AsyncError error) { _target._signalError(error); } 544 void signalError(AsyncError error) { _target._signalError(error); }
508 void close() { _target._close(); } 545 void close() { _target._close(); }
509 } 546 }
510 547
511 548
549
550 /**
551 * A stream transformer that intercepts all events and can generate any event as
552 * output.
553 *
554 * Each incoming event on the source stream is passed to the corresponding
555 * provided event handler, along with a [StreamSink] linked to the output
556 * Stream.
557 * The handler can then decide exactly which events to send to the output.
558 */
559 class _StreamEventTransformerImpl<S, T>
560 implements StreamEventTransformer<S, T> {
561 final _TransformDataHandler<S, T> _handleData;
562 final _TransformErrorHandler<T> _handleError;
563 final _TransformDoneHandler<T> _handleDone;
564
565 _StreamEventTransformerImpl(void onData(S data, StreamSink<T> sink),
566 void onError(AsyncError data, StreamSink<T> sink),
567 void onDone(StreamSink<T> sink))
568 : this._handleData = (onData == null ? _defaultHandleData : onData),
569 this._handleError = (onError == null ? _defaultHandleError : onError),
570 this._handleDone = (onDone == null ? _defaultHandleDone : onDone);
571
572 void handleData(S data, StreamSink<T> sink) {
573 try {
574 _handleData(data, sink);
575 } catch (e, s) {
576 sink.signalError(_asyncError(e, s));
577 }
578 }
579
580 void handleError(AsyncError error, StreamSink<T> sink) {
581 try {
582 _handleError(error, sink);
583 } catch (e, s) {
584 sink.signalError(_asyncError(e, s, error));
585 }
586 }
587
588 void handleDone(StreamSink<T> sink) {
589 try {
590 _handleDone(sink);
591 } catch (e, s) {
592 sink.signalError(_asyncError(e, s));
593 }
594 }
595 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698