mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 784717 - Asynchronous directory walk controller code. r=froydnj
This commit is contained in:
parent
600e5f8970
commit
ecb2fe56b1
@ -582,6 +582,173 @@ File.Info.fromMsg = function fromMsg(value) {
|
||||
return new File.Info(value);
|
||||
};
|
||||
|
||||
/**
|
||||
* Iterate asynchronously through a directory
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
let DirectoryIterator = function DirectoryIterator(path, options) {
|
||||
/**
|
||||
* Open the iterator on the worker thread
|
||||
*
|
||||
* @type {Promise}
|
||||
* @resolves {*} A message accepted by the methods of DirectoryIterator
|
||||
* in the worker thread
|
||||
* @rejects {StopIteration} If all entries have already been visited
|
||||
* or the iterator has been closed.
|
||||
*/
|
||||
this._itmsg = Scheduler.post(
|
||||
"new_DirectoryIterator", [Type.path.toMsg(path), options],
|
||||
path
|
||||
);
|
||||
this._isClosed = false;
|
||||
};
|
||||
DirectoryIterator.prototype = {
|
||||
/**
|
||||
* Get the next entry in the directory.
|
||||
*
|
||||
* @return {Promise}
|
||||
* @resolves {OS.File.Entry}
|
||||
* @rejects {StopIteration} If all entries have already been visited.
|
||||
*/
|
||||
next: function next() {
|
||||
let self = this;
|
||||
let promise = this._itmsg;
|
||||
|
||||
// Get the iterator, call _next
|
||||
promise = promise.then(
|
||||
function withIterator(iterator) {
|
||||
return self._next(iterator);
|
||||
});
|
||||
|
||||
return promise;
|
||||
},
|
||||
/**
|
||||
* Get several entries at once.
|
||||
*
|
||||
* @param {number=} length If specified, the number of entries
|
||||
* to return. If unspecified, return all remaining entries.
|
||||
* @return {Promise}
|
||||
* @resolves {Array} An array containing the |length| next entries.
|
||||
*/
|
||||
nextBatch: function nextBatch(size) {
|
||||
if (this._isClosed) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
let promise = this._itmsg;
|
||||
promise = promise.then(
|
||||
function withIterator(iterator) {
|
||||
return Scheduler.post("DirectoryIterator_prototype_nextBatch", [iterator, size]);
|
||||
});
|
||||
promise = promise.then(
|
||||
function withEntries(array) {
|
||||
return array.map(DirectoryIterator.Entry.fromMsg);
|
||||
});
|
||||
return promise;
|
||||
},
|
||||
/**
|
||||
* Apply a function to all elements of the directory sequentially.
|
||||
*
|
||||
* @param {Function} cb This function will be applied to all entries
|
||||
* of the directory. It receives as arguments
|
||||
* - the OS.File.Entry corresponding to the entry;
|
||||
* - the index of the entry in the enumeration;
|
||||
* - the iterator itself - return |iterator.close()| to stop the loop.
|
||||
*
|
||||
* If the callback returns a promise, iteration waits until the
|
||||
* promise is resolved before proceeding.
|
||||
*
|
||||
* @return {Promise} A promise resolved once the loop has reached
|
||||
* its end.
|
||||
*/
|
||||
forEach: function forEach(cb, options) {
|
||||
if (this._isClosed) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
let self = this;
|
||||
let position = 0;
|
||||
let iterator;
|
||||
|
||||
// Grab iterator
|
||||
let promise = this._itmsg.then(
|
||||
function(aIterator) {
|
||||
iterator = aIterator;
|
||||
}
|
||||
);
|
||||
|
||||
// Then iterate
|
||||
let loop = function loop() {
|
||||
if (self._isClosed) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return self._next(iterator).then(
|
||||
function onSuccess(value) {
|
||||
return Promise.resolve(cb(value, position++, self)).then(loop);
|
||||
},
|
||||
function onFailure(reason) {
|
||||
if (reason == StopIteration) {
|
||||
return;
|
||||
}
|
||||
throw reason;
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
return promise.then(loop);
|
||||
},
|
||||
/**
|
||||
* Auxiliary method: fetch the next item
|
||||
*
|
||||
* @rejects {StopIteration} If all entries have already been visited
|
||||
* or the iterator has been closed.
|
||||
*/
|
||||
_next: function _next(iterator) {
|
||||
if (this._isClosed) {
|
||||
LOG("DirectoryIterator._next", "closed");
|
||||
return this._itmsg;
|
||||
}
|
||||
let self = this;
|
||||
let promise = Scheduler.post("DirectoryIterator_prototype_next", [iterator]);
|
||||
promise = promise.then(
|
||||
DirectoryIterator.Entry.fromMsg,
|
||||
function onReject(reason) {
|
||||
// If the exception is |StopIteration| (which we may determine only
|
||||
// from its message...) we need to stop the iteration.
|
||||
if (!(reason instanceof WorkerErrorEvent && reason.message == "uncaught exception: [object StopIteration]")) {
|
||||
// Any exception other than StopIteration should be propagated as such
|
||||
throw reason;
|
||||
}
|
||||
self.close();
|
||||
throw StopIteration;
|
||||
});
|
||||
return promise;
|
||||
},
|
||||
/**
|
||||
* Close the iterator
|
||||
*/
|
||||
close: function close() {
|
||||
if (this._isClosed) {
|
||||
return;
|
||||
}
|
||||
this._isClosed = true;
|
||||
let self = this;
|
||||
this._itmsg.then(
|
||||
function withIterator(iterator) {
|
||||
self._itmsg = Promise.reject(StopIteration);
|
||||
return Scheduler.post("DirectoryIterator_prototype_close", [iterator]);
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
DirectoryIterator.Entry = function Entry(value) {
|
||||
return value;
|
||||
};
|
||||
DirectoryIterator.Entry.fromMsg = function fromMsg(value) {
|
||||
return new DirectoryIterator.Entry(value);
|
||||
};
|
||||
|
||||
// Constants
|
||||
Object.defineProperty(File, "POS_START", {value: OS.Shared.POS_START});
|
||||
Object.defineProperty(File, "POS_CURRENT", {value: OS.Shared.POS_CURRENT});
|
||||
@ -589,4 +756,4 @@ Object.defineProperty(File, "POS_END", {value: OS.Shared.POS_END});
|
||||
|
||||
OS.File = File;
|
||||
OS.File.Error = OSError;
|
||||
|
||||
OS.File.DirectoryIterator = DirectoryIterator;
|
||||
|
Loading…
Reference in New Issue
Block a user