/** * 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:

* * 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) { var ASSERT = require("./assert.js"); 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); }; };