
com.englishtown.promises.internal.ArrayHelper Maven / Gradle / Ivy
package com.englishtown.promises.internal;
import com.englishtown.promises.Promise;
import com.englishtown.promises.PromiseResolver;
import com.englishtown.promises.State;
import com.englishtown.promises.Thenable;
import com.englishtown.promises.exceptions.RejectException;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* Helper methods for array promise operations
*/
public class ArrayHelper {
private final PromiseHelper helper;
@Inject
public ArrayHelper(PromiseHelper helper) {
this.helper = helper;
}
/**
* One-winner competitive race.
* Return a promise that will fulfill when one of the promises
* in the input array fulfills, or will reject when all promises
* have rejected.
*
* @param promises list of promises
* @param type of promises
* @return {Promise} promise for the first fulfilled value
*/
public Promise any(List extends Thenable> promises) {
PromiseResolver resolver = (resolve, reject) -> {
ValueHolder pending = new ValueHolder<>(promises.size());
List errors = new ArrayList<>();
Function> handleResolve = (x) -> {
resolve.accept(x);
return null;
};
Function> handleReject = (e) -> {
errors.add(e);
if (--pending.value == 0) {
reject.accept(new RejectException("All promises rejected", errors));
}
return null;
};
promises.forEach((p) -> {
helper.toPromise(p).then(handleResolve, handleReject);
});
if (pending.value == 0) {
resolve.accept(null);
}
};
return new TrustedPromise<>(resolver, helper);
}
/**
* N-winner competitive race
* Return a promise that will fulfill when n input promises have
* fulfilled, or will reject when it becomes impossible for n
* input promises to fulfill (ie when promises.length - n + 1
* have rejected)
*
* @param promises list of promises
* @param n number of promises to fulfill
* @param type of promises
* @return promise for the earliest n fulfillment values
*/
public Promise> some(List extends Thenable> promises, int n) {
int nFinal = Math.max(n, 0);
return new TrustedPromise<>((resolve, reject) -> {
final ValueHolder nFulfill = new ValueHolder<>(0);
final ValueHolder nReject = new ValueHolder<>(null);
List results = new ArrayList<>(nFinal);
List errors = new ArrayList<>();
Function> handleResolve = (x) -> {
if (nFulfill.value > 0) {
--nFulfill.value;
results.add(x);
if (nFulfill.value == 0) {
resolve.accept(results);
}
}
return null;
};
Function> handleReject = (e) -> {
if (nReject.value > 0) {
--nReject.value; // TODO: sync?
errors.add(e);
if (nReject.value == 0) {
reject.accept(new RejectException("Too many rejections", errors));
}
}
return null;
};
nReject.value = (promises.size() - nFinal + 1);
nFulfill.value = Math.min(nFinal, promises.size());
if (nFulfill.value == 0) {
resolve.accept(results);
return;
}
promises.stream().forEach(p -> {
helper.toPromise(p).then(handleResolve, handleReject);
});
}, helper);
}
/**
* Apply f to the value of each promise in a list of promises
* and return a new list containing the results.
*
* @param promises list of promises
* @param f function run when a promise fulfills
* @param fallback function run when a promise rejects
* @param type of promises
* @return promise for list of results
*/
public Promise> map(List extends Thenable> promises, Function> f, Function> fallback) {
return helper.all(promises
.stream()
.map(x -> helper.toPromise(x).then(f, fallback))
.collect(Collectors.toList()));
}
/**
* Return a promise that will always fulfill with an array containing
* the outcome states of all input promises. The returned promise
* will never reject.
*
* @param promises list of promises
* @param type of promises
* @return promise for list of states
*/
public Promise>> settle(List extends Thenable> promises) {
return helper.all(promises.stream().map(p -> {
TrustedPromise p1 = helper.toPromise(p);
//noinspection unchecked
return p1.then(
x -> helper.resolve(p1.inspect()),
t -> helper.resolve(p1.inspect())
);
}).collect(Collectors.toList()));
}
public Promise reduce(List extends Thenable> promises, BiFunction> f) {
//noinspection unchecked
List> thenables = (List>) promises;
return (Promise) thenables
.stream()
.reduce(
(result, x) -> helper.toPromise(result).then(
r -> helper.toPromise(x).then(
x1 -> f.apply(r, x1)
)
))
.get();
}
public Promise reduce(List extends Thenable> promises, BiFunction> f, Thenable initialValue) {
//noinspection unchecked
List> thenables = (List>) promises;
return (Promise) thenables
.stream()
.reduce(
initialValue,
(result, x) -> helper.toPromise(result).then(
r -> helper.toPromise(x).then(
x1 -> f.apply(r, x1)
)
), (c1, c2) -> c1);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy