Index: sdk/lib/io/io_sink.dart |
diff --git a/sdk/lib/io/io_sink.dart b/sdk/lib/io/io_sink.dart |
index 2d6719d6a8f43140ee3e916fd1b5c583ea9874be..b1c05a02542b9a412e1440f49c83df226210fe42 100644 |
--- a/sdk/lib/io/io_sink.dart |
+++ b/sdk/lib/io/io_sink.dart |
@@ -5,20 +5,27 @@ |
part of dart.io; |
/** |
- * Helper class to wrap a [StreamConsumer<List<int>>] and provide |
- * utility functions for writing to the StreamConsumer directly. The |
- * [IOSink] buffers the input given by all [StringSink] methods and will delay |
- * an [addStream] until the buffer is flushed. |
+ * A combined byte and text output. |
* |
- * When the [IOSink] is bound to a stream (through [addStream]) any call |
- * to the [IOSink] will throw a [StateError]. When the [addStream] completes, |
- * the [IOSink] will again be open for all calls. |
+ * An [IOSink] combines a [StreamSink] of bytes with a [StringSink], |
+ * and allows easy output of both bytes and text. |
+ * |
+ * Writing text ([write]) and adding bytes ([add]) may be interleaved freely. |
+ * |
+ * While a stream is being added using [addStream], any further attempts |
+ * to add or write to the [IOSink] will fail until the [addStream] completes. |
* |
* If data is added to the [IOSink] after the sink is closed, the data will be |
* ignored. Use the [done] future to be notified when the [IOSink] is closed. |
*/ |
abstract class IOSink implements StreamSink<List<int>>, StringSink { |
- // TODO(ajohnsen): Make _encodingMutable an argument. |
+ |
+ /** |
+ * Create an [IOSink] that outputs to a [target] [StreamConsumer] of bytes. |
+ * |
+ * Text written to [StreamSink] methods is encoded to bytes using [encoding] |
+ * before being output on [target]. |
+ */ |
factory IOSink(StreamConsumer<List<int>> target, |
{Encoding encoding: UTF8}) |
=> new _IOSinkImpl(target, encoding); |
@@ -30,7 +37,7 @@ abstract class IOSink implements StreamSink<List<int>>, StringSink { |
Encoding encoding; |
/** |
- * Adds [data] to the target consumer, ignoring [encoding]. |
+ * Adds byte [data] to the target consumer, ignoring [encoding]. |
* |
* The [encoding] does not apply to this method, and the `data` list is passed |
* directly to the target consumer as a stream event. |
@@ -58,7 +65,7 @@ abstract class IOSink implements StreamSink<List<int>>, StringSink { |
* Iterates over the given [objects] and [write]s them in sequence. |
* |
* If [separator] is provided, a `write` with the `separator` is performed |
- * between any two elements of `objects`. |
+ * between any two elements of objects`. |
* |
* This operation is non-blocking. See [flush] or [done] for how to get any |
* errors generated by this call. |
@@ -75,7 +82,7 @@ abstract class IOSink implements StreamSink<List<int>>, StringSink { |
void writeln([Object obj = ""]); |
/** |
- * Writes the [charCode] to `this`. |
+ * Writes the character of [charCode]. |
* |
* This method is equivalent to `write(new String.fromCharCode(charCode))`. |
* |
@@ -107,7 +114,7 @@ abstract class IOSink implements StreamSink<List<int>>, StringSink { |
* Returns a [Future] that completes once all buffered data is accepted by the |
* to underlying [StreamConsumer]. |
* |
- * It's an error to call this method, while an [addStream] is incomplete. |
+ * This method must not be called while an [addStream] is incomplete. |
* |
* NOTE: This is not necessarily the same as the data being flushed by the |
* operating system. |
@@ -129,17 +136,14 @@ abstract class IOSink implements StreamSink<List<int>>, StringSink { |
class _StreamSinkImpl<T> implements StreamSink<T> { |
final StreamConsumer<T> _target; |
- Completer _doneCompleter = new Completer(); |
- Future _doneFuture; |
+ final Completer _doneCompleter = new Completer(); |
StreamController<T> _controllerInstance; |
Completer _controllerCompleter; |
bool _isClosed = false; |
bool _isBound = false; |
bool _hasError = false; |
- _StreamSinkImpl(this._target) { |
- _doneFuture = _doneCompleter.future; |
- } |
+ _StreamSinkImpl(this._target); |
void add(T data) { |
if (_isClosed) return; |
@@ -180,8 +184,8 @@ class _StreamSinkImpl<T> implements StreamSink<T> { |
var future = _controllerCompleter.future; |
_controllerInstance.close(); |
return future.whenComplete(() { |
- _isBound = false; |
- }); |
+ _isBound = false; |
+ }); |
} |
Future close() { |
@@ -203,19 +207,19 @@ class _StreamSinkImpl<T> implements StreamSink<T> { |
_target.close().then(_completeDoneValue, onError: _completeDoneError); |
} |
- Future get done => _doneFuture; |
+ Future get done => _doneCompleter.future; |
void _completeDoneValue(value) { |
- if (_doneCompleter == null) return; |
- _doneCompleter.complete(value); |
- _doneCompleter = null; |
+ if (!_doneCompleter.isCompleted) { |
+ _doneCompleter.complete(value); |
+ } |
} |
void _completeDoneError(error, StackTrace stackTrace) { |
- if (_doneCompleter == null) return; |
- _hasError = true; |
- _doneCompleter.completeError(error, stackTrace); |
- _doneCompleter = null; |
+ if (!_doneCompleter.isCompleted) { |
+ _hasError = true; |
+ _doneCompleter.completeError(error, stackTrace); |
+ } |
} |
StreamController<T> get _controller { |
@@ -228,32 +232,29 @@ class _StreamSinkImpl<T> implements StreamSink<T> { |
if (_controllerInstance == null) { |
_controllerInstance = new StreamController<T>(sync: true); |
_controllerCompleter = new Completer(); |
- _target.addStream(_controller.stream) |
- .then( |
- (_) { |
- if (_isBound) { |
- // A new stream takes over - forward values to that stream. |
- _controllerCompleter.complete(this); |
- _controllerCompleter = null; |
- _controllerInstance = null; |
- } else { |
- // No new stream, .close was called. Close _target. |
- _closeTarget(); |
- } |
- }, |
- onError: (error, stackTrace) { |
- if (_isBound) { |
- // A new stream takes over - forward errors to that stream. |
- _controllerCompleter.completeError(error, stackTrace); |
- _controllerCompleter = null; |
- _controllerInstance = null; |
- } else { |
- // No new stream. No need to close target, as it have already |
- // failed. |
- _completeDoneError(error, stackTrace); |
- } |
- }); |
- } |
+ _target.addStream(_controller.stream).then((_) { |
+ if (_isBound) { |
+ // A new stream takes over - forward values to that stream. |
+ _controllerCompleter.complete(this); |
+ _controllerCompleter = null; |
+ _controllerInstance = null; |
+ } else { |
+ // No new stream, .close was called. Close _target. |
+ _closeTarget(); |
+ } |
+ }, onError: (error, stackTrace) { |
+ if (_isBound) { |
+ // A new stream takes over - forward errors to that stream. |
+ _controllerCompleter.completeError(error, stackTrace); |
+ _controllerCompleter = null; |
+ _controllerInstance = null; |
+ } else { |
+ // No new stream. No need to close target, as it has already |
+ // failed. |
+ _completeDoneError(error, stackTrace); |
+ } |
+ }); |
+ } |
return _controllerInstance; |
} |
} |
@@ -297,8 +298,8 @@ class _IOSinkImpl extends _StreamSinkImpl<List<int>> implements IOSink { |
} |
} |
- void writeln([Object obj = ""]) { |
- write(obj); |
+ void writeln([Object object = ""]) { |
+ write(object); |
write("\n"); |
} |