Spaces:
Paused
Paused
| ; | |
| module.exports = function (Promise, apiRejection, tryConvertToPromise, | |
| createContext, INTERNAL, debug) { | |
| var util = require("./util"); | |
| var TypeError = require("./errors").TypeError; | |
| var inherits = require("./util").inherits; | |
| var errorObj = util.errorObj; | |
| var tryCatch = util.tryCatch; | |
| var NULL = {}; | |
| function thrower(e) { | |
| setTimeout(function(){throw e;}, 0); | |
| } | |
| function castPreservingDisposable(thenable) { | |
| var maybePromise = tryConvertToPromise(thenable); | |
| if (maybePromise !== thenable && | |
| typeof thenable._isDisposable === "function" && | |
| typeof thenable._getDisposer === "function" && | |
| thenable._isDisposable()) { | |
| maybePromise._setDisposable(thenable._getDisposer()); | |
| } | |
| return maybePromise; | |
| } | |
| function dispose(resources, inspection) { | |
| var i = 0; | |
| var len = resources.length; | |
| var ret = new Promise(INTERNAL); | |
| function iterator() { | |
| if (i >= len) return ret._fulfill(); | |
| var maybePromise = castPreservingDisposable(resources[i++]); | |
| if (maybePromise instanceof Promise && | |
| maybePromise._isDisposable()) { | |
| try { | |
| maybePromise = tryConvertToPromise( | |
| maybePromise._getDisposer().tryDispose(inspection), | |
| resources.promise); | |
| } catch (e) { | |
| return thrower(e); | |
| } | |
| if (maybePromise instanceof Promise) { | |
| return maybePromise._then(iterator, thrower, | |
| null, null, null); | |
| } | |
| } | |
| iterator(); | |
| } | |
| iterator(); | |
| return ret; | |
| } | |
| function Disposer(data, promise, context) { | |
| this._data = data; | |
| this._promise = promise; | |
| this._context = context; | |
| } | |
| Disposer.prototype.data = function () { | |
| return this._data; | |
| }; | |
| Disposer.prototype.promise = function () { | |
| return this._promise; | |
| }; | |
| Disposer.prototype.resource = function () { | |
| if (this.promise().isFulfilled()) { | |
| return this.promise().value(); | |
| } | |
| return NULL; | |
| }; | |
| Disposer.prototype.tryDispose = function(inspection) { | |
| var resource = this.resource(); | |
| var context = this._context; | |
| if (context !== undefined) context._pushContext(); | |
| var ret = resource !== NULL | |
| ? this.doDispose(resource, inspection) : null; | |
| if (context !== undefined) context._popContext(); | |
| this._promise._unsetDisposable(); | |
| this._data = null; | |
| return ret; | |
| }; | |
| Disposer.isDisposer = function (d) { | |
| return (d != null && | |
| typeof d.resource === "function" && | |
| typeof d.tryDispose === "function"); | |
| }; | |
| function FunctionDisposer(fn, promise, context) { | |
| this.constructor$(fn, promise, context); | |
| } | |
| inherits(FunctionDisposer, Disposer); | |
| FunctionDisposer.prototype.doDispose = function (resource, inspection) { | |
| var fn = this.data(); | |
| return fn.call(resource, resource, inspection); | |
| }; | |
| function maybeUnwrapDisposer(value) { | |
| if (Disposer.isDisposer(value)) { | |
| this.resources[this.index]._setDisposable(value); | |
| return value.promise(); | |
| } | |
| return value; | |
| } | |
| function ResourceList(length) { | |
| this.length = length; | |
| this.promise = null; | |
| this[length-1] = null; | |
| } | |
| ResourceList.prototype._resultCancelled = function() { | |
| var len = this.length; | |
| for (var i = 0; i < len; ++i) { | |
| var item = this[i]; | |
| if (item instanceof Promise) { | |
| item.cancel(); | |
| } | |
| } | |
| }; | |
| Promise.using = function () { | |
| var len = arguments.length; | |
| if (len < 2) return apiRejection( | |
| "you must pass at least 2 arguments to Promise.using"); | |
| var fn = arguments[len - 1]; | |
| if (typeof fn !== "function") { | |
| return apiRejection("expecting a function but got " + util.classString(fn)); | |
| } | |
| var input; | |
| var spreadArgs = true; | |
| if (len === 2 && Array.isArray(arguments[0])) { | |
| input = arguments[0]; | |
| len = input.length; | |
| spreadArgs = false; | |
| } else { | |
| input = arguments; | |
| len--; | |
| } | |
| var resources = new ResourceList(len); | |
| for (var i = 0; i < len; ++i) { | |
| var resource = input[i]; | |
| if (Disposer.isDisposer(resource)) { | |
| var disposer = resource; | |
| resource = resource.promise(); | |
| resource._setDisposable(disposer); | |
| } else { | |
| var maybePromise = tryConvertToPromise(resource); | |
| if (maybePromise instanceof Promise) { | |
| resource = | |
| maybePromise._then(maybeUnwrapDisposer, null, null, { | |
| resources: resources, | |
| index: i | |
| }, undefined); | |
| } | |
| } | |
| resources[i] = resource; | |
| } | |
| var reflectedResources = new Array(resources.length); | |
| for (var i = 0; i < reflectedResources.length; ++i) { | |
| reflectedResources[i] = Promise.resolve(resources[i]).reflect(); | |
| } | |
| var resultPromise = Promise.all(reflectedResources) | |
| .then(function(inspections) { | |
| for (var i = 0; i < inspections.length; ++i) { | |
| var inspection = inspections[i]; | |
| if (inspection.isRejected()) { | |
| errorObj.e = inspection.error(); | |
| return errorObj; | |
| } else if (!inspection.isFulfilled()) { | |
| resultPromise.cancel(); | |
| return; | |
| } | |
| inspections[i] = inspection.value(); | |
| } | |
| promise._pushContext(); | |
| fn = tryCatch(fn); | |
| var ret = spreadArgs | |
| ? fn.apply(undefined, inspections) : fn(inspections); | |
| var promiseCreated = promise._popContext(); | |
| debug.checkForgottenReturns( | |
| ret, promiseCreated, "Promise.using", promise); | |
| return ret; | |
| }); | |
| var promise = resultPromise.lastly(function() { | |
| var inspection = new Promise.PromiseInspection(resultPromise); | |
| return dispose(resources, inspection); | |
| }); | |
| resources.promise = promise; | |
| promise._setOnCancel(resources); | |
| return promise; | |
| }; | |
| Promise.prototype._setDisposable = function (disposer) { | |
| this._bitField = this._bitField | 131072; | |
| this._disposer = disposer; | |
| }; | |
| Promise.prototype._isDisposable = function () { | |
| return (this._bitField & 131072) > 0; | |
| }; | |
| Promise.prototype._getDisposer = function () { | |
| return this._disposer; | |
| }; | |
| Promise.prototype._unsetDisposable = function () { | |
| this._bitField = this._bitField & (~131072); | |
| this._disposer = undefined; | |
| }; | |
| Promise.prototype.disposer = function (fn) { | |
| if (typeof fn === "function") { | |
| return new FunctionDisposer(fn, this, createContext()); | |
| } | |
| throw new TypeError(); | |
| }; | |
| }; | |