All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.englishtown.promises.impl.DefaultWhen Maven / Gradle / Ivy

The newest version!
package com.englishtown.promises.impl;

import com.englishtown.promises.*;
import com.englishtown.promises.internal.ArrayHelper;
import com.englishtown.promises.internal.PromiseHelper;
import com.englishtown.promises.internal.TrustedPromise;

import javax.inject.Inject;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;

/**
 * Default implementation of {@link com.englishtown.promises.When}
 */
public class DefaultWhen implements When {

    private final PromiseHelper helper;
    private final ArrayHelper arrayHelper;

    @Inject
    public DefaultWhen(PromiseHelper helper, ArrayHelper arrayHelper) {
        this.helper = helper;
        this.arrayHelper = arrayHelper;
    }

//            // Public API
//
//            when.lift        = lift;                 // lift a function to return promises
//            when['try']      = attempt;              // call a function and return a promise
//            when.attempt     = attempt;              // alias for when.try
//
//            when.iterate     = Promise.iterate;      // Generate a stream of promises
//            when.unfold      = Promise.unfold;       // Generate a stream of promises
//
//

    @Override
    public  Promise when(T x) {
        return when(x, null, null);
    }

    @Override
    public  Promise when(Thenable x) {
        return this.when(x, null, null);
    }

    @Override
    public  Promise when(T x, Function> onFulfilled) {
        return when(x, onFulfilled, null);
    }

    @Override
    public  Promise when(T x, Function> onFulfilled, Function> onRejected) {
        Promise p = resolve(x);
        return p.then(onFulfilled, onRejected);
    }

    @Override
    public  Promise when(Thenable x, Function> onFulfilled) {
        return when(x, onFulfilled, null);
    }

    @Override
    public  Promise when(Thenable x, Function> onFulfilled, Function> onRejected) {
        Promise p = resolve(x);
        return p.then(onFulfilled, onRejected);
    }

    @Override
    public  Promise resolve(T x) {
        return helper.resolve(x);
    }

    @Override
    public  Promise resolve(Thenable x) {
        return helper.resolve(x);
    }

    @Override
    public  Promise reject(Throwable x) {
        return helper.reject(x);
    }

    @Override
    public  Promise promise(PromiseResolver resolver) {
        return new TrustedPromise<>(resolver, helper);
    }

//    /**
//     * Lift the supplied function, creating a version of f that returns
//     * promises, and accepts promises as arguments.
//     *
//     * @param {function} f
//     * @return {Function} version of f that returns promises
//     */
//    public  Promise lift(Object f) {
//        return function() {
//            return _apply(f, this, slice.call(arguments));
//        }
//    }

//    /**
//     * Call f in a future turn, with the supplied args, and return a promise
//     * for the result.
//     *
//     * @param {function} f
//     * @return {Promise}
//     */
//    function attempt(f /*, args... */) {
//        /*jshint validthis:true */
//        return _apply(f, this, slice.call(arguments, 1));
//    }

    /**
     * try/lift helper that allows specifying thisArg
     */
    private  Promise _apply(Function, Thenable> f, List> args) {
        return helper.all(args).then(f::apply);
//        return Promise.all(args).then(function(args) {
//            return f.apply(thisArg, args);
//        });
    }


    @Override
    public  Deferred defer() {
        return new DeferredImpl<>();
    }

    private class DeferredImpl implements Deferred {

        private final TrustedPromise promise;

        public DeferredImpl() {
            promise = helper.defer();
        }

        @Override
        public Resolver getResolver() {
            return this;
        }

        @Override
        public Promise getPromise() {
            return promise;
        }

        @Override
        public void resolve(T x) {
            promise._handler.resolve(x);
        }

        @Override
        public void resolve(Thenable x) {
            promise._handler.resolve(x);
        }

        @Override
        public void reject(Throwable x) {
            promise._handler.reject(x);
        }
    }

//
//    /**
//     * Determines if x is promise-like, i.e. a thenable object
//     * NOTE: Will return true for *any thenable object*, and isn't truly
//     * safe, since it may attempt to access the `then` property of x (i.e.
//     * clever/malicious getters may do weird things)
//     *
//     * @param {*} x anything
//     * @return {boolean} true if x is promise-like
//     */
//    function isPromiseLike(x) {
//        return x && typeof x.then == = 'function';
//    }

    @Override
    public  Promise> join(Promise... promises) {
        return helper.all(Arrays.asList(promises));
    }

    @Override
    public  Promise> all(List> promises) {
        return when(promises, helper::all);
    }

    @Override
    public  Promise>> settle(List> promises) {
        return when(promises, arrayHelper::settle);
    }

    @Override
    public  Promise any(List> promises) {
        return when(promises, arrayHelper::any);
    }

    @Override
    public  Promise> some(List> promises, int n) {
        return arrayHelper.some(promises, n);
    }

    @Override
    public  Promise> map(List> promises, Function> mapFunc) {
        return when(promises, (promises1) -> arrayHelper.map(promises1, mapFunc, null));
    }

    @Override
    public  Promise reduce(List> promises, BiFunction> f) {
        return when(promises, (promises1) -> arrayHelper.reduce(promises1, f));
    }

    @Override
    public  Promise reduce(List> promises, BiFunction> f, Thenable initialValue) {
        return when(promises, (promises1) -> arrayHelper.reduce(promises1, f, initialValue));
    }

//    /**
//     * Traditional reduce function, similar to `Array.prototype.reduceRight()`, but
//     * input may contain promises and/or values, and reduceFunc
//     * may return either a value or a promise, *and* initialValue may
//     * be a promise for the starting value.
//     *
//     * @param {Array|Promise} promises array or promise for an array of anything,
//     *                        may contain a mix of promises and values.
//     * @param {function}      f reduce function reduce(currentValue, nextValue, index)
//     * @return {Promise} that will resolve to the final reduced value
//     */
//    function reduceRight(promises, f /*, initialValue */) {
//		/*jshint unused:false*/
//        var args = slice.call(arguments, 1);
//        return when(promises, function(array) {
//            args.unshift(array);
//            return Promise.reduceRight.apply(Promise, args);
//        });
//    }
//
//    return when;

    @Override
    public  Promise> sequence(List>> tasks, Thenable arg) {
        List results = new ArrayList<>();

        // Create resolved promises for tasks so we can use reduce()
        List>>> promises = new ArrayList<>(tasks.size());
        tasks.stream().forEach((task) -> promises.add(resolve(task)));

        Function>> addResult = (result) -> {
            results.add(result);
            return resolve(results);
        };

        return resolve(arg).then(argResult -> {
            return this.reduce(promises, (results1, task) -> {
                return when(task.apply(argResult), addResult);
            }, resolve(results));
        });

    }

    @Override
    public  Promise race(List> promises) {
        return helper.race(promises);
    }

}