net.pincette.rs.AsyncDepend Maven / Gradle / Ivy
package net.pincette.rs;
import static net.pincette.rs.Serializer.dispatch;
import static net.pincette.rs.Util.initialStageDeque;
import java.util.Deque;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.Flow.Processor;
import java.util.function.BiFunction;
import net.pincette.function.SideEffect;
/**
* Emits the values produced by functions in the order the values arrive. The functions also receive
* the result of the previous call, or null if it is the first call. The stream
* completes only after the last stage has completed.
*
* @param the incoming value type.
* @param the outgoing value type.
* @author Werner Donn\u00e9
* @since 3.0
*/
public class AsyncDepend extends ProcessorBase {
private final BiFunction> function;
private final Deque> stages = initialStageDeque();
public AsyncDepend(final BiFunction> function) {
this.function = function;
}
/**
* Returns a processor with the mapping function, which transforms the objects. The functions
* stages are executed in the order of the stream, which completes only after the last stage is
* completed. A function call will also receive the result of the previous call, which is
* null for the first call.
*
* @param function the mapping function.
* @param the incoming value type.
* @param the outgoing value type.
* @return The processor.
*/
public static Processor mapAsync(
final BiFunction> function) {
return new AsyncDepend<>(function);
}
@Override
protected void emit(final long number) {
subscription.request(number);
}
@Override
public void onComplete() {
dispatch(
() -> {
if (!getError()) {
stages.getFirst().thenRunAsync(() -> subscriber.onComplete());
}
});
}
@Override
public void onNext(final T value) {
if (value == null) {
throw new NullPointerException("Can't emit null.");
}
dispatch(
() -> {
if (!getError()) {
final CompletionStage previous = stages.getFirst();
final CompletableFuture next = new CompletableFuture<>();
stages.addFirst(next);
previous
.thenComposeAsync(v -> function.apply(value, v))
.thenApply(
r ->
SideEffect.run(
() -> {
subscriber.onNext(r);
next.complete(r);
})
.andThenGet(() -> r))
.exceptionally(
t -> {
subscriber.onError(t);
subscription.cancel();
return null;
});
while (stages.size() > 10) {
stages.removeLast();
}
}
});
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy