Add clearer rules for implementations. This helps implementations know how to handle corner cases, and helps users know what behavior they can rely on. R=rnystrom@google.com Review URL: https://codereview.chromium.org//1604903006 .
diff --git a/pkgs/stream_channel/lib/stream_channel.dart b/pkgs/stream_channel/lib/stream_channel.dart index a8c9a09..fd7b093 100644 --- a/pkgs/stream_channel/lib/stream_channel.dart +++ b/pkgs/stream_channel/lib/stream_channel.dart
@@ -9,18 +9,55 @@ /// An abstract class representing a two-way communication channel. /// -/// Subclasses are strongly encouraged to mix in or extend [StreamChannelMixin] -/// to get default implementations of the various instance methods. Adding new -/// methods to this interface will not be considered a breaking change if -/// implementations are also added to [StreamChannelMixin]. +/// Users should consider the [stream] emitting a "done" event to be the +/// canonical indicator that the channel has closed. If they wish to close the +/// channel, they should close the [sink]—canceling the stream subscription is +/// not sufficient. Protocol errors may be emitted through the stream or through +/// [Sink.done], depending on their underlying cause. Note that the sink may +/// silently drop events if the channel closes before [Sink.close] is called. +/// +/// Implementations are strongly encouraged to mix in or extend +/// [StreamChannelMixin] to get default implementations of the various instance +/// methods. Adding new methods to this interface will not be considered a +/// breaking change if implementations are also added to [StreamChannelMixin]. +/// +/// Implementations must provide the following guarantees: +/// +/// * The stream is single-subscription, and must follow all the guarantees of +/// single-subscription streams. +/// +/// * Closing the sink causes the stream to close before it emits any more +/// events. +/// +/// * After the stream closes, the sink is automatically closed. If this +/// happens, sink methods should silently drop their arguments until +/// [Sink.close] is called. +/// +/// * If the stream closes before it has a listener, the sink should silently +/// drop events if possible. +/// +/// * Canceling the stream's subscription has no effect on the sink. The channel +/// must still be able to respond to the other endpoint closing the channel +/// even after the subscription has been canceled. +/// +/// * The sink *either* forwards errors to the other endpoint *or* closes as +/// soon as an error is added and forwards that error to the [Sink.done] +/// future. +/// +/// These guarantees allow users to interact uniformly with all implementations, +/// and ensure that either endpoint closing the stream produces consistent +/// behavior. abstract class StreamChannel<T> { - /// The stream that emits values from the other endpoint. + /// The single-subscription stream that emits values from the other endpoint. Stream<T> get stream; /// The sink for sending values to the other endpoint. StreamSink<T> get sink; /// Creates a new [StreamChannel] that communicates over [stream] and [sink]. + /// + /// Note that this stream/sink pair must provide the guarantees listed in the + /// [StreamChannel] documentation. factory StreamChannel(Stream<T> stream, StreamSink<T> sink) => new _StreamChannel<T>(stream, sink);