Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: pkg/dev_compiler/tool/input_sdk/lib/io/io_sink.dart

Issue 2698353003: unfork DDC's copy of most SDK libraries (Closed)
Patch Set: revert core_patch Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 part of dart.io;
6
7 /**
8 * A combined byte and text output.
9 *
10 * An [IOSink] combines a [StreamSink] of bytes with a [StringSink],
11 * and allows easy output of both bytes and text.
12 *
13 * Writing text ([write]) and adding bytes ([add]) may be interleaved freely.
14 *
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.
17 *
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.
20 */
21 abstract class IOSink implements StreamSink<List<int>>, StringSink {
22
23 /**
24 * Create an [IOSink] that outputs to a [target] [StreamConsumer] of bytes.
25 *
26 * Text written to [StreamSink] methods is encoded to bytes using [encoding]
27 * before being output on [target].
28 */
29 factory IOSink(StreamConsumer<List<int>> target,
30 {Encoding encoding: UTF8})
31 => new _IOSinkImpl(target, encoding);
32
33 /**
34 * The [Encoding] used when writing strings. Depending on the
35 * underlying consumer this property might be mutable.
36 */
37 Encoding encoding;
38
39 /**
40 * Adds byte [data] to the target consumer, ignoring [encoding].
41 *
42 * The [encoding] does not apply to this method, and the `data` list is passed
43 * directly to the target consumer as a stream event.
44 *
45 * This function must not be called when a stream is currently being added
46 * using [addStream].
47 *
48 * This operation is non-blocking. See [flush] or [done] for how to get any
49 * errors generated by this call.
50 *
51 * The data list should not be modified after it has been passed to `add`.
52 */
53 void add(List<int> data);
54
55 /**
56 * Converts [obj] to a String by invoking [Object.toString] and
57 * [add]s the encoding of the result to the target consumer.
58 *
59 * This operation is non-blocking. See [flush] or [done] for how to get any
60 * errors generated by this call.
61 */
62 void write(Object obj);
63
64 /**
65 * Iterates over the given [objects] and [write]s them in sequence.
66 *
67 * If [separator] is provided, a `write` with the `separator` is performed
68 * between any two elements of objects`.
69 *
70 * This operation is non-blocking. See [flush] or [done] for how to get any
71 * errors generated by this call.
72 */
73 void writeAll(Iterable objects, [String separator = ""]);
74
75 /**
76 * Converts [obj] to a String by invoking [Object.toString] and
77 * writes the result to `this`, followed by a newline.
78 *
79 * This operation is non-blocking. See [flush] or [done] for how to get any
80 * errors generated by this call.
81 */
82 void writeln([Object obj = ""]);
83
84 /**
85 * Writes the character of [charCode].
86 *
87 * This method is equivalent to `write(new String.fromCharCode(charCode))`.
88 *
89 * This operation is non-blocking. See [flush] or [done] for how to get any
90 * errors generated by this call.
91 */
92 void writeCharCode(int charCode);
93
94 /**
95 * Passes the error to the target consumer as an error event.
96 *
97 * This function must not be called when a stream is currently being added
98 * using [addStream].
99 *
100 * This operation is non-blocking. See [flush] or [done] for how to get any
101 * errors generated by this call.
102 */
103 void addError(error, [StackTrace stackTrace]);
104
105 /**
106 * Adds all elements of the given [stream] to `this`.
107 *
108 * Returns a [Future] that completes when
109 * all elements of the given [stream] are added to `this`.
110 */
111 Future addStream(Stream<List<int>> stream);
112
113 /**
114 * Returns a [Future] that completes once all buffered data is accepted by the
115 * to underlying [StreamConsumer].
116 *
117 * This method must not be called while an [addStream] is incomplete.
118 *
119 * NOTE: This is not necessarily the same as the data being flushed by the
120 * operating system.
121 */
122 Future flush();
123
124 /**
125 * Close the target consumer.
126 */
127 Future close();
128
129 /**
130 * Get a future that will complete when the consumer closes, or when an
131 * error occurs. This future is identical to the future returned by
132 * [close].
133 */
134 Future get done;
135 }
136
137 class _StreamSinkImpl<T> implements StreamSink<T> {
138 final StreamConsumer<T> _target;
139 final Completer _doneCompleter = new Completer();
140 StreamController<T> _controllerInstance;
141 Completer _controllerCompleter;
142 bool _isClosed = false;
143 bool _isBound = false;
144 bool _hasError = false;
145
146 _StreamSinkImpl(this._target);
147
148 void add(T data) {
149 if (_isClosed) return;
150 _controller.add(data);
151 }
152
153 void addError(error, [StackTrace stackTrace]) {
154 _controller.addError(error, stackTrace);
155 }
156
157 Future addStream(Stream<T> stream) {
158 if (_isBound) {
159 throw new StateError("StreamSink is already bound to a stream");
160 }
161 _isBound = true;
162 if (_hasError) return done;
163 // Wait for any sync operations to complete.
164 Future targetAddStream() {
165 return _target.addStream(stream)
166 .whenComplete(() {
167 _isBound = false;
168 });
169 }
170 if (_controllerInstance == null) return targetAddStream();
171 var future = _controllerCompleter.future;
172 _controllerInstance.close();
173 return future.then((_) => targetAddStream());
174 }
175
176 Future flush() {
177 if (_isBound) {
178 throw new StateError("StreamSink is bound to a stream");
179 }
180 if (_controllerInstance == null) return new Future.value(this);
181 // Adding an empty stream-controller will return a future that will complete
182 // when all data is done.
183 _isBound = true;
184 var future = _controllerCompleter.future;
185 _controllerInstance.close();
186 return future.whenComplete(() {
187 _isBound = false;
188 });
189 }
190
191 Future close() {
192 if (_isBound) {
193 throw new StateError("StreamSink is bound to a stream");
194 }
195 if (!_isClosed) {
196 _isClosed = true;
197 if (_controllerInstance != null) {
198 _controllerInstance.close();
199 } else {
200 _closeTarget();
201 }
202 }
203 return done;
204 }
205
206 void _closeTarget() {
207 _target.close().then(_completeDoneValue, onError: _completeDoneError);
208 }
209
210 Future get done => _doneCompleter.future;
211
212 void _completeDoneValue(value) {
213 if (!_doneCompleter.isCompleted) {
214 _doneCompleter.complete(value);
215 }
216 }
217
218 void _completeDoneError(error, StackTrace stackTrace) {
219 if (!_doneCompleter.isCompleted) {
220 _hasError = true;
221 _doneCompleter.completeError(error, stackTrace);
222 }
223 }
224
225 StreamController<T> get _controller {
226 if (_isBound) {
227 throw new StateError("StreamSink is bound to a stream");
228 }
229 if (_isClosed) {
230 throw new StateError("StreamSink is closed");
231 }
232 if (_controllerInstance == null) {
233 _controllerInstance = new StreamController<T>(sync: true);
234 _controllerCompleter = new Completer();
235 _target.addStream(_controller.stream).then((_) {
236 if (_isBound) {
237 // A new stream takes over - forward values to that stream.
238 _controllerCompleter.complete(this);
239 _controllerCompleter = null;
240 _controllerInstance = null;
241 } else {
242 // No new stream, .close was called. Close _target.
243 _closeTarget();
244 }
245 }, onError: (error, stackTrace) {
246 if (_isBound) {
247 // A new stream takes over - forward errors to that stream.
248 _controllerCompleter.completeError(error, stackTrace);
249 _controllerCompleter = null;
250 _controllerInstance = null;
251 } else {
252 // No new stream. No need to close target, as it has already
253 // failed.
254 _completeDoneError(error, stackTrace);
255 }
256 });
257 }
258 return _controllerInstance;
259 }
260 }
261
262
263 class _IOSinkImpl extends _StreamSinkImpl<List<int>> implements IOSink {
264 Encoding _encoding;
265 bool _encodingMutable = true;
266
267 _IOSinkImpl(StreamConsumer<List<int>> target, this._encoding)
268 : super(target);
269
270 Encoding get encoding => _encoding;
271
272 void set encoding(Encoding value) {
273 if (!_encodingMutable) {
274 throw new StateError("IOSink encoding is not mutable");
275 }
276 _encoding = value;
277 }
278
279 void write(Object obj) {
280 String string = '$obj';
281 if (string.isEmpty) return;
282 add(_encoding.encode(string));
283 }
284
285 void writeAll(Iterable objects, [String separator = ""]) {
286 Iterator iterator = objects.iterator;
287 if (!iterator.moveNext()) return;
288 if (separator.isEmpty) {
289 do {
290 write(iterator.current);
291 } while (iterator.moveNext());
292 } else {
293 write(iterator.current);
294 while (iterator.moveNext()) {
295 write(separator);
296 write(iterator.current);
297 }
298 }
299 }
300
301 void writeln([Object object = ""]) {
302 write(object);
303 write("\n");
304 }
305
306 void writeCharCode(int charCode) {
307 write(new String.fromCharCode(charCode));
308 }
309 }
OLDNEW
« no previous file with comments | « pkg/dev_compiler/tool/input_sdk/lib/io/io_service.dart ('k') | pkg/dev_compiler/tool/input_sdk/lib/io/io_sources.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698