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

Side by Side Diff: runtime/bin/string_stream.dart

Issue 8885032: Improve the event handling for string input stream (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 9 years 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 | Annotate | Revision Log
« no previous file with comments | « runtime/bin/chunked_stream.dart ('k') | tests/standalone/src/FileInputStreamTest.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, 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 // Interface for decoders decoding binary data into string data. The 5 // Interface for decoders decoding binary data into string data. The
6 // decoder keeps track of line breaks during decoding. 6 // decoder keeps track of line breaks during decoding.
7 interface _StringDecoder { 7 interface _StringDecoder {
8 // Add more binary data to be decoded. The ownership of the buffer 8 // Add more binary data to be decoded. The ownership of the buffer
9 // is transfered to the decoder and the caller most not modify it any more. 9 // is transfered to the decoder and the caller most not modify it any more.
10 int write(List<int> buffer); 10 int write(List<int> buffer);
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after
225 } else if (_encoding == "ASCII") { 225 } else if (_encoding == "ASCII") {
226 _decoder = new _AsciiDecoder(); 226 _decoder = new _AsciiDecoder();
227 } else { 227 } else {
228 throw new StreamException("Unsupported encoding $_encoding"); 228 throw new StreamException("Unsupported encoding $_encoding");
229 } 229 }
230 _input.dataHandler = _dataHandler; 230 _input.dataHandler = _dataHandler;
231 _input.closeHandler = _closeHandler; 231 _input.closeHandler = _closeHandler;
232 } 232 }
233 233
234 String read() { 234 String read() {
235 // If there is buffered data return that first. 235 String result = _decoder.decoded;
236 var decodedString = _decoder.decoded; 236 _checkInstallDataHandler();
237 if (decodedString !== null) { 237 return result;
238 if (_inputClosed && _decoder.isEmpty()) {
239 _streamClosed();
240 }
241 return decodedString;
242 } else if (_inputClosed) {
243 _streamClosed();
244 return null;
245 } else {
246 _readData();
247 return _decoder.decoded;
248 }
249 } 238 }
250 239
251 String readLine() { 240 String readLine() {
252 if (_closed) return null; 241 String decodedLine = _decoder.decodedLine;
253 242 if (decodedLine == null) {
254 if (_decoder.lineBreaks == 0) { 243 if (_inputClosed) {
255 _readData(); 244 // Last line might not have a line separator.
245 decodedLine = _decoder.decoded;
246 if (decodedLine != null && decodedLine[decodedLine.length - 1] == '\r') {
Mads Ager (google) 2011/12/09 08:47:04 Long line.
Søren Gjesse 2011/12/09 11:44:32 Done.
247 decodedLine = decodedLine.substring(0, decodedLine.length - 1);
248 }
249 }
256 } 250 }
257 var decodedLine = _decoder.decodedLine; 251 _checkInstallDataHandler();
258 if (decodedLine !== null) { 252 return decodedLine;
259 if (_inputClosed && _decoder.isEmpty()) {
260 _streamClosed();
261 }
262 return decodedLine;
263 }
264 if (_inputClosed) {
265 decodedLine = _decoder.decoded;
266 if (decodedLine[decodedLine.length - 1] == '\r') {
267 decodedLine = decodedLine.substring(0, decodedLine.length - 1);
268 }
269 _streamClosed();
270 return decodedLine;
271 }
272 return null;
273 } 253 }
274 254
275 String get encoding() => _encoding; 255 String get encoding() => _encoding;
276 256
277 bool get closed() => _closed; 257 bool get closed() => _inputClosed && _decoder.isEmpty();
278 258
279 void set dataHandler(void callback()) { 259 void set dataHandler(void callback()) {
280 _clientDataHandler = callback; 260 _clientDataHandler = callback;
281 _clientLineHandler = null; 261 _clientLineHandler = null;
262 _checkInstallDataHandler();
282 } 263 }
283 264
284 void set lineHandler(void callback()) { 265 void set lineHandler(void callback()) {
285 _clientLineHandler = callback; 266 _clientLineHandler = callback;
286 _clientDataHandler = null; 267 _clientDataHandler = null;
268 _checkInstallDataHandler();
287 } 269 }
288 270
289 void set closeHandler(void callback()) { 271 void set closeHandler(void callback()) {
290 _clientCloseHandler = callback; 272 _clientCloseHandler = callback;
291 } 273 }
292 274
293 void _dataHandler() { 275 void _dataHandler() {
294 _readData(); 276 _readData();
295 if (!_decoder.isEmpty() && _clientDataHandler !== null) { 277 if (!_decoder.isEmpty() && _clientDataHandler !== null) {
296 _clientDataHandler(); 278 _clientDataHandler();
297 } 279 }
298 if (_decoder.lineBreaks > 0 && _clientLineHandler !== null) { 280 if (_decoder.lineBreaks > 0 && _clientLineHandler !== null) {
299 _clientLineHandler(); 281 _clientLineHandler();
300 } 282 }
283 _checkScheduleCallback();
284 _checkInstallDataHandler();
301 } 285 }
302 286
303 void _closeHandler() { 287 void _closeHandler() {
304 _inputClosed = true; 288 _inputClosed = true;
305 if (!_decoder.isEmpty()) { 289 if (_decoder.isEmpty() && _clientCloseHandler != null) {
306 // If there is still data buffered call the data handler. 290 _clientCloseHandler();
307 if (_clientDataHandler !== null) _clientDataHandler(); 291 _closed = true;
308 if (_clientLineHandler !== null) _clientLineHandler();
309 } else { 292 } else {
310 _closed = true; 293 _checkScheduleCallback();
311 if (_clientCloseHandler !== null) _clientCloseHandler();
312 } 294 }
313 } 295 }
314 296
315 void _readData() { 297 void _readData() {
316 List<int> data = _input.read(); 298 List<int> data = _input.read();
317 if (data !== null) { 299 if (data !== null) {
318 _decoder.write(data); 300 _decoder.write(data);
319 } 301 }
320 } 302 }
321 303
322 void _streamClosed() { 304 void _checkInstallDataHandler() {
323 _closed = true; 305 if (_inputClosed ||
306 (_clientDataHandler === null && _clientLineHandler === null)) {
307 _input.dataHandler = null;
308 } else if (_clientDataHandler !== null) {
309 if (_decoder.isEmpty()) {
310 _input.dataHandler = _dataHandler;
311 } else {
312 _input.dataHandler = null;
313 }
314 } else {
315 assert(_clientLineHandler !== null);
316 if (_decoder.lineBreaks == 0) {
317 _input.dataHandler = _dataHandler;
318 } else {
319 _input.dataHandler = null;
320 }
321 }
322 }
324 323
325 // TODO(sgjesse): Find a better way of scheduling callbacks from 324 // TODO(sgjesse): Find a better way of scheduling callbacks from
326 // the event loop. 325 // the event loop.
326 void _checkScheduleCallback() {
327 void issueDataCallback(Timer timer) {
328 _scheduledDataCallback = null;
329 if (_clientDataHandler !== null) {
330 _clientDataHandler();
331 _checkScheduleCallback();
332 }
333 }
334
335 void issueLineCallback(Timer timer) {
336 _scheduledLineCallback = null;
337 if (_clientLineHandler !== null) {
338 _clientLineHandler();
339 _checkScheduleCallback();
340 }
341 }
342
327 void issueCloseCallback(Timer timer) { 343 void issueCloseCallback(Timer timer) {
328 if (_clientCloseHandler !== null) _clientCloseHandler(); 344 _scheduledCloseCallback = null;
345 if (!_closed) {
346 if (_clientCloseHandler !== null) _clientCloseHandler();
347 _closed = true;
348 }
329 } 349 }
330 new Timer(issueCloseCallback, 0, false); 350
351 if (!_closed) {
352 // Schedule data callback if string data available.
353 if (_clientDataHandler != null &&
354 !_decoder.isEmpty() &&
355 _scheduledDataCallback == null) {
356 if (_scheduledLineCallback != null) _scheduledLineCallback.cancel();
357 _scheduledDataCallback = new Timer(issueDataCallback, 0, false);
358 }
359
360 // Schedule line callback if a line is available.
361 if (_clientLineHandler != null &&
362 (_decoder.lineBreaks > 0 || (!_decoder.isEmpty() && _inputClosed)) &&
363 _scheduledLineCallback == null) {
364 if (_scheduledDataCallback != null) _scheduledDataCallback.cancel();
365 _scheduledLineCallback = new Timer(issueLineCallback, 0, false);
366 }
367
368 // Schedule close callback if no more data and input is closed.
369 if (_decoder.isEmpty() &&
370 _inputClosed &&
371 _scheduledCloseCallback == null) {
372 _scheduledCloseCallback = new Timer(issueCloseCallback, 0, false);
373 }
374 }
331 } 375 }
332 376
333 InputStream _input; 377 InputStream _input;
334 String _encoding; 378 String _encoding;
335 _StringDecoder _decoder; 379 _StringDecoder _decoder;
336 bool _inputClosed = false; // Is the underlying input stream closed? 380 bool _inputClosed = false; // Is the underlying input stream closed?
337 bool _closed = false; // Is this stream closed. 381 bool _closed = false; // Is this stream closed.
338 bool _eof = false; // Has all data been read from the decoder? 382 bool _eof = false; // Has all data been read from the decoder?
339 var _clientDataHandler; 383 Timer _scheduledDataCallback;
340 var _clientLineHandler; 384 Timer _scheduledLineCallback;
341 var _clientCloseHandler; 385 Timer _scheduledCloseCallback;
386 Function _clientDataHandler;
387 Function _clientLineHandler;
388 Function _clientCloseHandler;
342 } 389 }
OLDNEW
« no previous file with comments | « runtime/bin/chunked_stream.dart ('k') | tests/standalone/src/FileInputStreamTest.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698