Line data Source code
1 : // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
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.
4 :
5 : import 'dart:async';
6 :
7 : import 'package:async/async.dart';
8 :
9 : import 'src/guarantee_channel.dart';
10 : import 'src/close_guarantee_channel.dart';
11 : import 'src/stream_channel_transformer.dart';
12 :
13 : export 'src/delegating_stream_channel.dart';
14 : export 'src/disconnector.dart';
15 : export 'src/isolate_channel.dart';
16 : export 'src/json_document_transformer.dart';
17 : export 'src/multi_channel.dart';
18 : export 'src/stream_channel_completer.dart';
19 : export 'src/stream_channel_controller.dart';
20 : export 'src/stream_channel_transformer.dart';
21 :
22 : /// An abstract class representing a two-way communication channel.
23 : ///
24 : /// Users should consider the [stream] emitting a "done" event to be the
25 : /// canonical indicator that the channel has closed. If they wish to close the
26 : /// channel, they should close the [sink]—canceling the stream subscription is
27 : /// not sufficient. Protocol errors may be emitted through the stream or through
28 : /// [Sink.done], depending on their underlying cause. Note that the sink may
29 : /// silently drop events if the channel closes before [Sink.close] is called.
30 : ///
31 : /// Implementations are strongly encouraged to mix in or extend
32 : /// [StreamChannelMixin] to get default implementations of the various instance
33 : /// methods. Adding new methods to this interface will not be considered a
34 : /// breaking change if implementations are also added to [StreamChannelMixin].
35 : ///
36 : /// Implementations must provide the following guarantees:
37 : ///
38 : /// * The stream is single-subscription, and must follow all the guarantees of
39 : /// single-subscription streams.
40 : ///
41 : /// * Closing the sink causes the stream to close before it emits any more
42 : /// events.
43 : ///
44 : /// * After the stream closes, the sink is automatically closed. If this
45 : /// happens, sink methods should silently drop their arguments until
46 : /// [Sink.close] is called.
47 : ///
48 : /// * If the stream closes before it has a listener, the sink should silently
49 : /// drop events if possible.
50 : ///
51 : /// * Canceling the stream's subscription has no effect on the sink. The channel
52 : /// must still be able to respond to the other endpoint closing the channel
53 : /// even after the subscription has been canceled.
54 : ///
55 : /// * The sink *either* forwards errors to the other endpoint *or* closes as
56 : /// soon as an error is added and forwards that error to the [Sink.done]
57 : /// future.
58 : ///
59 : /// These guarantees allow users to interact uniformly with all implementations,
60 : /// and ensure that either endpoint closing the stream produces consistent
61 : /// behavior.
62 : abstract class StreamChannel<T> {
63 : /// The single-subscription stream that emits values from the other endpoint.
64 : Stream<T> get stream;
65 :
66 : /// The sink for sending values to the other endpoint.
67 : StreamSink<T> get sink;
68 :
69 : /// Creates a new [StreamChannel] that communicates over [stream] and [sink].
70 : ///
71 : /// Note that this stream/sink pair must provide the guarantees listed in the
72 : /// [StreamChannel] documentation. If they don't do so natively, [new
73 : /// StreamChannel.withGuarantees] should be used instead.
74 : factory StreamChannel(Stream<T> stream, StreamSink<T> sink) =>
75 0 : new _StreamChannel<T>(stream, sink);
76 :
77 : /// Creates a new [StreamChannel] that communicates over [stream] and [sink].
78 : ///
79 : /// Unlike [new StreamChannel], this enforces the guarantees listed in the
80 : /// [StreamChannel] documentation. This makes it somewhat less efficient than
81 : /// just wrapping a stream and a sink directly, so [new StreamChannel] should
82 : /// be used when the guarantees are provided natively.
83 : ///
84 : /// If [allowSinkErrors] is `false`, errors are not allowed to be passed to
85 : /// [sink]. If any are, the connection will close and the error will be
86 : /// forwarded to [Sink.done].
87 : factory StreamChannel.withGuarantees(Stream<T> stream, StreamSink<T> sink,
88 : {bool allowSinkErrors: true}) =>
89 0 : new GuaranteeChannel(stream, sink, allowSinkErrors: allowSinkErrors);
90 :
91 : /// Creates a new [StreamChannel] that communicates over [stream] and [sink].
92 : ///
93 : /// This specifically enforces the second guarantee: closing the sink causes
94 : /// the stream to close before it emits any more events. This guarantee is
95 : /// invalidated when an asynchronous gap is added between the original
96 : /// stream's event dispatch and the returned stream's, for example by
97 : /// transforming it with a [StreamTransformer]. This is a lighter-weight way
98 : /// of preserving that guarantee in particular than
99 : /// [StreamChannel.withGuarantees].
100 : factory StreamChannel.withCloseGuarantee(
101 : Stream<T> stream, StreamSink<T> sink) =>
102 0 : new CloseGuaranteeChannel(stream, sink);
103 :
104 : /// Connects [this] to [other], so that any values emitted by either are sent
105 : /// directly to the other.
106 : void pipe(StreamChannel<T> other);
107 :
108 : /// Transforms [this] using [transformer].
109 : ///
110 : /// This is identical to calling `transformer.bind(channel)`.
111 : StreamChannel<S> transform<S>(StreamChannelTransformer<S, T> transformer);
112 :
113 : /// Transforms only the [stream] component of [this] using [transformer].
114 : StreamChannel<T> transformStream(StreamTransformer<T, T> transformer);
115 :
116 : /// Transforms only the [sink] component of [this] using [transformer].
117 : StreamChannel<T> transformSink(StreamSinkTransformer<T, T> transformer);
118 :
119 : /// Returns a copy of [this] with [stream] replaced by [change]'s return
120 : /// value.
121 : StreamChannel<T> changeStream(Stream<T> change(Stream<T> stream));
122 :
123 : /// Returns a copy of [this] with [sink] replaced by [change]'s return
124 : /// value.
125 : StreamChannel<T> changeSink(StreamSink<T> change(StreamSink<T> sink));
126 :
127 : /// Returns a copy of [this] with the generic type coerced to [S].
128 : ///
129 : /// If any events emitted by [stream] aren't of type [S], they're converted
130 : /// into [CastError] events. Similarly, if any events are added to [sync] that
131 : /// aren't of type [S], a [CastError] is thrown.
132 : StreamChannel<S> cast<S>();
133 : }
134 :
135 : /// An implementation of [StreamChannel] that simply takes a stream and a sink
136 : /// as parameters.
137 : ///
138 : /// This is distinct from [StreamChannel] so that it can use
139 : /// [StreamChannelMixin].
140 : class _StreamChannel<T> extends StreamChannelMixin<T> {
141 : final Stream<T> stream;
142 : final StreamSink<T> sink;
143 :
144 0 : _StreamChannel(this.stream, this.sink);
145 : }
146 :
147 : /// A mixin that implements the instance methods of [StreamChannel] in terms of
148 : /// [stream] and [sink].
149 : abstract class StreamChannelMixin<T> implements StreamChannel<T> {
150 : void pipe(StreamChannel<T> other) {
151 0 : stream.pipe(other.sink);
152 0 : other.stream.pipe(sink);
153 : }
154 :
155 : StreamChannel<S> transform<S>(StreamChannelTransformer<S, T> transformer) =>
156 0 : transformer.bind(this);
157 :
158 : StreamChannel<T> transformStream(StreamTransformer<T, T> transformer) =>
159 0 : changeStream(transformer.bind);
160 :
161 : StreamChannel<T> transformSink(StreamSinkTransformer<T, T> transformer) =>
162 0 : changeSink(transformer.bind);
163 :
164 : StreamChannel<T> changeStream(Stream<T> change(Stream<T> stream)) =>
165 0 : new StreamChannel.withCloseGuarantee(change(stream), sink);
166 :
167 : StreamChannel<T> changeSink(StreamSink<T> change(StreamSink<T> sink)) =>
168 0 : new StreamChannel.withCloseGuarantee(stream, change(sink));
169 :
170 0 : StreamChannel<S> cast<S>() => new StreamChannel(
171 0 : DelegatingStream.typed(stream), DelegatingStreamSink.typed(sink));
172 : }
|