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 : import 'dart:convert';
7 :
8 : import 'package:async/async.dart';
9 :
10 : import '../stream_channel.dart';
11 : import 'transformer/typed.dart';
12 :
13 : /// A [StreamChannelTransformer] transforms the events being passed to and
14 : /// emitted by a [StreamChannel].
15 : ///
16 : /// This works on the same principle as [StreamTransformer] and
17 : /// [StreamSinkTransformer]. Each transformer defines a [bind] method that takes
18 : /// in the original [StreamChannel] and returns the transformed version.
19 : ///
20 : /// Transformers must be able to have [bind] called multiple times. If a
21 : /// subclass implements [bind] explicitly, it should be sure that the returned
22 : /// stream follows the second stream channel guarantee: closing the sink causes
23 : /// the stream to close before it emits any more events. This guarantee is
24 : /// invalidated when an asynchronous gap is added between the original stream's
25 : /// event dispatch and the returned stream's, for example by transforming it
26 : /// with a [StreamTransformer]. The guarantee can be easily preserved using [new
27 : /// StreamChannel.withCloseGuarantee].
28 : class StreamChannelTransformer<S, T> {
29 : /// The transformer to use on the channel's stream.
30 : final StreamTransformer<T, S> _streamTransformer;
31 :
32 : /// The transformer to use on the channel's sink.
33 : final StreamSinkTransformer<S, T> _sinkTransformer;
34 :
35 : /// Creates a wrapper that coerces the type of [transformer].
36 : ///
37 : /// This soundly converts a [StreamChannelTransformer] to a
38 : /// `StreamChannelTransformer<S, T>`, regardless of its original generic type,
39 : /// by asserting that the events emitted by the transformed channel's stream
40 : /// are instances of `T` whenever they're provided. If they're not, the stream
41 : /// throws a [CastError]. This also means that calls to [StreamSink.add] on
42 : /// the transformed channel's sink may throw a [CastError] if the argument
43 : /// type doesn't match the reified type of the sink.
44 : static StreamChannelTransformer<S, T> typed<S, T>(
45 : StreamChannelTransformer transformer) =>
46 0 : transformer is StreamChannelTransformer<S, T>
47 : ? transformer
48 0 : : new TypeSafeStreamChannelTransformer(transformer);
49 :
50 : /// Creates a [StreamChannelTransformer] from existing stream and sink
51 : /// transformers.
52 : const StreamChannelTransformer(
53 0 : this._streamTransformer, this._sinkTransformer);
54 :
55 : /// Creates a [StreamChannelTransformer] from a codec's encoder and decoder.
56 : ///
57 : /// All input to the inner channel's sink is encoded using [Codec.encoder],
58 : /// and all output from its stream is decoded using [Codec.decoder].
59 : StreamChannelTransformer.fromCodec(Codec<S, T> codec)
60 0 : : this(
61 0 : typedStreamTransformer(codec.decoder),
62 0 : StreamSinkTransformer.typed(
63 0 : new StreamSinkTransformer.fromStreamTransformer(
64 0 : codec.encoder)));
65 :
66 : /// Transforms the events sent to and emitted by [channel].
67 : ///
68 : /// Creates a new channel. When events are passed to the returned channel's
69 : /// sink, the transformer will transform them and pass the transformed
70 : /// versions to `channel.sink`. When events are emitted from the
71 : /// `channel.straem`, the transformer will transform them and pass the
72 : /// transformed versions to the returned channel's stream.
73 : StreamChannel<S> bind(StreamChannel<T> channel) =>
74 0 : new StreamChannel<S>.withCloseGuarantee(
75 0 : channel.stream.transform(_streamTransformer),
76 0 : _sinkTransformer.bind(channel.sink));
77 : }
|