OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 part of dart.io; | 5 part of dart.io; |
6 | 6 |
7 /** | 7 /** |
8 * A combined byte and text output. | 8 * A combined byte and text output. |
9 * | 9 * |
10 * An [IOSink] combines a [StreamSink] of bytes with a [StringSink], | 10 * An [IOSink] combines a [StreamSink] of bytes with a [StringSink], |
11 * and allows easy output of both bytes and text. | 11 * and allows easy output of both bytes and text. |
12 * | 12 * |
13 * Writing text ([write]) and adding bytes ([add]) may be interleaved freely. | 13 * Writing text ([write]) and adding bytes ([add]) may be interleaved freely. |
14 * | 14 * |
15 * While a stream is being added using [addStream], any further attempts | 15 * While a stream is being added using [addStream], any further attempts |
16 * to add or write to the [IOSink] will fail until the [addStream] completes. | 16 * to add or write to the [IOSink] will fail until the [addStream] completes. |
17 * | 17 * |
18 * If data is added to the [IOSink] after the sink is closed, the data will be | 18 * If data is added to the [IOSink] after the sink is closed, the data will be |
19 * ignored. Use the [done] future to be notified when the [IOSink] is closed. | 19 * ignored. Use the [done] future to be notified when the [IOSink] is closed. |
20 */ | 20 */ |
21 abstract class IOSink implements StreamSink<List<int>>, StringSink { | 21 abstract class IOSink implements StreamSink<List<int>>, StringSink { |
22 | |
23 /** | 22 /** |
24 * Create an [IOSink] that outputs to a [target] [StreamConsumer] of bytes. | 23 * Create an [IOSink] that outputs to a [target] [StreamConsumer] of bytes. |
25 * | 24 * |
26 * Text written to [StreamSink] methods is encoded to bytes using [encoding] | 25 * Text written to [StreamSink] methods is encoded to bytes using [encoding] |
27 * before being output on [target]. | 26 * before being output on [target]. |
28 */ | 27 */ |
29 factory IOSink(StreamConsumer<List<int>> target, | 28 factory IOSink(StreamConsumer<List<int>> target, {Encoding encoding: UTF8}) => |
30 {Encoding encoding: UTF8}) | 29 new _IOSinkImpl(target, encoding); |
31 => new _IOSinkImpl(target, encoding); | |
32 | 30 |
33 /** | 31 /** |
34 * The [Encoding] used when writing strings. Depending on the | 32 * The [Encoding] used when writing strings. Depending on the |
35 * underlying consumer this property might be mutable. | 33 * underlying consumer this property might be mutable. |
36 */ | 34 */ |
37 Encoding encoding; | 35 Encoding encoding; |
38 | 36 |
39 /** | 37 /** |
40 * Adds byte [data] to the target consumer, ignoring [encoding]. | 38 * Adds byte [data] to the target consumer, ignoring [encoding]. |
41 * | 39 * |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
159 } | 157 } |
160 | 158 |
161 Future addStream(Stream<T> stream) { | 159 Future addStream(Stream<T> stream) { |
162 if (_isBound) { | 160 if (_isBound) { |
163 throw new StateError("StreamSink is already bound to a stream"); | 161 throw new StateError("StreamSink is already bound to a stream"); |
164 } | 162 } |
165 _isBound = true; | 163 _isBound = true; |
166 if (_hasError) return done; | 164 if (_hasError) return done; |
167 // Wait for any sync operations to complete. | 165 // Wait for any sync operations to complete. |
168 Future targetAddStream() { | 166 Future targetAddStream() { |
169 return _target.addStream(stream) | 167 return _target.addStream(stream).whenComplete(() { |
170 .whenComplete(() { | 168 _isBound = false; |
171 _isBound = false; | 169 }); |
172 }); | |
173 } | 170 } |
| 171 |
174 if (_controllerInstance == null) return targetAddStream(); | 172 if (_controllerInstance == null) return targetAddStream(); |
175 var future = _controllerCompleter.future; | 173 var future = _controllerCompleter.future; |
176 _controllerInstance.close(); | 174 _controllerInstance.close(); |
177 return future.then((_) => targetAddStream()); | 175 return future.then((_) => targetAddStream()); |
178 } | 176 } |
179 | 177 |
180 Future flush() { | 178 Future flush() { |
181 if (_isBound) { | 179 if (_isBound) { |
182 throw new StateError("StreamSink is bound to a stream"); | 180 throw new StateError("StreamSink is bound to a stream"); |
183 } | 181 } |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
251 // A new stream takes over - forward errors to that stream. | 249 // A new stream takes over - forward errors to that stream. |
252 _controllerCompleter.completeError(error, stackTrace); | 250 _controllerCompleter.completeError(error, stackTrace); |
253 _controllerCompleter = null; | 251 _controllerCompleter = null; |
254 _controllerInstance = null; | 252 _controllerInstance = null; |
255 } else { | 253 } else { |
256 // No new stream. No need to close target, as it has already | 254 // No new stream. No need to close target, as it has already |
257 // failed. | 255 // failed. |
258 _completeDoneError(error, stackTrace); | 256 _completeDoneError(error, stackTrace); |
259 } | 257 } |
260 }); | 258 }); |
261 } | 259 } |
262 return _controllerInstance; | 260 return _controllerInstance; |
263 } | 261 } |
264 } | 262 } |
265 | 263 |
266 | |
267 class _IOSinkImpl extends _StreamSinkImpl<List<int>> implements IOSink { | 264 class _IOSinkImpl extends _StreamSinkImpl<List<int>> implements IOSink { |
268 Encoding _encoding; | 265 Encoding _encoding; |
269 bool _encodingMutable = true; | 266 bool _encodingMutable = true; |
270 | 267 |
271 _IOSinkImpl(StreamConsumer<List<int>> target, this._encoding) | 268 _IOSinkImpl(StreamConsumer<List<int>> target, this._encoding) : super(target); |
272 : super(target); | |
273 | 269 |
274 Encoding get encoding => _encoding; | 270 Encoding get encoding => _encoding; |
275 | 271 |
276 void set encoding(Encoding value) { | 272 void set encoding(Encoding value) { |
277 if (!_encodingMutable) { | 273 if (!_encodingMutable) { |
278 throw new StateError("IOSink encoding is not mutable"); | 274 throw new StateError("IOSink encoding is not mutable"); |
279 } | 275 } |
280 _encoding = value; | 276 _encoding = value; |
281 } | 277 } |
282 | 278 |
(...skipping 21 matching lines...) Expand all Loading... |
304 | 300 |
305 void writeln([Object object = ""]) { | 301 void writeln([Object object = ""]) { |
306 write(object); | 302 write(object); |
307 write("\n"); | 303 write("\n"); |
308 } | 304 } |
309 | 305 |
310 void writeCharCode(int charCode) { | 306 void writeCharCode(int charCode) { |
311 write(new String.fromCharCode(charCode)); | 307 write(new String.fromCharCode(charCode)); |
312 } | 308 } |
313 } | 309 } |
OLD | NEW |