
mutiny.zero.ZeroPublisher Maven / Gradle / Ivy
Show all versions of mutiny-zero Show documentation
package mutiny.zero;
import static java.util.Objects.requireNonNull;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.Flow.Publisher;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;
import mutiny.zero.internal.*;
/**
* Factory methods to simplify the creation of reactive streams compliant {@link Publisher}.
*
* There are convenience methods for creating {@link Publisher} from in-memory data.
*
* The general-purpose abstraction is to use a {@link Tube} and the {@link #create(TubeConfiguration, Consumer)}
* factory method.
*/
public interface ZeroPublisher {
// ---- "Iterate over something" ---- //
/**
* Create a {@link Publisher} from existing items.
*
* @param items the existing items, cannot be a {@code null array}
* @param the items type
* @return a new {@link Publisher}
*/
@SafeVarargs
static Publisher fromItems(T... items) {
requireNonNull(items, "The items array cannot be null");
return fromIterable(Arrays.asList(items));
}
/**
* Create a {@link Publisher} from an iterable object.
*
* Note that this assumes an in-memory, non-blocking {@link java.util.Iterator}.
* Do not try to force an iterator as a way to bridge an API with {@link Publisher} as it does not behave like an
* in-memory data structure.
*
* @param iterable the iterable object, cannot be {@code null}
* @param the items type
* @return a nes {@link Publisher}
*/
static Publisher fromIterable(Iterable iterable) {
requireNonNull(iterable, "The iterable cannot be null");
return new IterablePublisher<>(iterable);
}
/**
* Create a {@link Publisher} from a {@link java.util.stream.Stream}.
*
* Note that this assumes an in-memory, non-blocking data structure, just like {@link #fromIterable(Iterable)}.
* Also note that a {@link java.util.stream.Stream} can only be traversed once, hence the use of a supplier because
* multiple subscriptions would fail.
*
* @param supplier the stream supplier, cannot be {@code null}
* @param the items type
* @return a new {@link Publisher}
*/
static Publisher fromStream(Supplier> supplier) {
requireNonNull(supplier, "The supplier cannot be null");
return new StreamPublisher<>(supplier);
}
/**
* Create a {@link Publisher} from a generator over some state.
*
* Note that this assumes an in-memory, non-blocking data structure, just like {@link #fromIterable(Iterable)}.
*
* @param stateSupplier the initial state supplier, cannot be {@code null} but can supply {@code null}
* @param generator a generator function over the initial state and an iterator, cannot be {@code null}, cannot yield
* {@code null}
* @param the initial state type
* @param the items type
* @return a new {@link Publisher}
*/
static Publisher fromGenerator(Supplier stateSupplier, Function> generator) {
requireNonNull(stateSupplier, "The state supplier cannot be null");
requireNonNull(generator, "The generator supplier cannot be null");
return new GeneratorPublisher<>(stateSupplier, generator);
}
// ---- CompletionStage integration ---- //
/**
* Create a {@link Publisher} from a {@link CompletionStage}.
*
* @param completionStageSupplier the completion stage supplier, cannot be {@code null}, cannot yield {@code null}
* @param the item type
* @return a new {@link Publisher}
*/
static Publisher fromCompletionStage(Supplier> completionStageSupplier) {
requireNonNull(completionStageSupplier, "The CompletionStage supplier cannot be null");
return new CompletionStagePublisher<>(completionStageSupplier);
}
/**
* Create a {@link CompletionStage} from a {@link Publisher}.
*
* The {@link Publisher} is requested exactly 1 element and the subscription is cancelled after it has been received.
*
* @param publisher the publisher, cannot be {@code null}
* @param the item type
* @return a new {@link CompletionStage}
*/
static CompletionStage> toCompletionStage(Publisher publisher) {
requireNonNull(publisher, "The publisher cannot be null");
CompletableFuture> future = new CompletableFuture<>();
publisher.subscribe(new PublisherToCompletionStageSubscriber<>(future));
return future;
}
// ---- Special cases ---- //
/**
* Create a {@link Publisher} from a known failure.
*
* @param failure the failure, cannot be {@code null}
* @param the items type
* @return a new {@link Publisher}
*/
static Publisher fromFailure(Throwable failure) {
requireNonNull(failure, "The failure cannot be null");
return new FailurePublisher<>(failure);
}
/**
* Create an empty {@link Publisher} that completes upon subscription without ever sending any item.
*
* @param the items type
* @return a new {@link Publisher}
*/
static Publisher empty() {
return new EmptyPublisher<>();
}
// ---- Tube / DIY ---- //
/**
* Create a new {@link Publisher} with the general-purpose {@link Tube} API.
*
* @param configuration the tube configuration
* @param tubeConsumer the tube consumer, cannot be {@code null}
* @param the items type
* @return a new {@link Publisher}
*/
static Publisher create(TubeConfiguration configuration, Consumer> tubeConsumer) {
requireNonNull(configuration.getBackpressureStrategy(), "The backpressure strategy cannot be null");
requireNonNull(tubeConsumer, "The tube consumer cannot be null");
if (((configuration.getBackpressureStrategy() == BackpressureStrategy.BUFFER)
|| (configuration.getBackpressureStrategy() == BackpressureStrategy.LATEST))
&& configuration.getBufferSize() <= 0) {
throw new IllegalArgumentException("The buffer size must be strictly positive");
}
return new TubePublisher<>(configuration, tubeConsumer);
}
}