Add type-coercion functions.

These match (and are based on) the coercion functions in
dart-lang/async.

R=sigmund@google.com

Review URL: https://codereview.chromium.org//1966853003 .
diff --git a/.analysis_options b/.analysis_options
new file mode 100644
index 0000000..a10d4c5
--- /dev/null
+++ b/.analysis_options
@@ -0,0 +1,2 @@
+analyzer:
+  strong-mode: true
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a5a7e46..6d86e48 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,11 @@
+## 1.4.0
+
+* Add `StreamChannel.cast()`, which soundly coerces the generic type of a
+  channel.
+
+* Add `StreamChannelTransformer.typed()`, which soundly coerces the generic type
+  of a transformer.
+
 ## 1.3.2
 
 * Fix all strong-mode errors and warnings.
diff --git a/lib/src/stream_channel_transformer.dart b/lib/src/stream_channel_transformer.dart
index ac98085..ca09ea1 100644
--- a/lib/src/stream_channel_transformer.dart
+++ b/lib/src/stream_channel_transformer.dart
@@ -8,6 +8,7 @@
 import 'package:async/async.dart';
 
 import '../stream_channel.dart';
+import 'transformer/typed.dart';
 
 /// A [StreamChannelTransformer] transforms the events being passed to and
 /// emitted by a [StreamChannel].
@@ -24,6 +25,21 @@
   /// The transformer to use on the channel's sink.
   final StreamSinkTransformer<S, T> _sinkTransformer;
 
+  /// Creates a wrapper that coerces the type of [transformer].
+  ///
+  /// This soundly converts a [StreamChannelTransformer] to a
+  /// `StreamChannelTransformer<S, T>`, regardless of its original generic type,
+  /// by asserting that the events emitted by the transformed channel's stream
+  /// are instances of `T` whenever they're provided. If they're not, the stream
+  /// throws a [CastError]. This also means that calls to [StreamSink.add] on
+  /// the transformed channel's sink may throw a [CastError] if the argument
+  /// type doesn't match the reified type of the sink.
+  static StreamChannelTransformer/*<S, T>*/ typed/*<S, T>*/(
+          StreamChannelTransformer transformer) =>
+      transformer is StreamChannelTransformer/*<S, T>*/
+          ? transformer
+          : new TypeSafeStreamChannelTransformer(transformer);
+
   /// Creates a [StreamChannelTransformer] from existing stream and sink
   /// transformers.
   const StreamChannelTransformer(
diff --git a/lib/src/transformer/typed.dart b/lib/src/transformer/typed.dart
new file mode 100644
index 0000000..f35e01c
--- /dev/null
+++ b/lib/src/transformer/typed.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../../stream_channel.dart';
+
+/// A wrapper that coerces the generic type of the channel returned by an inner
+/// transformer to `S`.
+class TypeSafeStreamChannelTransformer<S, T>
+    implements StreamChannelTransformer<S, T> {
+ final StreamChannelTransformer _inner;
+
+  TypeSafeStreamChannelTransformer(this._inner);
+
+  StreamChannel<S> bind(StreamChannel<T> channel) =>
+      _inner.bind(channel).cast();
+}
diff --git a/lib/stream_channel.dart b/lib/stream_channel.dart
index b89845d..3615d21 100644
--- a/lib/stream_channel.dart
+++ b/lib/stream_channel.dart
@@ -109,6 +109,13 @@
   /// Returns a copy of [this] with [sink] replaced by [change]'s return
   /// value.
   StreamChannel<T> changeSink(StreamSink<T> change(StreamSink<T> sink));
+
+  /// Returns a copy of [this] with the generic type coerced to [S].
+  ///
+  /// If any events emitted by [stream] aren't of type [S], they're converted
+  /// into [CastError] events. Similarly, if any events are added to [sync] that
+  /// aren't of type [S], a [CastError] is thrown.
+  StreamChannel/*<S>*/ cast/*<S>*/();
 }
 
 /// An implementation of [StreamChannel] that simply takes a stream and a sink
@@ -145,4 +152,7 @@
 
   StreamChannel<T> changeSink(StreamSink<T> change(StreamSink<T> sink)) =>
       new StreamChannel(stream, change(sink));
+
+  StreamChannel/*<S>*/ cast/*<S>*/() => new StreamChannel(
+      DelegatingStream.typed(stream), DelegatingStreamSink.typed(sink));
 }
diff --git a/pubspec.yaml b/pubspec.yaml
index 3e87e2b..1c1df31 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
 name: stream_channel
-version: 1.3.2
+version: 1.4.0
 description: An abstraction for two-way communication channels.
 author: Dart Team <misc@dartlang.org>
 homepage: https://github.com/dart-lang/stream_channel