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