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

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

Issue 10392023: Change dart:io to use Future for one-shot operations. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Adding stable test binaries Created 8 years, 7 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 | Annotate | Revision Log
« no previous file with comments | « runtime/bin/file.dart ('k') | runtime/bin/process.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) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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 class _FileInputStream extends _BaseDataInputStream implements InputStream { 5 class _FileInputStream extends _BaseDataInputStream implements InputStream {
6 _FileInputStream(String name) { 6 _FileInputStream(String name) {
7 var file = new File(name); 7 var file = new File(name);
8 _data = []; 8 _data = [];
9 _position = 0; 9 _position = 0;
10 file.onError = _reportError; 10 var chained = file.open(FileMode.READ).chain((openedFile) {
11 file.open(FileMode.READ, (openedFile) { 11 return _readDataFromFile(openedFile);
12 _readDataFromFile(openedFile); 12 });
13 chained.handleException((e) {
14 _reportError(e);
15 return true;
13 }); 16 });
14 } 17 }
15 18
16 _FileInputStream.fromStdio(int fd) { 19 _FileInputStream.fromStdio(int fd) {
17 assert(fd == 0); 20 assert(fd == 0);
18 var file = _File._openStdioSync(fd); 21 var file = _File._openStdioSync(fd);
19 _data = []; 22 _data = [];
20 _position = 0; 23 _position = 0;
21 _readDataFromFile(file); 24 _readDataFromFile(file).handleException((e) {
25 _reportError(e);
26 return true;
27 });
22 } 28 }
23 29
24 void _readDataFromFile(RandomAccessFile openedFile) { 30 Future<RandomAccessFile> _closeAfterRead(RandomAccessFile openedFile) {
25 openedFile.onError = _reportError; 31 return openedFile.close().transform((ignore) {
26 openedFile.length((length) { 32 _streamMarkedClosed = true;
33 _checkScheduleCallbacks();
34 return openedFile;
35 });
36 }
37
38 Future<RandomAccessFile> _readDataFromFile(RandomAccessFile openedFile) {
39 return openedFile.length().chain((length) {
27 var contents = new Uint8List(length); 40 var contents = new Uint8List(length);
28 if (length != 0) { 41 if (length != 0) {
29 openedFile.readList(contents, 0, length, (read) { 42 return openedFile.readList(contents, 0, length).chain((read) {
30 if (read != length) { 43 if (read != length) {
31 _reportError(new FileIOException( 44 throw new FileIOException(
32 'Failed reading file contents in FileInputStream')); 45 'Failed reading file contents in FileInputStream');
33 } else { 46 } else {
34 _data = contents; 47 _data = contents;
35 } 48 }
36 openedFile.close(() { 49 return _closeAfterRead(openedFile);
37 _streamMarkedClosed = true;
38 _checkScheduleCallbacks();
39 });
40 }); 50 });
41 } else { 51 } else {
42 openedFile.close(() { 52 return _closeAfterRead(openedFile);
43 _streamMarkedClosed = true;
44 _checkScheduleCallbacks();
45 });
46 } 53 }
47 }); 54 });
48 } 55 }
49 56
50 int available() { 57 int available() {
51 return _closed ? 0 : _data.length - _position; 58 return _closed ? 0 : _data.length - _position;
52 } 59 }
53 60
54 void pipe(OutputStream output, [bool close = true]) { 61 void pipe(OutputStream output, [bool close = true]) {
55 _pipe(this, output, close: close); 62 _pipe(this, output, close: close);
(...skipping 22 matching lines...) Expand all
78 List<int> _data; 85 List<int> _data;
79 int _position; 86 int _position;
80 bool _closed = false; 87 bool _closed = false;
81 } 88 }
82 89
83 90
84 class _FileOutputStream extends _BaseOutputStream implements OutputStream { 91 class _FileOutputStream extends _BaseOutputStream implements OutputStream {
85 _FileOutputStream(String name, FileMode mode) { 92 _FileOutputStream(String name, FileMode mode) {
86 _pendingOperations = new List<List<int>>(); 93 _pendingOperations = new List<List<int>>();
87 var f = new File(name); 94 var f = new File(name);
88 f.open(mode, (openedFile) { 95 var openFuture = f.open(mode);
96 openFuture.then((openedFile) {
89 _file = openedFile; 97 _file = openedFile;
90 _setupFileHandlers();
91 _processPendingOperations(); 98 _processPendingOperations();
92 }); 99 });
93 f.onError = _reportError; 100 openFuture.handleException((e) {
101 _reportError(e);
102 return true;
103 });
94 } 104 }
95 105
96 _FileOutputStream.fromStdio(int fd) { 106 _FileOutputStream.fromStdio(int fd) {
97 assert(1 <= fd && fd <= 2); 107 assert(1 <= fd && fd <= 2);
98 _file = _File._openStdioSync(fd); 108 _file = _File._openStdioSync(fd);
99 _setupFileHandlers();
100 }
101
102
103 void _setupFileHandlers() {
104 _file.onError = _reportError;
105 _file.onNoPendingWrites = () {
106 if (!_streamMarkedClosed && _onNoPendingWrites != null) {
107 _onNoPendingWrites();
108 }
109 };
110 } 109 }
111 110
112 bool write(List<int> buffer, [bool copyBuffer = false]) { 111 bool write(List<int> buffer, [bool copyBuffer = false]) {
113 var data = buffer; 112 var data = buffer;
114 if (copyBuffer) { 113 if (copyBuffer) {
115 var length = buffer.length; 114 var length = buffer.length;
116 data = new Uint8List(length); 115 data = new Uint8List(length);
117 data.setRange(0, length, buffer, 0); 116 data.setRange(0, length, buffer, 0);
118 } 117 }
119 if (_file == null) { 118 if (_file == null) {
(...skipping 13 matching lines...) Expand all
133 } 132 }
134 var copy = new Uint8List(length); 133 var copy = new Uint8List(length);
135 copy.setRange(0, length, buffer, offset); 134 copy.setRange(0, length, buffer, offset);
136 return write(copy); 135 return write(copy);
137 } 136 }
138 137
139 void close() { 138 void close() {
140 if (_file == null) { 139 if (_file == null) {
141 _pendingOperations.add(null); 140 _pendingOperations.add(null);
142 } else if (!_streamMarkedClosed) { 141 } else if (!_streamMarkedClosed) {
143 _file.close(() { 142 _file.close().then((ignore) {
144 if (_onClosed != null) _onClosed(); 143 if (_onClosed != null) _onClosed();
145 }); 144 });
146 _streamMarkedClosed = true; 145 _streamMarkedClosed = true;
147 } 146 }
148 } 147 }
149 148
150 void set onNoPendingWrites(void callback()) { 149 void set onNoPendingWrites(void callback()) {
151 _onNoPendingWrites = callback; 150 _onNoPendingWrites = callback;
151 if (((_pendingOperations == null) || (_pendingOperations.length == 0)) &&
152 (outstandingWrites == 0) &&
153 !_streamMarkedClosed &&
154 (_onNoPendingWrites != null)) {
155 new Timer(0, (t) {
156 if (_onNoPendingWrites != null) {
157 _onNoPendingWrites();
158 }
159 });
160 }
152 } 161 }
153 162
154 void set onClosed(void callback()) { 163 void set onClosed(void callback()) {
155 _onClosed = callback; 164 _onClosed = callback;
156 } 165 }
157 166
158 void _processPendingOperations() { 167 void _processPendingOperations() {
159 _pendingOperations.forEach((buffer) { 168 _pendingOperations.forEach((buffer) {
160 (buffer != null) ? write(buffer) : close(); 169 (buffer != null) ? write(buffer) : close();
161 }); 170 });
162 _pendingOperations = null; 171 _pendingOperations = null;
163 } 172 }
164 173
165 void _write(List<int> buffer, int offset, int len) { 174 void _write(List<int> buffer, int offset, int len) {
166 _file.writeList(buffer, offset, len); 175 outstandingWrites++;
176 var writeListFuture = _file.writeList(buffer, offset, len);
177 writeListFuture.then((ignore) {
178 outstandingWrites--;
179 if ((outstandingWrites == 0) &&
180 !_streamMarkedClosed &&
181 (_onNoPendingWrites != null)) {
182 _onNoPendingWrites();
183 }
184 });
185 writeListFuture.handleException((e) {
186 outstandingWrites--;
187 _reportError(e);
188 return true;
189 });
167 } 190 }
168 191
169 RandomAccessFile _file; 192 RandomAccessFile _file;
170 193
171 // When this is set to true the stream is marked closed. When a 194 // When this is set to true the stream is marked closed. When a
172 // stream is marked closed no more data can be written. 195 // stream is marked closed no more data can be written.
173 bool _streamMarkedClosed = false; 196 bool _streamMarkedClosed = false;
174 197
175 // When this is set to true the close callback has been called and 198 // When this is set to true the close callback has been called and
176 // the stream is fully closed. 199 // the stream is fully closed.
177 bool _closeCallbackCalled = false; 200 bool _closeCallbackCalled = false;
178 201
202 // Number of writes that have not yet completed.
203 int outstandingWrites = 0;
204
179 // List of pending writes that were issued before the underlying 205 // List of pending writes that were issued before the underlying
180 // file was successfully opened. 206 // file was successfully opened.
181 List<List<int>> _pendingOperations; 207 List<List<int>> _pendingOperations;
182 208
183 Function _onNoPendingWrites; 209 Function _onNoPendingWrites;
184 Function _onClosed; 210 Function _onClosed;
185 } 211 }
186 212
187 213
188 // Helper class containing static file helper methods. 214 // Helper class containing static file helper methods.
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after
361 387
362 static int checkedWriteString(int id, String string) { 388 static int checkedWriteString(int id, String string) {
363 if (string is !String) return -1; 389 if (string is !String) return -1;
364 return writeString(id, string); 390 return writeString(id, string);
365 } 391 }
366 392
367 } 393 }
368 394
369 // Base class for _File and _RandomAccessFile with shared functions. 395 // Base class for _File and _RandomAccessFile with shared functions.
370 class _FileBase { 396 class _FileBase {
371 void _reportError(e) {
372 if (_onError != null) {
373 _onError(e);
374 } else {
375 throw e;
376 }
377 }
378
379 bool _isErrorResponse(response) { 397 bool _isErrorResponse(response) {
380 return response is List && response[0] != _FileUtils.kSuccessResponse; 398 return response is List && response[0] != _FileUtils.kSuccessResponse;
381 } 399 }
382 400
383 void _handleErrorResponse(response, String message) { 401 Exception _exceptionFromResponse(response, String message) {
384 assert(_isErrorResponse(response)); 402 assert(_isErrorResponse(response));
385 switch (response[_FileUtils.kErrorResponseErrorType]) { 403 switch (response[_FileUtils.kErrorResponseErrorType]) {
386 case _FileUtils.kIllegalArgumentResponse: 404 case _FileUtils.kIllegalArgumentResponse:
387 _reportError(new IllegalArgumentException()); 405 return new IllegalArgumentException();
388 break;
389 case _FileUtils.kOSErrorResponse: 406 case _FileUtils.kOSErrorResponse:
390 var err = new OSError(response[_FileUtils.kOSErrorResponseMessage], 407 var err = new OSError(response[_FileUtils.kOSErrorResponseMessage],
391 response[_FileUtils.kOSErrorResponseErrorCode]); 408 response[_FileUtils.kOSErrorResponseErrorCode]);
392 _reportError(new FileIOException(message, err)); 409 return new FileIOException(message, err);
393 break;
394 case _FileUtils.kFileClosedResponse: 410 case _FileUtils.kFileClosedResponse:
395 _reportError(new FileIOException("File closed")); 411 return new FileIOException("File closed");
396 break;
397 default: 412 default:
398 _reportError(new Exception("Unknown error")); 413 return new Exception("Unknown error");
399 break;
400 } 414 }
401 } 415 }
402
403 void set onError(void handler(e)) {
404 _onError = handler;
405 }
406
407 Function _onError;
408 } 416 }
409 417
410 // Class for encapsulating the native implementation of files. 418 // Class for encapsulating the native implementation of files.
411 class _File extends _FileBase implements File { 419 class _File extends _FileBase implements File {
412 // Constructor for file. 420 // Constructor for file.
413 _File(String this._name); 421 _File(String this._name);
414 422
415 void exists(void callback(bool exists)) { 423 Future<bool> exists() {
416 _ensureFileService(); 424 _ensureFileService();
425 Completer<bool> completer = new Completer<bool>();
417 List request = new List(2); 426 List request = new List(2);
418 request[0] = _FileUtils.kExistsRequest; 427 request[0] = _FileUtils.kExistsRequest;
419 request[1] = _name; 428 request[1] = _name;
420 _fileService.call(request).then((response) { 429 _fileService.call(request).then((response) {
421 if (_isErrorResponse(response)) { 430 if (_isErrorResponse(response)) {
422 _handleErrorResponse(response, "Cannot open file '$_name'"); 431 var e = _exceptionFromResponse(response, "Cannot open file '$_name'");
432 completer.completeException(e);
423 } else { 433 } else {
424 callback(response); 434 completer.complete(response);
425 } 435 }
426 }); 436 });
437 return completer.future;
427 } 438 }
428 439
429 bool existsSync() { 440 bool existsSync() {
430 return _FileUtils.checkedExists(_name); 441 return _FileUtils.checkedExists(_name);
431 } 442 }
432 443
433 void create(void callback()) { 444 Future<File> create() {
434 _ensureFileService(); 445 _ensureFileService();
446 Completer<File> completer = new Completer<File>();
435 List request = new List(2); 447 List request = new List(2);
436 request[0] = _FileUtils.kCreateRequest; 448 request[0] = _FileUtils.kCreateRequest;
437 request[1] = _name; 449 request[1] = _name;
438 _fileService.call(request).then((response) { 450 _fileService.call(request).then((response) {
439 if (_isErrorResponse(response)) { 451 if (_isErrorResponse(response)) {
440 _handleErrorResponse(response, "Cannot create file"); 452 var e = _exceptionFromResponse(response, "Cannot create file '$_name'");
453 completer.completeException(e);
441 } else { 454 } else {
442 callback(); 455 completer.complete(this);
443 } 456 }
444 }); 457 });
458 return completer.future;
445 } 459 }
446 460
447 void createSync() { 461 void createSync() {
448 bool created = _FileUtils.checkedCreate(_name); 462 bool created = _FileUtils.checkedCreate(_name);
449 if (!created) { 463 if (!created) {
450 throw new FileIOException("Cannot create file '$_name'"); 464 throw new FileIOException("Cannot create file '$_name'");
451 } 465 }
452 } 466 }
453 467
454 void delete(void callback()) { 468 Future<File> delete() {
455 _ensureFileService(); 469 _ensureFileService();
470 Completer<File> completer = new Completer<File>();
456 List request = new List(2); 471 List request = new List(2);
457 request[0] = _FileUtils.kDeleteRequest; 472 request[0] = _FileUtils.kDeleteRequest;
458 request[1] = _name; 473 request[1] = _name;
459 _fileService.call(request).then((response) { 474 _fileService.call(request).then((response) {
460 if (_isErrorResponse(response)) { 475 if (_isErrorResponse(response)) {
461 _handleErrorResponse(response, "Cannot delete file '$_name'"); 476 var e = _exceptionFromResponse(response, "Cannot delete file '$_name'");
477 completer.completeException(e);
462 } else { 478 } else {
463 callback(); 479 completer.complete(this);
464 } 480 }
465 }); 481 });
482 return completer.future;
466 } 483 }
467 484
468 void deleteSync() { 485 void deleteSync() {
469 _FileUtils.checkedDelete(_name); 486 _FileUtils.checkedDelete(_name);
470 } 487 }
471 488
472 void directory(void callback(Directory dir)) { 489 Future<Directory> directory() {
473 _ensureFileService(); 490 _ensureFileService();
491 Completer<Directory> completer = new Completer<Directory>();
474 List request = new List(2); 492 List request = new List(2);
475 request[0] = _FileUtils.kDirectoryRequest; 493 request[0] = _FileUtils.kDirectoryRequest;
476 request[1] = _name; 494 request[1] = _name;
477 _fileService.call(request).then((response) { 495 _fileService.call(request).then((response) {
478 if (_isErrorResponse(response)) { 496 if (_isErrorResponse(response)) {
479 _handleErrorResponse(response, "Cannot retrieve directory for file"); 497 var e = _exceptionFromResponse(response,
498 "Cannot retrieve directory for "
499 "file '$_name'");
500 completer.completeException(e);
480 } else { 501 } else {
481 callback(new Directory(response)); 502 completer.complete(new Directory(response));
482 } 503 }
483 }); 504 });
505 return completer.future;
484 } 506 }
485 507
486 Directory directorySync() { 508 Directory directorySync() {
487 _FileUtils.checkedDirectory(_name); 509 _FileUtils.checkedDirectory(_name);
488 return new Directory(_FileUtils.directory(_name)); 510 return new Directory(_FileUtils.directory(_name));
489 } 511 }
490 512
491 void open(FileMode mode, void callback(RandomAccessFile file)) { 513 Future<RandomAccessFile> open([FileMode mode = FileMode.READ]) {
492 _ensureFileService(); 514 _ensureFileService();
515 Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>();
493 if (mode != FileMode.READ && 516 if (mode != FileMode.READ &&
494 mode != FileMode.WRITE && 517 mode != FileMode.WRITE &&
495 mode != FileMode.APPEND) { 518 mode != FileMode.APPEND) {
496 _reportError(new IllegalArgumentException()); 519 new Timer(0, (t) {
497 return; 520 completer.completeException(new IllegalArgumentException());
521 });
522 return completer.future;
498 } 523 }
499 List request = new List(3); 524 List request = new List(3);
500 request[0] = _FileUtils.kOpenRequest; 525 request[0] = _FileUtils.kOpenRequest;
501 request[1] = _name; 526 request[1] = _name;
502 request[2] = mode._mode; // Direct int value for serialization. 527 request[2] = mode._mode; // Direct int value for serialization.
503 _fileService.call(request).then((response) { 528 _fileService.call(request).then((response) {
504 if (_isErrorResponse(response)) { 529 if (_isErrorResponse(response)) {
505 _handleErrorResponse(response, "Cannot open file '$_name'"); 530 var e = _exceptionFromResponse(response, "Cannot open file '$_name'");
531 completer.completeException(e);
506 } else { 532 } else {
507 callback(new _RandomAccessFile(response, _name)); 533 completer.complete(new _RandomAccessFile(response, _name));
508 } 534 }
509 }); 535 });
536 return completer.future;
510 } 537 }
511 538
512 void length(void callback(int length)) { 539 Future<int> length() {
513 _ensureFileService(); 540 _ensureFileService();
541 Completer<int> completer = new Completer<int>();
514 List request = new List(2); 542 List request = new List(2);
515 request[0] = _FileUtils.kLengthFromNameRequest; 543 request[0] = _FileUtils.kLengthFromNameRequest;
516 request[1] = _name; 544 request[1] = _name;
517 _fileService.call(request).then((response) { 545 _fileService.call(request).then((response) {
518 if (_isErrorResponse(response)) { 546 if (_isErrorResponse(response)) {
519 _handleErrorResponse(response, 547 var e = _exceptionFromResponse(response,
520 "Cannot retrieve length of file '$_name'"); 548 "Cannot retrieve length of "
549 "file '$_name'");
550 completer.completeException(e);
521 } else { 551 } else {
522 callback(response); 552 completer.complete(response);
523 } 553 }
524 }); 554 });
555 return completer.future;
525 } 556 }
526 557
527 int lengthSync() { 558 int lengthSync() {
528 var result = _FileUtils.checkedLengthFromName(_name); 559 var result = _FileUtils.checkedLengthFromName(_name);
529 if (result is OSError) { 560 if (result is OSError) {
530 throw new FileIOException("Cannot retrieve length of file '$_name'", 561 throw new FileIOException("Cannot retrieve length of file '$_name'",
531 result); 562 result);
532 } 563 }
533 return result; 564 return result;
534 } 565 }
(...skipping 11 matching lines...) Expand all
546 } 577 }
547 578
548 static RandomAccessFile _openStdioSync(int fd) { 579 static RandomAccessFile _openStdioSync(int fd) {
549 var id = _FileUtils.openStdio(fd); 580 var id = _FileUtils.openStdio(fd);
550 if (id == 0) { 581 if (id == 0) {
551 throw new FileIOException("Cannot open stdio file for: $fd"); 582 throw new FileIOException("Cannot open stdio file for: $fd");
552 } 583 }
553 return new _RandomAccessFile(id, ""); 584 return new _RandomAccessFile(id, "");
554 } 585 }
555 586
556 void fullPath(void callback(String result)) { 587 Future<String> fullPath() {
557 _ensureFileService(); 588 _ensureFileService();
589 Completer<String> completer = new Completer<String>();
558 List request = new List(2); 590 List request = new List(2);
559 request[0] = _FileUtils.kFullPathRequest; 591 request[0] = _FileUtils.kFullPathRequest;
560 request[1] = _name; 592 request[1] = _name;
561 _fileService.call(request).then((response) { 593 _fileService.call(request).then((response) {
562 if (_isErrorResponse(response)) { 594 if (_isErrorResponse(response)) {
563 _handleErrorResponse(response, "Cannot retrieve full path"); 595 var e = _exceptionFromResponse(response,
596 "Cannot retrieve full path"
597 " for '$_name'");
598 completer.completeException(e);
564 } else { 599 } else {
565 callback(response); 600 completer.complete(response);
566 } 601 }
567 }); 602 });
603 return completer.future;
568 } 604 }
569 605
570 String fullPathSync() { 606 String fullPathSync() {
571 return _FileUtils.checkedFullPath(_name); 607 return _FileUtils.checkedFullPath(_name);
572 } 608 }
573 609
574 InputStream openInputStream() { 610 InputStream openInputStream() {
575 return new _FileInputStream(_name); 611 return new _FileInputStream(_name);
576 } 612 }
577 613
578 OutputStream openOutputStream([FileMode mode = FileMode.WRITE]) { 614 OutputStream openOutputStream([FileMode mode = FileMode.WRITE]) {
579 if (mode != FileMode.WRITE && 615 if (mode != FileMode.WRITE &&
580 mode != FileMode.APPEND) { 616 mode != FileMode.APPEND) {
581 throw new FileIOException( 617 throw new FileIOException(
582 "Wrong FileMode. Use FileMode.WRITE or FileMode.APPEND"); 618 "Wrong FileMode. Use FileMode.WRITE or FileMode.APPEND");
583 } 619 }
584 return new _FileOutputStream(_name, mode); 620 return new _FileOutputStream(_name, mode);
585 } 621 }
586 622
587 void readAsBytes(void callback(List<int> bytes)) { 623 Future<List<int>> readAsBytes() {
588 _ensureFileService(); 624 _ensureFileService();
625 Completer<List<int>> completer = new Completer<List<int>>();
589 var chunks = new _BufferList(); 626 var chunks = new _BufferList();
590 var stream = openInputStream(); 627 var stream = openInputStream();
591 stream.onClosed = () { 628 stream.onClosed = () {
592 callback(chunks.readBytes(chunks.length)); 629 completer.complete(chunks.readBytes(chunks.length));
593 }; 630 };
594 stream.onData = () { 631 stream.onData = () {
595 var chunk = stream.read(); 632 var chunk = stream.read();
596 chunks.add(chunk); 633 chunks.add(chunk);
597 }; 634 };
598 stream.onError = (e) => _reportError(e); 635 stream.onError = completer.completeException;
636 return completer.future;
599 } 637 }
600 638
601 List<int> readAsBytesSync() { 639 List<int> readAsBytesSync() {
602 var opened = openSync(); 640 var opened = openSync();
603 var length = opened.lengthSync(); 641 var length = opened.lengthSync();
604 var result = new Uint8List(length); 642 var result = new Uint8List(length);
605 var read = opened.readListSync(result, 0, length); 643 var read = opened.readListSync(result, 0, length);
606 if (read != length) { 644 if (read != length) {
607 throw new FileIOException("Failed to read file"); 645 throw new FileIOException("Failed to read file");
608 } 646 }
609 opened.closeSync(); 647 opened.closeSync();
610 return result; 648 return result;
611 } 649 }
612 650
613 void readAsText(Encoding encoding, void callback(String text)) { 651 Future<String> readAsText([Encoding encoding = Encoding.UTF_8]) {
614 _ensureFileService(); 652 _ensureFileService();
615 var decoder = _StringDecoders.decoder(encoding); 653 var decoder = _StringDecoders.decoder(encoding);
616 readAsBytes((bytes) { 654 return readAsBytes().transform((bytes) {
617 try { 655 decoder.write(bytes);
618 decoder.write(bytes); 656 return decoder.decoded;
619 } catch (var e) {
620 _reportError(e);
621 return;
622 }
623 callback(decoder.decoded);
624 }); 657 });
625 } 658 }
626 659
627 String readAsTextSync([Encoding encoding = Encoding.UTF_8]) { 660 String readAsTextSync([Encoding encoding = Encoding.UTF_8]) {
628 var decoder = _StringDecoders.decoder(encoding); 661 var decoder = _StringDecoders.decoder(encoding);
629 List<int> bytes = readAsBytesSync(); 662 List<int> bytes = readAsBytesSync();
630 decoder.write(bytes); 663 decoder.write(bytes);
631 return decoder.decoded; 664 return decoder.decoded;
632 } 665 }
633 666
634 List<String> _getDecodedLines(_StringDecoder decoder) { 667 List<String> _getDecodedLines(_StringDecoder decoder) {
635 List<String> result = []; 668 List<String> result = [];
636 var line = decoder.decodedLine; 669 var line = decoder.decodedLine;
637 while (line != null) { 670 while (line != null) {
638 result.add(line); 671 result.add(line);
639 line = decoder.decodedLine; 672 line = decoder.decodedLine;
640 } 673 }
641 // If there is more data with no terminating line break we treat 674 // If there is more data with no terminating line break we treat
642 // it as the last line. 675 // it as the last line.
643 var data = decoder.decoded; 676 var data = decoder.decoded;
644 if (data != null) { 677 if (data != null) {
645 result.add(data); 678 result.add(data);
646 } 679 }
647 return result; 680 return result;
648 } 681 }
649 682
650 void readAsLines(Encoding encoding, void callback(List<String> lines)) { 683 Future<List<String>> readAsLines([Encoding encoding = Encoding.UTF_8]) {
651 _ensureFileService(); 684 _ensureFileService();
685 Completer<List<String>> completer = new Completer<List<String>>();
652 var decoder = _StringDecoders.decoder(encoding); 686 var decoder = _StringDecoders.decoder(encoding);
653 readAsBytes((bytes) { 687 return readAsBytes().transform((bytes) {
654 try { 688 decoder.write(bytes);
655 decoder.write(bytes); 689 return _getDecodedLines(decoder);
656 } catch (var e) {
657 _reportError(e);
658 return;
659 }
660 callback(_getDecodedLines(decoder));
661 }); 690 });
662 } 691 }
663 692
664 List<String> readAsLinesSync([Encoding encoding = Encoding.UTF_8]) { 693 List<String> readAsLinesSync([Encoding encoding = Encoding.UTF_8]) {
665 var decoder = _StringDecoders.decoder(encoding); 694 var decoder = _StringDecoders.decoder(encoding);
666 List<int> bytes = readAsBytesSync(); 695 List<int> bytes = readAsBytesSync();
667 decoder.write(bytes); 696 decoder.write(bytes);
668 return _getDecodedLines(decoder); 697 return _getDecodedLines(decoder);
669 } 698 }
670 699
671 String get name() => _name; 700 String get name() => _name;
672 701
673 void _ensureFileService() { 702 void _ensureFileService() {
674 if (_fileService == null) { 703 if (_fileService == null) {
675 _fileService = _FileUtils.newServicePort(); 704 _fileService = _FileUtils.newServicePort();
676 } 705 }
677 } 706 }
678 707
679 String _name; 708 final String _name;
680 709
681 SendPort _fileService; 710 SendPort _fileService;
682 } 711 }
683 712
684 713
685 class _RandomAccessFile extends _FileBase implements RandomAccessFile { 714 class _RandomAccessFile extends _FileBase implements RandomAccessFile {
686 _RandomAccessFile(int this._id, String this._name); 715 _RandomAccessFile(int this._id, String this._name);
687 716
688 void close(void callback()) { 717 Future<RandomAccessFile> close() {
718 Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>();
689 if (_id == 0) { 719 if (_id == 0) {
690 _reportError(new FileIOException("Cannot close file '$_name'")); 720 // Complete asynchronously so the user has a chance to setup
691 return; 721 // handlers without getting exceptions when registering the
722 // then handler.
723 new Timer(0, (t) {
724 completer.completeException(
725 new FileIOException("Cannot close file '$_name'"));
726 });
727 return completer.future;
692 } 728 }
693 _ensureFileService(); 729 _ensureFileService();
694 List request = new List(2); 730 List request = new List(2);
695 request[0] = _FileUtils.kCloseRequest; 731 request[0] = _FileUtils.kCloseRequest;
696 request[1] = _id; 732 request[1] = _id;
697 // Set the id_ to 0 (NULL) to ensure the no more async requests 733 // Set the id_ to 0 (NULL) to ensure the no more async requests
698 // can be issues for this file. 734 // can be issues for this file.
699 _id = 0; 735 _id = 0;
700 _fileService.call(request).then((result) { 736 _fileService.call(request).then((result) {
701 if (result != -1) { 737 if (result != -1) {
702 _id = result; 738 _id = result;
703 callback(); 739 completer.complete(this);
704 } else { 740 } else {
705 _reportError(new FileIOException("Cannot close file '$_name'")); 741 completer.completeException(
742 new FileIOException("Cannot close file '$_name'"));
706 } 743 }
707 }); 744 });
745 return completer.future;
708 } 746 }
709 747
710 void closeSync() { 748 void closeSync() {
711 var id = _FileUtils.close(_id); 749 var id = _FileUtils.close(_id);
712 if (id == -1) { 750 if (id == -1) {
713 throw new FileIOException("Cannot close file '$_name'"); 751 throw new FileIOException("Cannot close file '$_name'");
714 } 752 }
715 _id = id; 753 _id = id;
716 } 754 }
717 755
718 void readByte(void callback(int byte)) { 756 Future<int> readByte() {
719 _ensureFileService(); 757 _ensureFileService();
758 Completer<int> completer = new Completer<int>();
720 List request = new List(2); 759 List request = new List(2);
721 request[0] = _FileUtils.kReadByteRequest; 760 request[0] = _FileUtils.kReadByteRequest;
722 request[1] = _id; 761 request[1] = _id;
723 _fileService.call(request).then((response) { 762 _fileService.call(request).then((response) {
724 if (_isErrorResponse(response)) { 763 if (_isErrorResponse(response)) {
725 _handleErrorResponse(response, "readByte failed for file '$_name'"); 764 var e = _exceptionFromResponse(response,
765 "readByte failed for file '$_name'");
766 completer.completeException(e);
726 } else { 767 } else {
727 callback(response); 768 completer.complete(response);
728 } 769 }
729 }); 770 });
771 return completer.future;
730 } 772 }
731 773
732 int readByteSync() { 774 int readByteSync() {
733 _checkNotClosed(); 775 _checkNotClosed();
734 var result = _FileUtils.readByte(_id); 776 var result = _FileUtils.readByte(_id);
735 if (result is OSError) { 777 if (result is OSError) {
736 throw new FileIOException("readByte failed for file '$_name'", result); 778 throw new FileIOException("readByte failed for file '$_name'", result);
737 } 779 }
738 return result; 780 return result;
739 } 781 }
740 782
741 void readList(List<int> buffer, int offset, int bytes, 783 Future<int> readList(List<int> buffer, int offset, int bytes) {
742 void callback(int read)) {
743 _ensureFileService(); 784 _ensureFileService();
785 Completer<int> completer = new Completer<int>();
744 if (buffer is !List || offset is !int || bytes is !int) { 786 if (buffer is !List || offset is !int || bytes is !int) {
745 _reportError(new FileIOException( 787 // Complete asynchronously so the user has a chance to setup
746 "Invalid arguments to readList for file '$_name'")); 788 // handlers without getting exceptions when registering the
747 return; 789 // then handler.
790 new Timer(0, (t) {
791 completer.completeException(new FileIOException(
792 "Invalid arguments to readList for file '$_name'"));
793 });
794 return completer.future;
748 }; 795 };
749 List request = new List(3); 796 List request = new List(3);
750 request[0] = _FileUtils.kReadListRequest; 797 request[0] = _FileUtils.kReadListRequest;
751 request[1] = _id; 798 request[1] = _id;
752 request[2] = bytes; 799 request[2] = bytes;
753 _fileService.call(request).then((response) { 800 _fileService.call(request).then((response) {
754 if (_isErrorResponse(response)) { 801 if (_isErrorResponse(response)) {
755 _handleErrorResponse(response, "readList failed for file '$_name'"); 802 var e = _exceptionFromResponse(response,
803 "readList failed for file '$_name'");
804 completer.completeException(e);
756 } else { 805 } else {
757 var read = response[1]; 806 var read = response[1];
758 var data = response[2]; 807 var data = response[2];
759 buffer.setRange(offset, read, data); 808 buffer.setRange(offset, read, data);
760 callback(read); 809 completer.complete(read);
761 } 810 }
762 }); 811 });
812 return completer.future;
763 } 813 }
764 814
765 int readListSync(List<int> buffer, int offset, int bytes) { 815 int readListSync(List<int> buffer, int offset, int bytes) {
766 _checkNotClosed(); 816 _checkNotClosed();
767 if (buffer is !List || offset is !int || bytes is !int) { 817 if (buffer is !List || offset is !int || bytes is !int) {
768 throw new FileIOException( 818 throw new FileIOException(
769 "Invalid arguments to readList for file '$_name'"); 819 "Invalid arguments to readList for file '$_name'");
770 } 820 }
771 if (bytes == 0) return 0; 821 if (bytes == 0) return 0;
772 int index = 822 int index =
773 _FileUtils.checkReadWriteListArguments(buffer.length, offset, bytes); 823 _FileUtils.checkReadWriteListArguments(buffer.length, offset, bytes);
774 if (index != 0) { 824 if (index != 0) {
775 throw new IndexOutOfRangeException(index); 825 throw new IndexOutOfRangeException(index);
776 } 826 }
777 var result = _FileUtils.readList(_id, buffer, offset, bytes); 827 var result = _FileUtils.readList(_id, buffer, offset, bytes);
778 if (result is OSError) { 828 if (result is OSError) {
779 throw new FileIOException("readList failed for file '$_name'", 829 throw new FileIOException("readList failed for file '$_name'",
780 result); 830 result);
781 } 831 }
782 return result; 832 return result;
783 } 833 }
784 834
785 void writeByte(int value) { 835 Future<RandomAccessFile> writeByte(int value) {
786 _ensureFileService(); 836 _ensureFileService();
837 Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>();
787 if (value is !int) { 838 if (value is !int) {
788 _reportError(new FileIOException( 839 // Complete asynchronously so the user has a chance to setup
789 "Invalid argument to writeByte for file '$_name'")); 840 // handlers without getting exceptions when registering the
790 return; 841 // then handler.
842 new Timer(0, (t) {
843 completer.completeException(new FileIOException(
844 "Invalid argument to writeByte for file '$_name'"));
845 });
846 return completer.future;
791 } 847 }
792 List request = new List(3); 848 List request = new List(3);
793 request[0] = _FileUtils.kWriteByteRequest; 849 request[0] = _FileUtils.kWriteByteRequest;
794 request[1] = _id; 850 request[1] = _id;
795 request[2] = value; 851 request[2] = value;
796 _writeEnqueued();
797 _fileService.call(request).then((response) { 852 _fileService.call(request).then((response) {
798 _writeCompleted();
799 if (_isErrorResponse(response)) { 853 if (_isErrorResponse(response)) {
800 _handleErrorResponse(response, "writeByte failed for file '$_name'"); 854 var e = _exceptionFromResponse(response,
855 "writeByte failed for file '$_name'");
856 completer.completeException(e);
857 } else {
858 completer.complete(this);
801 } 859 }
802 }); 860 });
861 return completer.future;
803 } 862 }
804 863
805 int writeByteSync(int value) { 864 int writeByteSync(int value) {
806 _checkNotClosed(); 865 _checkNotClosed();
807 if (value is !int) { 866 if (value is !int) {
808 throw new FileIOException( 867 throw new FileIOException(
809 "Invalid argument to writeByte for file '$_name'"); 868 "Invalid argument to writeByte for file '$_name'");
810 } 869 }
811 var result = _FileUtils.writeByte(_id, value); 870 var result = _FileUtils.writeByte(_id, value);
812 if (result is OSError) { 871 if (result is OSError) {
813 throw new FileIOException("writeByte failed for file '$_name'", 872 throw new FileIOException("writeByte failed for file '$_name'",
814 result); 873 result);
815 } 874 }
816 return result; 875 return result;
817 } 876 }
818 877
819 void writeList(List<int> buffer, int offset, int bytes) { 878 Future<RandomAccessFile> writeList(List<int> buffer, int offset, int bytes) {
820 _ensureFileService(); 879 _ensureFileService();
880 Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>();
821 if (buffer is !List || offset is !int || bytes is !int) { 881 if (buffer is !List || offset is !int || bytes is !int) {
822 _reportError(new FileIOException( 882 // Complete asynchronously so the user has a chance to setup
883 // handlers without getting exceptions when registering the
884 // then handler.
885 new Timer(0, (t) {
886 completer.completeException(new FileIOException(
823 "Invalid arguments to writeList for file '$_name'")); 887 "Invalid arguments to writeList for file '$_name'"));
824 return; 888 });
889 return completer.future;
825 } 890 }
826 891
827 List result = 892 List result =
828 _FileUtils.ensureFastAndSerializableBuffer(buffer, offset, bytes); 893 _FileUtils.ensureFastAndSerializableBuffer(buffer, offset, bytes);
829 List outBuffer = result[0]; 894 List outBuffer = result[0];
830 int outOffset = result[1]; 895 int outOffset = result[1];
831 896
832 List request = new List(5); 897 List request = new List(5);
833 request[0] = _FileUtils.kWriteListRequest; 898 request[0] = _FileUtils.kWriteListRequest;
834 request[1] = _id; 899 request[1] = _id;
835 request[2] = outBuffer; 900 request[2] = outBuffer;
836 request[3] = outOffset; 901 request[3] = outOffset;
837 request[4] = bytes; 902 request[4] = bytes;
838 _writeEnqueued();
839 _fileService.call(request).then((response) { 903 _fileService.call(request).then((response) {
840 _writeCompleted();
841 if (_isErrorResponse(response)) { 904 if (_isErrorResponse(response)) {
842 _handleErrorResponse(response, "writeList failed for file '$_name'"); 905 var e = _exceptionFromResponse(response,
906 "writeList failed for file '$_name'");
907 completer.completeException(e);
908 } else {
909 completer.complete(this);
843 } 910 }
844 }); 911 });
912 return completer.future;
845 } 913 }
846 914
847 int writeListSync(List<int> buffer, int offset, int bytes) { 915 int writeListSync(List<int> buffer, int offset, int bytes) {
848 _checkNotClosed(); 916 _checkNotClosed();
849 if (buffer is !List || offset is !int || bytes is !int) { 917 if (buffer is !List || offset is !int || bytes is !int) {
850 throw new FileIOException( 918 throw new FileIOException(
851 "Invalid arguments to writeList for file '$_name'"); 919 "Invalid arguments to writeList for file '$_name'");
852 } 920 }
853 if (bytes == 0) return 0; 921 if (bytes == 0) return 0;
854 int index = 922 int index =
855 _FileUtils.checkReadWriteListArguments(buffer.length, offset, bytes); 923 _FileUtils.checkReadWriteListArguments(buffer.length, offset, bytes);
856 if (index != 0) { 924 if (index != 0) {
857 throw new IndexOutOfRangeException(index); 925 throw new IndexOutOfRangeException(index);
858 } 926 }
859 var result = _FileUtils.writeList(_id, buffer, offset, bytes); 927 var result = _FileUtils.writeList(_id, buffer, offset, bytes);
860 if (result is OSError) { 928 if (result is OSError) {
861 throw new FileIOException("writeList failed for file '$_name'", result); 929 throw new FileIOException("writeList failed for file '$_name'", result);
862 } 930 }
863 return result; 931 return result;
864 } 932 }
865 933
866 void writeString(String string, [Encoding encoding = Encoding.UTF_8]) { 934 Future<RandomAccessFile> writeString(String string,
935 [Encoding encoding = Encoding.UTF_8]) {
867 _ensureFileService(); 936 _ensureFileService();
937 Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>();
868 List request = new List(3); 938 List request = new List(3);
869 request[0] = _FileUtils.kWriteStringRequest; 939 request[0] = _FileUtils.kWriteStringRequest;
870 request[1] = _id; 940 request[1] = _id;
871 request[2] = string; 941 request[2] = string;
872 _writeEnqueued();
873 _fileService.call(request).then((response) { 942 _fileService.call(request).then((response) {
874 _writeCompleted();
875 if (_isErrorResponse(response)) { 943 if (_isErrorResponse(response)) {
876 _handleErrorResponse(response, "writeString failed for file '$_name'"); 944 var e = _exceptionFromResponse(response,
945 "writeString failed for file '$_name'");
946 completer.completeException(e);
947 } else {
948 completer.complete(this);
877 } 949 }
878 }); 950 });
951 return completer.future;
879 } 952 }
880 953
881 int writeStringSync(String string, [Encoding encoding = Encoding.UTF_8]) { 954 int writeStringSync(String string, [Encoding encoding = Encoding.UTF_8]) {
882 _checkNotClosed(); 955 _checkNotClosed();
883 var result = _FileUtils.checkedWriteString(_id, string); 956 var result = _FileUtils.checkedWriteString(_id, string);
884 if (result is OSError) { 957 if (result is OSError) {
885 throw new FileIOException("writeString failed for file '$_name'", result); 958 throw new FileIOException("writeString failed for file '$_name'", result);
886 } 959 }
887 return result; 960 return result;
888 } 961 }
889 962
890 void position(void callback(int position)) { 963 Future<int> position() {
891 _ensureFileService(); 964 _ensureFileService();
965 Completer<int> completer = new Completer<int>();
892 List request = new List(2); 966 List request = new List(2);
893 request[0] = _FileUtils.kPositionRequest; 967 request[0] = _FileUtils.kPositionRequest;
894 request[1] = _id; 968 request[1] = _id;
895 _fileService.call(request).then((response) { 969 _fileService.call(request).then((response) {
896 if (_isErrorResponse(response)) { 970 if (_isErrorResponse(response)) {
897 _handleErrorResponse(response, "position failed for file '$_name'"); 971 var e = _exceptionFromResponse(response,
972 "position failed for file '$_name'");
973 completer.completeException(e);
898 } else { 974 } else {
899 callback(response); 975 completer.complete(response);
900 } 976 }
901 }); 977 });
978 return completer.future;
902 } 979 }
903 980
904 int positionSync() { 981 int positionSync() {
905 _checkNotClosed(); 982 _checkNotClosed();
906 var result = _FileUtils.position(_id); 983 var result = _FileUtils.position(_id);
907 if (result is OSError) { 984 if (result is OSError) {
908 throw new FileIOException("position failed for file '$_name'", result); 985 throw new FileIOException("position failed for file '$_name'", result);
909 } 986 }
910 return result; 987 return result;
911 } 988 }
912 989
913 void setPosition(int position, void callback()) { 990 Future<RandomAccessFile> setPosition(int position) {
914 _ensureFileService(); 991 _ensureFileService();
992 Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>();
915 List request = new List(3); 993 List request = new List(3);
916 request[0] = _FileUtils.kSetPositionRequest; 994 request[0] = _FileUtils.kSetPositionRequest;
917 request[1] = _id; 995 request[1] = _id;
918 request[2] = position; 996 request[2] = position;
919 _fileService.call(request).then((response) { 997 _fileService.call(request).then((response) {
920 if (_isErrorResponse(response)) { 998 if (_isErrorResponse(response)) {
921 _handleErrorResponse(response, "setPosition failed for file '$_name'"); 999 var e = _exceptionFromResponse(response,
1000 "setPosition failed for file '$_name'");
1001 completer.completeException(e);
922 } else { 1002 } else {
923 callback(); 1003 completer.complete(this);
924 } 1004 }
925 }); 1005 });
1006 return completer.future;
926 } 1007 }
927 1008
928 void setPositionSync(int position) { 1009 void setPositionSync(int position) {
929 _checkNotClosed(); 1010 _checkNotClosed();
930 var result = _FileUtils.setPosition(_id, position); 1011 var result = _FileUtils.setPosition(_id, position);
931 if (result is OSError) { 1012 if (result is OSError) {
932 throw new FileIOException("setPosition failed for file '$_name'", result); 1013 throw new FileIOException("setPosition failed for file '$_name'", result);
933 } 1014 }
934 } 1015 }
935 1016
936 void truncate(int length, void callback()) { 1017 Future<RandomAccessFile> truncate(int length) {
937 _ensureFileService(); 1018 _ensureFileService();
1019 Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>();
938 List request = new List(3); 1020 List request = new List(3);
939 request[0] = _FileUtils.kTruncateRequest; 1021 request[0] = _FileUtils.kTruncateRequest;
940 request[1] = _id; 1022 request[1] = _id;
941 request[2] = length; 1023 request[2] = length;
942 _fileService.call(request).then((response) { 1024 _fileService.call(request).then((response) {
943 if (_isErrorResponse(response)) { 1025 if (_isErrorResponse(response)) {
944 _handleErrorResponse(response, "truncate failed for file '$_name'"); 1026 var e = _exceptionFromResponse(response,
1027 "truncate failed for file '$_name'");
1028 completer.completeException(e);
945 } else { 1029 } else {
946 callback(); 1030 completer.complete(this);
947 } 1031 }
948 }); 1032 });
1033 return completer.future;
949 } 1034 }
950 1035
951 void truncateSync(int length) { 1036 void truncateSync(int length) {
952 _checkNotClosed(); 1037 _checkNotClosed();
953 var result = _FileUtils.truncate(_id, length); 1038 var result = _FileUtils.truncate(_id, length);
954 if (result is OSError) { 1039 if (result is OSError) {
955 throw new FileIOException("truncate failed for file '$_name'", result); 1040 throw new FileIOException("truncate failed for file '$_name'", result);
956 } 1041 }
957 } 1042 }
958 1043
959 void length(void callback(int length)) { 1044 Future<int> length() {
960 _ensureFileService(); 1045 _ensureFileService();
1046 Completer<int> completer = new Completer<int>();
961 List request = new List(2); 1047 List request = new List(2);
962 request[0] = _FileUtils.kLengthRequest; 1048 request[0] = _FileUtils.kLengthRequest;
963 request[1] = _id; 1049 request[1] = _id;
964 _fileService.call(request).then((response) { 1050 _fileService.call(request).then((response) {
965 if (_isErrorResponse(response)) { 1051 if (_isErrorResponse(response)) {
966 _handleErrorResponse(response, "length failed for file '$_name'"); 1052 var e = _exceptionFromResponse(response,
1053 "length failed for file '$_name'");
1054 completer.completeException(e);
967 } else { 1055 } else {
968 callback(response); 1056 completer.complete(response);
969 } 1057 }
970 }); 1058 });
1059 return completer.future;
971 } 1060 }
972 1061
973 int lengthSync() { 1062 int lengthSync() {
974 _checkNotClosed(); 1063 _checkNotClosed();
975 var result = _FileUtils.length(_id); 1064 var result = _FileUtils.length(_id);
976 if (result is OSError) { 1065 if (result is OSError) {
977 throw new FileIOException("length failed for file '$_name'", result); 1066 throw new FileIOException("length failed for file '$_name'", result);
978 } 1067 }
979 return result; 1068 return result;
980 } 1069 }
981 1070
982 void flush(void callback()) { 1071 Future<RandomAccessFile> flush() {
983 _ensureFileService(); 1072 _ensureFileService();
1073 Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>();
984 List request = new List(2); 1074 List request = new List(2);
985 request[0] = _FileUtils.kFlushRequest; 1075 request[0] = _FileUtils.kFlushRequest;
986 request[1] = _id; 1076 request[1] = _id;
987 _fileService.call(request).then((response) { 1077 _fileService.call(request).then((response) {
988 if (_isErrorResponse(response)) { 1078 if (_isErrorResponse(response)) {
989 _handleErrorResponse(response, "flush failed for file '$_name'"); 1079 var e = _exceptionFromResponse(response,
1080 "flush failed for file '$_name'");
1081 completer.completeException(e);
990 } else { 1082 } else {
991 callback(); 1083 completer.complete(this);
992 } 1084 }
993 }); 1085 });
1086 return completer.future;
994 } 1087 }
995 1088
996 void flushSync() { 1089 void flushSync() {
997 _checkNotClosed(); 1090 _checkNotClosed();
998 var result = _FileUtils.flush(_id); 1091 var result = _FileUtils.flush(_id);
999 if (result is OSError) { 1092 if (result is OSError) {
1000 throw new FileIOException("flush failed for file '$_name'", result); 1093 throw new FileIOException("flush failed for file '$_name'", result);
1001 } 1094 }
1002 } 1095 }
1003 1096
1004 String get name() => _name; 1097 String get name() => _name;
1005 1098
1006 void set onNoPendingWrites(void handler()) {
1007 _onNoPendingWrites = handler;
1008 if (_pendingWrites == 0) {
1009 _noPendingWriteTimer = new Timer(0, (t) {
1010 if (_onNoPendingWrites != null) _onNoPendingWrites();
1011 });
1012 }
1013 }
1014
1015 void _ensureFileService() { 1099 void _ensureFileService() {
1016 if (_fileService == null) { 1100 if (_fileService == null) {
1017 _fileService = _FileUtils.newServicePort(); 1101 _fileService = _FileUtils.newServicePort();
1018 } 1102 }
1019 } 1103 }
1020 1104
1021 void _writeEnqueued() {
1022 _pendingWrites++;
1023 if (_noPendingWriteTimer != null) {
1024 _noPendingWriteTimer.cancel();
1025 _noPendingWriteTimer = null;
1026 }
1027 }
1028
1029 void _writeCompleted() {
1030 _pendingWrites--;
1031 if (_pendingWrites == 0 && _onNoPendingWrites != null) {
1032 _onNoPendingWrites();
1033 }
1034 }
1035
1036 void _checkNotClosed() { 1105 void _checkNotClosed() {
1037 if (_id == 0) { 1106 if (_id == 0) {
1038 throw new FileIOException("File closed '$_name'"); 1107 throw new FileIOException("File closed '$_name'");
1039 } 1108 }
1040 } 1109 }
1041 1110
1042 String _name; 1111 final String _name;
1043 int _id; 1112 int _id;
1044 int _pendingWrites = 0;
1045 1113
1046 SendPort _fileService; 1114 SendPort _fileService;
1047
1048 Timer _noPendingWriteTimer;
1049
1050 Function _onNoPendingWrites;
1051 } 1115 }
OLDNEW
« no previous file with comments | « runtime/bin/file.dart ('k') | runtime/bin/process.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698