| /** |
| * Copyright (c) 2014 Petka Antonov |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a copy |
| * of this software and associated documentation files (the "Software"), to deal |
| * in the Software without restriction, including without limitation the rights |
| * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| * copies of the Software, and to permit persons to whom the Software is |
| * furnished to do so, subject to the following conditions:</p> |
| * |
| * The above copyright notice and this permission notice shall be included in |
| * all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| * THE SOFTWARE. |
| * |
| */ |
| "use strict"; |
| module.exports = function( |
| Promise, Promise$_CreatePromiseArray, |
| PromiseArray, apiRejection, INTERNAL) { |
| |
| function Reduction(callback, index, accum, items, receiver) { |
| this.promise = new Promise(INTERNAL); |
| this.index = index; |
| this.length = items.length; |
| this.items = items; |
| this.callback = callback; |
| this.receiver = receiver; |
| this.accum = accum; |
| } |
| |
| Reduction.prototype.reject = function Reduction$reject(e) { |
| this.promise._reject(e); |
| }; |
| |
| Reduction.prototype.fulfill = function Reduction$fulfill(value, index) { |
| this.accum = value; |
| this.index = index + 1; |
| this.iterate(); |
| }; |
| |
| Reduction.prototype.iterate = function Reduction$iterate() { |
| var i = this.index; |
| var len = this.length; |
| var items = this.items; |
| var result = this.accum; |
| var receiver = this.receiver; |
| var callback = this.callback; |
| var iterate = this.iterate; |
| |
| for(; i < len; ++i) { |
| result = Promise._cast( |
| callback.call( |
| receiver, |
| result, |
| items[i], |
| i, |
| len |
| ), |
| iterate, |
| void 0 |
| ); |
| |
| if (result instanceof Promise) { |
| result._then( |
| this.fulfill, this.reject, void 0, this, i, iterate); |
| return; |
| } |
| } |
| this.promise._fulfill(result); |
| }; |
| |
| function Promise$_reducer(fulfilleds, initialValue) { |
| var fn = this; |
| var receiver = void 0; |
| if (typeof fn !== "function") { |
| receiver = fn.receiver; |
| fn = fn.fn; |
| } |
| var len = fulfilleds.length; |
| var accum = void 0; |
| var startIndex = 0; |
| |
| if (initialValue !== void 0) { |
| accum = initialValue; |
| startIndex = 0; |
| } |
| else { |
| startIndex = 1; |
| if (len > 0) accum = fulfilleds[0]; |
| } |
| var i = startIndex; |
| |
| if (i >= len) { |
| return accum; |
| } |
| |
| var reduction = new Reduction(fn, i, accum, fulfilleds, receiver); |
| reduction.iterate(); |
| return reduction.promise; |
| } |
| |
| function Promise$_unpackReducer(fulfilleds) { |
| var fn = this.fn; |
| var initialValue = this.initialValue; |
| return Promise$_reducer.call(fn, fulfilleds, initialValue); |
| } |
| |
| function Promise$_slowReduce( |
| promises, fn, initialValue, useBound, caller) { |
| return initialValue._then(function callee(initialValue) { |
| return Promise$_Reduce( |
| promises, fn, initialValue, useBound, callee); |
| }, void 0, void 0, void 0, void 0, caller); |
| } |
| |
| function Promise$_Reduce(promises, fn, initialValue, useBound, caller) { |
| if (typeof fn !== "function") { |
| return apiRejection("fn must be a function"); |
| } |
| |
| if (useBound === true && promises._isBound()) { |
| fn = { |
| fn: fn, |
| receiver: promises._boundTo |
| }; |
| } |
| |
| if (initialValue !== void 0) { |
| if (Promise.is(initialValue)) { |
| if (initialValue.isFulfilled()) { |
| initialValue = initialValue._settledValue; |
| } |
| else { |
| return Promise$_slowReduce(promises, |
| fn, initialValue, useBound, caller); |
| } |
| } |
| |
| return Promise$_CreatePromiseArray(promises, PromiseArray, caller, |
| useBound === true && promises._isBound() |
| ? promises._boundTo |
| : void 0) |
| .promise() |
| ._then(Promise$_unpackReducer, void 0, void 0, { |
| fn: fn, |
| initialValue: initialValue |
| }, void 0, Promise.reduce); |
| } |
| return Promise$_CreatePromiseArray(promises, PromiseArray, caller, |
| useBound === true && promises._isBound() |
| ? promises._boundTo |
| : void 0).promise() |
| ._then(Promise$_reducer, void 0, void 0, fn, void 0, caller); |
| } |
| |
| |
| Promise.reduce = function Promise$Reduce(promises, fn, initialValue) { |
| return Promise$_Reduce(promises, fn, |
| initialValue, false, Promise.reduce); |
| }; |
| |
| Promise.prototype.reduce = function Promise$reduce(fn, initialValue) { |
| return Promise$_Reduce(this, fn, initialValue, |
| true, this.reduce); |
| }; |
| }; |