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

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: Address review comments 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
« no previous file with comments | « sdk/lib/async/stream_impl.dart ('k') | tests/lib/async/stream_controller_test.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 /** 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 * Common behavior of [StreamSubscription] classes.
93 *
94 * Stores and allows updating of the event handlers of a [StreamSubscription].
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.
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 250 matching lines...) Expand 10 before | Expand all | Expand 10 after
421 return null; 454 return null;
422 } 455 }
423 if (!isEqual) { 456 if (!isEqual) {
424 sink._sendData(inputEvent); 457 sink._sendData(inputEvent);
425 _previous = inputEvent; 458 _previous = inputEvent;
426 } 459 }
427 } 460 }
428 } 461 }
429 } 462 }
430 463
464 // Stream transformations and event transformations.
431 465
432 typedef void _TransformDataHandler<S, T>(S data, StreamSink<T> sink); 466 typedef void _TransformDataHandler<S, T>(S data, StreamSink<T> sink);
433 typedef void _TransformErrorHandler<T>(AsyncError data, StreamSink<T> sink); 467 typedef void _TransformErrorHandler<T>(AsyncError data, StreamSink<T> sink);
434 typedef void _TransformDoneHandler<T>(StreamSink<T> sink); 468 typedef void _TransformDoneHandler<T>(StreamSink<T> sink);
435 469
470 /** Default data handler forwards all data. */
471 void _defaultHandleData(var data, StreamSink sink) {
472 sink.add(data);
473 }
474
475 /** Default error handler forwards all errors. */
476 void _defaultHandleError(AsyncError error, StreamSink sink) {
477 sink.signalError(error);
478 }
479
480 /** Default done handler forwards done. */
481 void _defaultHandleDone(StreamSink sink) {
482 sink.close();
483 }
484
485
436 /** 486 /**
437 * A stream transformer that intercepts all events and can generate any event as 487 * A stream transformer that intercepts all events and can generate any event as
438 * output. 488 * output.
439 * 489 *
440 * Each incoming event on the source stream is passed to the corresponding 490 * Each incoming event on the source stream is passed to the corresponding
441 * provided event handler, along with a [StreamSink] linked to the output 491 * provided event handler, along with a [StreamSink] linked to the output
442 * Stream. 492 * Stream.
443 * The handler can then decide exactly which events to send to the output. 493 * The handler can then decide exactly which events to send to the output.
444 */ 494 */
445 class _StreamTransformerImpl<S, T> implements StreamTransformer<S, T> { 495 class _StreamTransformerImpl<S, T> implements StreamTransformer<S, T> {
(...skipping 14 matching lines...) Expand all
460 // Cache a Sink object to avoid creating a new one for each event. 510 // Cache a Sink object to avoid creating a new one for each event.
461 _sink = new _StreamImplSink(stream); 511 _sink = new _StreamImplSink(stream);
462 source.listen(_handleData, onError: _handleError, onDone: _handleDone); 512 source.listen(_handleData, onError: _handleError, onDone: _handleDone);
463 return stream; 513 return stream;
464 } 514 }
465 515
466 void _handleData(S data) { 516 void _handleData(S data) {
467 try { 517 try {
468 _onData(data, _sink); 518 _onData(data, _sink);
469 } catch (e, s) { 519 } catch (e, s) {
470 _stream._signalError(_asyncError(e, s)); 520 _sink.signalError(_asyncError(e, s));
471 } 521 }
472 } 522 }
473 523
474 void _handleError(AsyncError error) { 524 void _handleError(AsyncError error) {
475 try { 525 try {
476 _onError(error, _sink); 526 _onError(error, _sink);
477 } catch (e, s) { 527 } catch (e, s) {
478 _stream._signalError(_asyncError(e, s, error)); 528 _sink.signalError(_asyncError(e, s, error));
479 } 529 }
480 } 530 }
481 531
482 void _handleDone() { 532 void _handleDone() {
483 try { 533 try {
484 _onDone(_sink); 534 _onDone(_sink);
485 } catch (e, s) { 535 } catch (e, s) {
486 _stream._signalError(_asyncError(e, s)); 536 _sink.signalError(_asyncError(e, s));
487 } 537 }
488 } 538 }
489
490 /** Default data handler forwards all data. */
491 static void _defaultHandleData(var data, StreamSink sink) {
492 sink.add(data);
493 }
494 /** Default error handler forwards all errors. */
495 static void _defaultHandleError(AsyncError error, StreamSink sink) {
496 sink.signalError(error);
497 }
498 /** Default done handler forwards done. */
499 static void _defaultHandleDone(StreamSink sink) {
500 sink.close();
501 }
502 } 539 }
503 540
504 /** Creates a [StreamSink] from a [_StreamImpl]'s input methods. */ 541 /** Creates a [StreamSink] from a [_StreamImpl]'s input methods. */
505 class _StreamImplSink<T> implements StreamSink<T> { 542 class _StreamImplSink<T> implements StreamSink<T> {
506 _StreamImpl<T> _target; 543 _StreamImpl<T> _target;
507 _StreamImplSink(this._target); 544 _StreamImplSink(this._target);
508 void add(T data) { _target._add(data); } 545 void add(T data) { _target._add(data); }
509 void signalError(AsyncError error) { _target._signalError(error); } 546 void signalError(AsyncError error) { _target._signalError(error); }
510 void close() { _target._close(); } 547 void close() { _target._close(); }
511 } 548 }
549
550
551 /**
552 * A stream transformer that intercepts all events and can generate any event as
553 * output.
554 *
555 * Each incoming event on the source stream is passed to the corresponding
556 * provided event handler, along with a [StreamSink] linked to the output
557 * Stream.
558 * The handler can then decide exactly which events to send to the output.
559 */
560 class _StreamEventTransformerImpl<S, T>
561 implements StreamEventTransformer<S, T> {
562 final _TransformDataHandler<S, T> _handleData;
563 final _TransformErrorHandler<T> _handleError;
564 final _TransformDoneHandler<T> _handleDone;
565
566 _StreamEventTransformerImpl(void onData(S data, StreamSink<T> sink),
567 void onError(AsyncError data, StreamSink<T> sink),
568 void onDone(StreamSink<T> sink))
569 : this._handleData = (onData == null ? _defaultHandleData : onData),
570 this._handleError = (onError == null ? _defaultHandleError : onError),
571 this._handleDone = (onDone == null ? _defaultHandleDone : onDone);
572
573 void handleData(S data, StreamSink<T> sink) {
574 try {
575 _handleData(data, sink);
576 } catch (e, s) {
577 sink.signalError(_asyncError(e, s));
578 }
579 }
580
581 void handleError(AsyncError error, StreamSink<T> sink) {
582 try {
583 _handleError(error, sink);
584 } catch (e, s) {
585 sink.signalError(_asyncError(e, s, error));
586 }
587 }
588
589 void handleDone(StreamSink<T> sink) {
590 try {
591 _handleDone(sink);
592 } catch (e, s) {
593 sink.signalError(_asyncError(e, s));
594 }
595 }
596 }
OLDNEW
« no previous file with comments | « sdk/lib/async/stream_impl.dart ('k') | tests/lib/async/stream_controller_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698