227 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			227 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
"use strict";
 | 
						|
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();
 | 
						|
    };
 | 
						|
 | 
						|
};
 |