Chromium Code Reviews| Index: runtime/bin/file_impl.dart |
| diff --git a/runtime/bin/file_impl.dart b/runtime/bin/file_impl.dart |
| index fc966cf941b9c4ccf82c78e667093e2792daf50c..f7c3ce89a00f9a38dafaa1925f4f37688efbc0e9 100644 |
| --- a/runtime/bin/file_impl.dart |
| +++ b/runtime/bin/file_impl.dart |
| @@ -7,9 +7,12 @@ class _FileInputStream extends _BaseDataInputStream implements InputStream { |
| var file = new File(name); |
| _data = []; |
| _position = 0; |
| - file.onError = _reportError; |
| - file.open(FileMode.READ, (openedFile) { |
| - _readDataFromFile(openedFile); |
| + var chained = file.open(FileMode.READ).chain((openedFile) { |
| + return _readDataFromFile(openedFile); |
| + }); |
| + chained.handleException((e) { |
| + _reportError(e); |
| + return true; |
| }); |
| } |
| @@ -18,31 +21,35 @@ class _FileInputStream extends _BaseDataInputStream implements InputStream { |
| var file = _File._openStdioSync(fd); |
| _data = []; |
| _position = 0; |
| - _readDataFromFile(file); |
| + _readDataFromFile(file).handleException((e) { |
| + _reportError(e); |
| + return true; |
| + }); |
| } |
| - void _readDataFromFile(RandomAccessFile openedFile) { |
| - openedFile.onError = _reportError; |
| - openedFile.length((length) { |
| + Future<RandomAccessFile> _closeAfterRead(RandomAccessFile openedFile) { |
| + return openedFile.close().transform((ignore) { |
| + _streamMarkedClosed = true; |
| + _checkScheduleCallbacks(); |
| + return openedFile; |
| + }); |
| + } |
| + |
| + Future<RandomAccessFile> _readDataFromFile(RandomAccessFile openedFile) { |
| + return openedFile.length().chain((length) { |
| var contents = new Uint8List(length); |
| if (length != 0) { |
| - openedFile.readList(contents, 0, length, (read) { |
| + return openedFile.readList(contents, 0, length).chain((read) { |
| if (read != length) { |
| - _reportError(new FileIOException( |
| - 'Failed reading file contents in FileInputStream')); |
| + throw new FileIOException( |
| + 'Failed reading file contents in FileInputStream'); |
| } else { |
| _data = contents; |
| } |
| - openedFile.close(() { |
| - _streamMarkedClosed = true; |
| - _checkScheduleCallbacks(); |
| - }); |
| + return _closeAfterRead(openedFile); |
| }); |
| } else { |
| - openedFile.close(() { |
| - _streamMarkedClosed = true; |
| - _checkScheduleCallbacks(); |
| - }); |
| + return _closeAfterRead(openedFile); |
| } |
| }); |
| } |
| @@ -85,28 +92,20 @@ class _FileOutputStream extends _BaseOutputStream implements OutputStream { |
| _FileOutputStream(String name, FileMode mode) { |
| _pendingOperations = new List<List<int>>(); |
| var f = new File(name); |
| - f.open(mode, (openedFile) { |
| + var openFuture = f.open(mode); |
| + openFuture.then((openedFile) { |
| _file = openedFile; |
| - _setupFileHandlers(); |
| _processPendingOperations(); |
| }); |
| - f.onError = _reportError; |
| + openFuture.handleException((e) { |
| + _reportError(e); |
| + return true; |
| + }); |
| } |
| _FileOutputStream.fromStdio(int fd) { |
| assert(1 <= fd && fd <= 2); |
| _file = _File._openStdioSync(fd); |
| - _setupFileHandlers(); |
| - } |
| - |
| - |
| - void _setupFileHandlers() { |
| - _file.onError = _reportError; |
| - _file.onNoPendingWrites = () { |
| - if (!_streamMarkedClosed && _onNoPendingWrites != null) { |
| - _onNoPendingWrites(); |
| - } |
| - }; |
| } |
| bool write(List<int> buffer, [bool copyBuffer = false]) { |
| @@ -140,7 +139,7 @@ class _FileOutputStream extends _BaseOutputStream implements OutputStream { |
| if (_file == null) { |
| _pendingOperations.add(null); |
| } else if (!_streamMarkedClosed) { |
| - _file.close(() { |
| + _file.close().then((ignore) { |
| if (_onClosed != null) _onClosed(); |
| }); |
| _streamMarkedClosed = true; |
| @@ -149,6 +148,12 @@ class _FileOutputStream extends _BaseOutputStream implements OutputStream { |
| void set onNoPendingWrites(void callback()) { |
| _onNoPendingWrites = callback; |
| + if (((_pendingOperations == null) || (_pendingOperations.length == 0)) && |
| + (outstandingWrites == 0) && |
| + !_streamMarkedClosed && |
| + (_onNoPendingWrites != null)) { |
| + _onNoPendingWrites(); |
|
Søren Gjesse
2012/05/10 11:24:45
Call this on the event loop using a Timer.
Mads Ager (google)
2012/05/10 12:42:38
Done.
|
| + } |
| } |
| void set onClosed(void callback()) { |
| @@ -163,7 +168,21 @@ class _FileOutputStream extends _BaseOutputStream implements OutputStream { |
| } |
| void _write(List<int> buffer, int offset, int len) { |
| - _file.writeList(buffer, offset, len); |
| + outstandingWrites++; |
| + var writeListFuture = _file.writeList(buffer, offset, len); |
| + writeListFuture.then((ignore) { |
| + outstandingWrites--; |
| + if ((outstandingWrites == 0) && |
| + !_streamMarkedClosed && |
| + (_onNoPendingWrites != null)) { |
| + _onNoPendingWrites(); |
| + } |
| + }); |
| + writeListFuture.handleException((e) { |
| + outstandingWrites--; |
| + _reportError(e); |
| + return true; |
| + }); |
| } |
| RandomAccessFile _file; |
| @@ -176,6 +195,9 @@ class _FileOutputStream extends _BaseOutputStream implements OutputStream { |
| // the stream is fully closed. |
| bool _closeCallbackCalled = false; |
| + // Number of writes that have not yet completed. |
| + int outstandingWrites = 0; |
| + |
| // List of pending writes that were issued before the underlying |
| // file was successfully opened. |
| List<List<int>> _pendingOperations; |
| @@ -368,43 +390,25 @@ class _FileUtils { |
| // Base class for _File and _RandomAccessFile with shared functions. |
| class _FileBase { |
| - void _reportError(e) { |
| - if (_onError != null) { |
| - _onError(e); |
| - } else { |
| - throw e; |
| - } |
| - } |
| - |
| bool _isErrorResponse(response) { |
| return response is List && response[0] != _FileUtils.kSuccessResponse; |
| } |
| - void _handleErrorResponse(response, String message) { |
| + Exception _exceptionFromResponse(response, String message) { |
| assert(_isErrorResponse(response)); |
| switch (response[_FileUtils.kErrorResponseErrorType]) { |
| case _FileUtils.kIllegalArgumentResponse: |
| - _reportError(new IllegalArgumentException()); |
| - break; |
| + return new IllegalArgumentException(); |
| case _FileUtils.kOSErrorResponse: |
| var err = new OSError(response[_FileUtils.kOSErrorResponseMessage], |
| response[_FileUtils.kOSErrorResponseErrorCode]); |
| - _reportError(new FileIOException(message, err)); |
| - break; |
| + return new FileIOException(message, err); |
| case _FileUtils.kFileClosedResponse: |
| - _reportError(new FileIOException("File closed")); |
| - break; |
| + return new FileIOException("File closed"); |
| default: |
| - _reportError(new Exception("Unknown error")); |
| - break; |
| + return new Exception("Unknown error"); |
| } |
| } |
| - |
| - void set onError(void handler(e)) { |
| - _onError = handler; |
| - } |
| - |
| - Function _onError; |
| } |
| // Class for encapsulating the native implementation of files. |
| @@ -412,36 +416,42 @@ class _File extends _FileBase implements File { |
| // Constructor for file. |
| _File(String this._name); |
| - void exists(void callback(bool exists)) { |
| + Future<bool> exists() { |
| _ensureFileService(); |
| + Completer<bool> completer = new Completer<bool>(); |
| List request = new List(2); |
| request[0] = _FileUtils.kExistsRequest; |
| request[1] = _name; |
| _fileService.call(request).then((response) { |
| if (_isErrorResponse(response)) { |
| - _handleErrorResponse(response, "Cannot open file '$_name'"); |
| + var e = _exceptionFromResponse(response, "Cannot open file '$_name'"); |
| + completer.completeException(e); |
| } else { |
| - callback(response); |
| + completer.complete(response); |
| } |
| }); |
| + return completer.future; |
| } |
| bool existsSync() { |
| return _FileUtils.checkedExists(_name); |
| } |
| - void create(void callback()) { |
| + Future<File> create() { |
| _ensureFileService(); |
| + Completer<File> completer = new Completer<File>(); |
| List request = new List(2); |
| request[0] = _FileUtils.kCreateRequest; |
| request[1] = _name; |
| _fileService.call(request).then((response) { |
| if (_isErrorResponse(response)) { |
| - _handleErrorResponse(response, "Cannot create file"); |
| + var e = _exceptionFromResponse(response, "Cannot create file '$_name'"); |
| + completer.completeException(e); |
| } else { |
| - callback(); |
| + completer.complete(this); |
| } |
| }); |
| + return completer.future; |
| } |
| void createSync() { |
| @@ -451,36 +461,44 @@ class _File extends _FileBase implements File { |
| } |
| } |
| - void delete(void callback()) { |
| + Future<File> delete() { |
| _ensureFileService(); |
| + Completer<File> completer = new Completer<File>(); |
| List request = new List(2); |
| request[0] = _FileUtils.kDeleteRequest; |
| request[1] = _name; |
| _fileService.call(request).then((response) { |
| if (_isErrorResponse(response)) { |
| - _handleErrorResponse(response, "Cannot delete file '$_name'"); |
| + var e = _exceptionFromResponse(response, "Cannot delete file '$_name'"); |
| + completer.completeException(e); |
| } else { |
| - callback(); |
| + completer.complete(this); |
| } |
| }); |
| + return completer.future; |
| } |
| void deleteSync() { |
| _FileUtils.checkedDelete(_name); |
| } |
| - void directory(void callback(Directory dir)) { |
| + Future<Directory> directory() { |
| _ensureFileService(); |
| + Completer<Directory> completer = new Completer<Directory>(); |
| List request = new List(2); |
| request[0] = _FileUtils.kDirectoryRequest; |
| request[1] = _name; |
| _fileService.call(request).then((response) { |
| if (_isErrorResponse(response)) { |
| - _handleErrorResponse(response, "Cannot retrieve directory for file"); |
| + var e = _exceptionFromResponse(response, |
| + "Cannot retrieve directory for " |
| + "file '$_name'"); |
| + completer.completeException(e); |
| } else { |
| - callback(new Directory(response)); |
| + completer.complete(new Directory(response)); |
| } |
| }); |
| + return completer.future; |
| } |
| Directory directorySync() { |
| @@ -488,13 +506,16 @@ class _File extends _FileBase implements File { |
| return new Directory(_FileUtils.directory(_name)); |
| } |
| - void open(FileMode mode, void callback(RandomAccessFile file)) { |
| + Future<RandomAccessFile> open(FileMode mode) { |
| _ensureFileService(); |
| + Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>(); |
| if (mode != FileMode.READ && |
| mode != FileMode.WRITE && |
| mode != FileMode.APPEND) { |
| - _reportError(new IllegalArgumentException()); |
| - return; |
| + new Timer(0, (t) { |
| + completer.completeException(new IllegalArgumentException()); |
| + }); |
| + return completer.future; |
| } |
| List request = new List(3); |
| request[0] = _FileUtils.kOpenRequest; |
| @@ -502,26 +523,32 @@ class _File extends _FileBase implements File { |
| request[2] = mode._mode; // Direct int value for serialization. |
| _fileService.call(request).then((response) { |
| if (_isErrorResponse(response)) { |
| - _handleErrorResponse(response, "Cannot open file '$_name'"); |
| + var e = _exceptionFromResponse(response, "Cannot open file '$_name'"); |
| + completer.completeException(e); |
| } else { |
| - callback(new _RandomAccessFile(response, _name)); |
| + completer.complete(new _RandomAccessFile(response, _name)); |
| } |
| }); |
| + return completer.future; |
| } |
| - void length(void callback(int length)) { |
| + Future<int> length() { |
| _ensureFileService(); |
| + Completer<int> completer = new Completer<int>(); |
| List request = new List(2); |
| request[0] = _FileUtils.kLengthFromNameRequest; |
| request[1] = _name; |
| _fileService.call(request).then((response) { |
| if (_isErrorResponse(response)) { |
| - _handleErrorResponse(response, |
| - "Cannot retrieve length of file '$_name'"); |
| + var e = _exceptionFromResponse(response, |
| + "Cannot retrieve length of " |
| + "file '$_name'"); |
| + completer.completeException(e); |
| } else { |
| - callback(response); |
| + completer.complete(response); |
| } |
| }); |
| + return completer.future; |
| } |
| int lengthSync() { |
| @@ -553,18 +580,23 @@ class _File extends _FileBase implements File { |
| return new _RandomAccessFile(id, ""); |
| } |
| - void fullPath(void callback(String result)) { |
| + Future<String> fullPath() { |
| _ensureFileService(); |
| + Completer<String> completer = new Completer<String>(); |
| List request = new List(2); |
| request[0] = _FileUtils.kFullPathRequest; |
| request[1] = _name; |
| _fileService.call(request).then((response) { |
| if (_isErrorResponse(response)) { |
| - _handleErrorResponse(response, "Cannot retrieve full path"); |
| + var e = _exceptionFromResponse(response, |
| + "Cannot retrieve full path" |
| + " for '$_name'"); |
| + completer.completeException(e); |
| } else { |
| - callback(response); |
| + completer.complete(response); |
| } |
| }); |
| + return completer.future; |
| } |
| String fullPathSync() { |
| @@ -584,18 +616,20 @@ class _File extends _FileBase implements File { |
| return new _FileOutputStream(_name, mode); |
| } |
| - void readAsBytes(void callback(List<int> bytes)) { |
| + Future<List<int>> readAsBytes() { |
| _ensureFileService(); |
| + Completer<List<int>> completer = new Completer<List<int>>(); |
| var chunks = new _BufferList(); |
| var stream = openInputStream(); |
| stream.onClosed = () { |
| - callback(chunks.readBytes(chunks.length)); |
| + completer.complete(chunks.readBytes(chunks.length)); |
| }; |
| stream.onData = () { |
| var chunk = stream.read(); |
| chunks.add(chunk); |
| }; |
| - stream.onError = (e) => _reportError(e); |
| + stream.onError = completer.completeException; |
| + return completer.future; |
| } |
| List<int> readAsBytesSync() { |
| @@ -610,17 +644,12 @@ class _File extends _FileBase implements File { |
| return result; |
| } |
| - void readAsText(Encoding encoding, void callback(String text)) { |
| + Future<String> readAsText(Encoding encoding) { |
| _ensureFileService(); |
| var decoder = _StringDecoders.decoder(encoding); |
| - readAsBytes((bytes) { |
| - try { |
| - decoder.write(bytes); |
| - } catch (var e) { |
| - _reportError(e); |
| - return; |
| - } |
| - callback(decoder.decoded); |
| + return readAsBytes().transform((bytes) { |
| + decoder.write(bytes); |
| + return decoder.decoded; |
| }); |
| } |
| @@ -647,17 +676,13 @@ class _File extends _FileBase implements File { |
| return result; |
| } |
| - void readAsLines(Encoding encoding, void callback(List<String> lines)) { |
| + Future<List<String>> readAsLines(Encoding encoding) { |
| _ensureFileService(); |
| + Completer<List<String>> completer = new Completer<List<String>>(); |
| var decoder = _StringDecoders.decoder(encoding); |
| - readAsBytes((bytes) { |
| - try { |
| - decoder.write(bytes); |
| - } catch (var e) { |
| - _reportError(e); |
| - return; |
| - } |
| - callback(_getDecodedLines(decoder)); |
| + return readAsBytes().transform((bytes) { |
| + decoder.write(bytes); |
| + return _getDecodedLines(decoder); |
| }); |
| } |
| @@ -676,7 +701,7 @@ class _File extends _FileBase implements File { |
| } |
| } |
| - String _name; |
| + final String _name; |
| SendPort _fileService; |
| } |
| @@ -685,10 +710,17 @@ class _File extends _FileBase implements File { |
| class _RandomAccessFile extends _FileBase implements RandomAccessFile { |
| _RandomAccessFile(int this._id, String this._name); |
| - void close(void callback()) { |
| + Future<RandomAccessFile> close() { |
| + Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>(); |
| if (_id == 0) { |
| - _reportError(new FileIOException("Cannot close file '$_name'")); |
| - return; |
| + // Complete asynchronously so the user has a chance to setup |
| + // handlers without getting exceptions when registering the |
| + // then handler. |
|
Søren Gjesse
2012/05/10 11:24:45
So we do always want to throw exceptions through t
Mads Ager (google)
2012/05/10 12:42:38
Yes, at least I did that consistently for the file
|
| + new Timer(0, (t) { |
| + completer.completeException( |
| + new FileIOException("Cannot close file '$_name'")); |
| + }); |
| + return completer.future; |
| } |
| _ensureFileService(); |
| List request = new List(2); |
| @@ -700,11 +732,13 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { |
| _fileService.call(request).then((result) { |
| if (result != -1) { |
| _id = result; |
| - callback(); |
| + completer.complete(this); |
| } else { |
| - _reportError(new FileIOException("Cannot close file '$_name'")); |
| + completer.completeException( |
| + new FileIOException("Cannot close file '$_name'")); |
| } |
| }); |
| + return completer.future; |
| } |
| void closeSync() { |
| @@ -715,18 +749,22 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { |
| _id = id; |
| } |
| - void readByte(void callback(int byte)) { |
| + Future<int> readByte() { |
| _ensureFileService(); |
| + Completer<int> completer = new Completer<int>(); |
| List request = new List(2); |
| request[0] = _FileUtils.kReadByteRequest; |
| request[1] = _id; |
| _fileService.call(request).then((response) { |
| if (_isErrorResponse(response)) { |
| - _handleErrorResponse(response, "readByte failed for file '$_name'"); |
| + var e = _exceptionFromResponse(response, |
| + "readByte failed for file '$_name'"); |
| + completer.completeException(e); |
| } else { |
| - callback(response); |
| + completer.complete(response); |
| } |
| }); |
| + return completer.future; |
| } |
| int readByteSync() { |
| @@ -738,13 +776,18 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { |
| return result; |
| } |
| - void readList(List<int> buffer, int offset, int bytes, |
| - void callback(int read)) { |
| + Future<int> readList(List<int> buffer, int offset, int bytes) { |
| _ensureFileService(); |
| + Completer<int> completer = new Completer<int>(); |
| if (buffer is !List || offset is !int || bytes is !int) { |
| - _reportError(new FileIOException( |
| - "Invalid arguments to readList for file '$_name'")); |
| - return; |
| + // Complete asynchronously so the user has a chance to setup |
| + // handlers without getting exceptions when registering the |
| + // then handler. |
| + new Timer(0, (t) { |
| + completer.completeException(new FileIOException( |
| + "Invalid arguments to readList for file '$_name'")); |
| + }); |
| + return completer.future; |
| }; |
| List request = new List(3); |
| request[0] = _FileUtils.kReadListRequest; |
| @@ -752,14 +795,17 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { |
| request[2] = bytes; |
| _fileService.call(request).then((response) { |
| if (_isErrorResponse(response)) { |
| - _handleErrorResponse(response, "readList failed for file '$_name'"); |
| + var e = _exceptionFromResponse(response, |
| + "readList failed for file '$_name'"); |
| + completer.completeException(e); |
| } else { |
| var read = response[1]; |
| var data = response[2]; |
| buffer.setRange(offset, read, data); |
| - callback(read); |
| + completer.complete(read); |
| } |
| }); |
| + return completer.future; |
| } |
| int readListSync(List<int> buffer, int offset, int bytes) { |
| @@ -782,24 +828,33 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { |
| return result; |
| } |
| - void writeByte(int value) { |
| + Future<RandomAccessFile> writeByte(int value) { |
| _ensureFileService(); |
| + Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>(); |
| if (value is !int) { |
| - _reportError(new FileIOException( |
| - "Invalid argument to writeByte for file '$_name'")); |
| - return; |
| + // Complete asynchronously so the user has a chance to setup |
| + // handlers without getting exceptions when registering the |
| + // then handler. |
| + new Timer(0, (t) { |
| + completer.completeException(new FileIOException( |
| + "Invalid argument to writeByte for file '$_name'")); |
| + }); |
| + return completer.future; |
| } |
| List request = new List(3); |
| request[0] = _FileUtils.kWriteByteRequest; |
| request[1] = _id; |
| request[2] = value; |
| - _writeEnqueued(); |
| _fileService.call(request).then((response) { |
| - _writeCompleted(); |
| if (_isErrorResponse(response)) { |
| - _handleErrorResponse(response, "writeByte failed for file '$_name'"); |
| + var e = _exceptionFromResponse(response, |
| + "writeByte failed for file '$_name'"); |
| + completer.completeException(e); |
| + } else { |
| + completer.complete(this); |
| } |
| }); |
| + return completer.future; |
| } |
| int writeByteSync(int value) { |
| @@ -816,12 +871,18 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { |
| return result; |
| } |
| - void writeList(List<int> buffer, int offset, int bytes) { |
| + Future<RandomAccessFile> writeList(List<int> buffer, int offset, int bytes) { |
| _ensureFileService(); |
| + Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>(); |
| if (buffer is !List || offset is !int || bytes is !int) { |
| - _reportError(new FileIOException( |
| + // Complete asynchronously so the user has a chance to setup |
| + // handlers without getting exceptions when registering the |
| + // then handler. |
| + new Timer(0, (t) { |
| + completer.completeException(new FileIOException( |
| "Invalid arguments to writeList for file '$_name'")); |
| - return; |
| + }); |
| + return completer.future; |
| } |
| List result = |
| @@ -835,13 +896,16 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { |
| request[2] = outBuffer; |
| request[3] = outOffset; |
| request[4] = bytes; |
| - _writeEnqueued(); |
| _fileService.call(request).then((response) { |
| - _writeCompleted(); |
| if (_isErrorResponse(response)) { |
| - _handleErrorResponse(response, "writeList failed for file '$_name'"); |
| + var e = _exceptionFromResponse(response, |
| + "writeList failed for file '$_name'"); |
| + completer.completeException(e); |
| + } else { |
| + completer.complete(this); |
| } |
| }); |
| + return completer.future; |
| } |
| int writeListSync(List<int> buffer, int offset, int bytes) { |
| @@ -863,19 +927,24 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { |
| return result; |
| } |
| - void writeString(String string, [Encoding encoding = Encoding.UTF_8]) { |
| + Future<RandomAccessFile> writeString(String string, |
| + [Encoding encoding = Encoding.UTF_8]) { |
| _ensureFileService(); |
| + Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>(); |
| List request = new List(3); |
| request[0] = _FileUtils.kWriteStringRequest; |
| request[1] = _id; |
| request[2] = string; |
| - _writeEnqueued(); |
| _fileService.call(request).then((response) { |
| - _writeCompleted(); |
| if (_isErrorResponse(response)) { |
| - _handleErrorResponse(response, "writeString failed for file '$_name'"); |
| + var e = _exceptionFromResponse(response, |
| + "writeString failed for file '$_name'"); |
| + completer.completeException(e); |
| + } else { |
| + completer.complete(this); |
| } |
| }); |
| + return completer.future; |
| } |
| int writeStringSync(String string, [Encoding encoding = Encoding.UTF_8]) { |
| @@ -887,18 +956,22 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { |
| return result; |
| } |
| - void position(void callback(int position)) { |
| + Future<int> position() { |
| _ensureFileService(); |
| + Completer<int> completer = new Completer<int>(); |
| List request = new List(2); |
| request[0] = _FileUtils.kPositionRequest; |
| request[1] = _id; |
| _fileService.call(request).then((response) { |
| if (_isErrorResponse(response)) { |
| - _handleErrorResponse(response, "position failed for file '$_name'"); |
| + var e = _exceptionFromResponse(response, |
| + "position failed for file '$_name'"); |
| + completer.completeException(e); |
| } else { |
| - callback(response); |
| + completer.complete(response); |
| } |
| }); |
| + return completer.future; |
| } |
| int positionSync() { |
| @@ -910,19 +983,23 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { |
| return result; |
| } |
| - void setPosition(int position, void callback()) { |
| + Future<RandomAccessFile> setPosition(int position) { |
| _ensureFileService(); |
| + Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>(); |
| List request = new List(3); |
| request[0] = _FileUtils.kSetPositionRequest; |
| request[1] = _id; |
| request[2] = position; |
| _fileService.call(request).then((response) { |
| if (_isErrorResponse(response)) { |
| - _handleErrorResponse(response, "setPosition failed for file '$_name'"); |
| + var e = _exceptionFromResponse(response, |
| + "setPosition failed for file '$_name'"); |
| + completer.completeException(e); |
| } else { |
| - callback(); |
| + completer.complete(this); |
| } |
| }); |
| + return completer.future; |
| } |
| void setPositionSync(int position) { |
| @@ -933,19 +1010,23 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { |
| } |
| } |
| - void truncate(int length, void callback()) { |
| + Future<RandomAccessFile> truncate(int length) { |
| _ensureFileService(); |
| + Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>(); |
| List request = new List(3); |
| request[0] = _FileUtils.kTruncateRequest; |
| request[1] = _id; |
| request[2] = length; |
| _fileService.call(request).then((response) { |
| if (_isErrorResponse(response)) { |
| - _handleErrorResponse(response, "truncate failed for file '$_name'"); |
| + var e = _exceptionFromResponse(response, |
| + "truncate failed for file '$_name'"); |
| + completer.completeException(e); |
| } else { |
| - callback(); |
| + completer.complete(this); |
| } |
| }); |
| + return completer.future; |
| } |
| void truncateSync(int length) { |
| @@ -956,18 +1037,22 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { |
| } |
| } |
| - void length(void callback(int length)) { |
| + Future<int> length() { |
| _ensureFileService(); |
| + Completer<int> completer = new Completer<int>(); |
| List request = new List(2); |
| request[0] = _FileUtils.kLengthRequest; |
| request[1] = _id; |
| _fileService.call(request).then((response) { |
| if (_isErrorResponse(response)) { |
| - _handleErrorResponse(response, "length failed for file '$_name'"); |
| + var e = _exceptionFromResponse(response, |
| + "length failed for file '$_name'"); |
| + completer.completeException(e); |
| } else { |
| - callback(response); |
| + completer.complete(response); |
| } |
| }); |
| + return completer.future; |
| } |
| int lengthSync() { |
| @@ -979,18 +1064,22 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { |
| return result; |
| } |
| - void flush(void callback()) { |
| + Future<RandomAccessFile> flush() { |
| _ensureFileService(); |
| + Completer<RandomAccessFile> completer = new Completer<RandomAccessFile>(); |
| List request = new List(2); |
| request[0] = _FileUtils.kFlushRequest; |
| request[1] = _id; |
| _fileService.call(request).then((response) { |
| if (_isErrorResponse(response)) { |
| - _handleErrorResponse(response, "flush failed for file '$_name'"); |
| + var e = _exceptionFromResponse(response, |
| + "flush failed for file '$_name'"); |
| + completer.completeException(e); |
| } else { |
| - callback(); |
| + completer.complete(this); |
| } |
| }); |
| + return completer.future; |
| } |
| void flushSync() { |
| @@ -1003,49 +1092,20 @@ class _RandomAccessFile extends _FileBase implements RandomAccessFile { |
| String get name() => _name; |
| - void set onNoPendingWrites(void handler()) { |
| - _onNoPendingWrites = handler; |
| - if (_pendingWrites == 0) { |
| - _noPendingWriteTimer = new Timer(0, (t) { |
| - if (_onNoPendingWrites != null) _onNoPendingWrites(); |
| - }); |
| - } |
| - } |
| - |
| void _ensureFileService() { |
| if (_fileService == null) { |
| _fileService = _FileUtils.newServicePort(); |
| } |
| } |
| - void _writeEnqueued() { |
| - _pendingWrites++; |
| - if (_noPendingWriteTimer != null) { |
| - _noPendingWriteTimer.cancel(); |
| - _noPendingWriteTimer = null; |
| - } |
| - } |
| - |
| - void _writeCompleted() { |
| - _pendingWrites--; |
| - if (_pendingWrites == 0 && _onNoPendingWrites != null) { |
| - _onNoPendingWrites(); |
| - } |
| - } |
| - |
| void _checkNotClosed() { |
| if (_id == 0) { |
| throw new FileIOException("File closed '$_name'"); |
| } |
| } |
| - String _name; |
| + final String _name; |
| int _id; |
| - int _pendingWrites = 0; |
| SendPort _fileService; |
| - |
| - Timer _noPendingWriteTimer; |
| - |
| - Function _onNoPendingWrites; |
| } |