net.pincette.rs.Concat Maven / Gradle / Ivy
package net.pincette.rs;
import static java.util.Arrays.asList;
import static net.pincette.rs.Serializer.dispatch;
import static net.pincette.rs.Util.empty;
import java.util.List;
import java.util.concurrent.Flow.Publisher;
import java.util.concurrent.Flow.Subscriber;
/**
* Concatenates multiple publishers of the same type to form one publisher that completes when the
* last given publisher completes.
*
* @param the value type.
* @author Werner Donn\u00e9
* @since 3.0
*/
public class Concat implements Publisher {
private final Chainer chainer = new Chainer();
private final List> publishers;
public Concat(final List> publishers) {
this.publishers = publishers;
}
public static Publisher of(final List> publishers) {
return new Concat<>(publishers);
}
@SafeVarargs
public static Publisher of(final Publisher... publishers) {
return new Concat<>(asList(publishers));
}
@Override
public void subscribe(final Subscriber super T> subscriber) {
if (publishers.isEmpty()) {
final Publisher empty = empty();
empty.subscribe(subscriber);
} else {
publishers.get(0).subscribe(chainer);
chainer.subscribe(subscriber);
}
}
private class Chainer extends ProcessorBase {
private int position;
private long requested;
@Override
public void cancel() {
// Don't cancel when a new subscription is taken, because then this dynamic subscription
// switching is no longer transparent for the publishers.
}
@Override
protected void emit(final long number) {
dispatch(
() -> {
requested += number;
more();
});
}
private void more() {
if (requested > 0) {
subscription.request(1);
}
}
@Override
public void onComplete() {
dispatch(
() -> {
if (position < publishers.size() - 1) {
publishers.get(++position).subscribe(this);
more();
} else {
super.onComplete();
}
});
}
@Override
public void onNext(final T item) {
dispatch(
() -> {
--requested;
subscriber.onNext(item);
more();
});
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy