You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					227 lines
				
				7.3 KiB
			
		
		
			
		
	
	
					227 lines
				
				7.3 KiB
			| 
											3 years ago
										 | "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(); | ||
|  |     }; | ||
|  | 
 | ||
|  | }; |