diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index eb84db68da7..a9db11550c6 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip networkTimeout=10000 retries=0 retryBackOffMs=500 diff --git a/src/jmh/java/io/reactivex/rxjava4/core/OperatorMergePerf.java b/src/jmh/java/io/reactivex/rxjava4/core/OperatorMergePerf.java index 58631d56a67..461ab98186f 100644 --- a/src/jmh/java/io/reactivex/rxjava4/core/OperatorMergePerf.java +++ b/src/jmh/java/io/reactivex/rxjava4/core/OperatorMergePerf.java @@ -83,7 +83,7 @@ public void mergeNAsyncStreamsOfN(final InputThousand input) throws InterruptedE public void mergeTwoAsyncStreamsOfN(final InputThousand input) throws InterruptedException { PerfSubscriber o = input.newLatchedObserver(); Flowable ob = Flowable.range(0, input.size).subscribeOn(Schedulers.computation()); - Flowable.merge(ob, ob).subscribe(o); + Flowable.mergeArray(ob, ob).subscribe(o); if (input.size == 1) { while (o.latch.getCount() != 0) { } } else { diff --git a/src/main/java/io/reactivex/rxjava4/core/Completable.java b/src/main/java/io/reactivex/rxjava4/core/Completable.java index 8eb9f4a9ace..a702fa7e7e1 100644 --- a/src/main/java/io/reactivex/rxjava4/core/Completable.java +++ b/src/main/java/io/reactivex/rxjava4/core/Completable.java @@ -220,7 +220,8 @@ public static Completable concatArray(@NonNull StandardBufferedConfig config, @N return wrap(sources[0]); } if (config.delayErrors()) { - return Flowable.fromArray(sources).concatMapCompletableDelayError(Functions.identity(), true, config.bufferSize()); + return Flowable.fromArray(sources) + .concatMapCompletable(Functions.identity(), config); } return RxJavaPlugins.onAssembly(new CompletableConcatArray(sources)); @@ -283,7 +284,6 @@ public static Completable concat(@NonNull Publisher<@NonNull ? extends Completab * @param config the operatar configuration record * @return the new {@code Completable} instance * @throws NullPointerException if {@code sources} or {@code config} is {@code null} - * @throws IllegalArgumentException if {@code prefetch} is non-positive * @since 4.0.0 */ @CheckReturnValue @@ -295,7 +295,8 @@ public static Completable concat(@NonNull Publisher<@NonNull ? extends Completab Objects.requireNonNull(sources, "sources is null"); Objects.requireNonNull(config, "config is null"); if (config.delayErrors()) { - return Flowable.fromPublisher(sources).concatMapCompletableDelayError(Functions.identity(), true, config.bufferSize()); + return Flowable.fromPublisher(sources) + .concatMapCompletable(Functions.identity(), config); } return RxJavaPlugins.onAssembly(new CompletableConcat(sources, config.bufferSize())); } @@ -321,7 +322,8 @@ public static Completable concat(@NonNull Iterable<@NonNull ? extends Completabl Objects.requireNonNull(sources, "sources is null"); Objects.requireNonNull(config, "config is null"); if (config.delayErrors()) { - return Flowable.fromIterable(sources).concatMapCompletableDelayError(Functions.identity(), true, config.bufferSize()); + return Flowable.fromIterable(sources) + .concatMapCompletable(Functions.identity(), config); } return RxJavaPlugins.onAssembly(new CompletableConcatIterable(sources)); } @@ -870,7 +872,6 @@ public static Completable merge(@NonNull Publisher<@NonNull ? extends Completabl * @param config the configuration record for this operator * @return the new {@code Completable} instance * @throws NullPointerException if {@code sources} or {@code config} is {@code null} - * @throws IllegalArgumentException if {@code maxConcurrency} is less than 1 * @since 4.0.0 */ @CheckReturnValue @@ -898,6 +899,7 @@ public static Completable merge(@NonNull Publisher<@NonNull ? extends Completabl * @param config the configuration record for this operator * @return the new {@code Completable} instance * @throws NullPointerException if {@code sources} or {@code config} is {@code null} + * @since 4.0.0 */ @CheckReturnValue @NonNull diff --git a/src/main/java/io/reactivex/rxjava4/core/Flowable.java b/src/main/java/io/reactivex/rxjava4/core/Flowable.java index 76218b94250..7bf840d8a32 100644 --- a/src/main/java/io/reactivex/rxjava4/core/Flowable.java +++ b/src/main/java/io/reactivex/rxjava4/core/Flowable.java @@ -350,11 +350,11 @@ public static int bufferSize() { public static <@NonNull T, @NonNull R> Flowable combineLatestArray(@NonNull Publisher[] sources, @NonNull Function combiner, @NonNull StandardBufferedConfig config) { Objects.requireNonNull(sources, "sources is null"); + Objects.requireNonNull(combiner, "combiner is null"); + Objects.requireNonNull(config, "config is null"); if (sources.length == 0) { return empty(); } - Objects.requireNonNull(combiner, "combiner is null"); - Objects.requireNonNull(config, "config is null"); return RxJavaPlugins.onAssembly(new FlowableCombineLatest<>(sources, combiner, config.bufferSize(), config.delayErrors())); } @@ -1016,14 +1016,13 @@ public static int bufferSize() { * @throws NullPointerException if {@code sources} or {@code config} is {@code null} * @since 4.0.0 */ - @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) public static <@NonNull T> Flowable concat(@NonNull Iterable<@NonNull ? extends Publisher> sources, @NonNull StandardBufferedConfig config) { - return fromIterable(sources).concatMap((Function)Functions.identity(), config); + return fromIterable(sources).concatMap(Functions.identity(), config); } /** @@ -1081,14 +1080,13 @@ public static int bufferSize() { * @see ReactiveX operators documentation: Concat * @since 4.0.0 */ - @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull public static <@NonNull T> Flowable concat(@NonNull Publisher<@NonNull ? extends Publisher> sources, @NonNull StandardBufferedConfig config) { - return fromPublisher(sources).concatMap((Function)Functions.identity(), config); + return fromPublisher(sources).concatMap(Functions.identity(), config); } /** @@ -1263,7 +1261,7 @@ public static int bufferSize() { @SchedulerSupport(SchedulerSupport.NONE) @NonNull public static <@NonNull T> Flowable concatEager(@NonNull Iterable<@NonNull ? extends Publisher> sources) { - return concatEager(sources, bufferSize(), bufferSize()); + return concatEager(sources, StandardConcurrentBufferedConfig.DELAY_ERRORS_BOUNDARY); } /** @@ -1285,24 +1283,22 @@ public static int bufferSize() { * * @param the value type * @param sources a sequence of {@code Publisher}s that need to be eagerly concatenated - * @param maxConcurrency the maximum number of concurrently running inner {@code Publisher}s; {@link Integer#MAX_VALUE} - * is interpreted as all inner {@code Publisher}s can be active at the same time - * @param prefetch the number of elements to prefetch from each inner {@code Publisher} source + * @param config the configuration record for this operator * @return the new {@code Flowable} instance with the specified concatenation behavior - * @throws NullPointerException if {@code sources} is {@code null} - * @throws IllegalArgumentException if {@code maxConcurrency} or {@code prefetch} is non-positive - * @since 2.0 + * @throws NullPointerException if {@code sources} and {@code config} is {@code null} + * @since 4.0.0 */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @SuppressWarnings({ "rawtypes", "unchecked" }) - public static <@NonNull T> Flowable concatEager(@NonNull Iterable<@NonNull ? extends Publisher> sources, int maxConcurrency, int prefetch) { + public static <@NonNull T> Flowable concatEager(@NonNull Iterable<@NonNull ? extends Publisher> sources, + @NonNull StandardConcurrentBufferedConfig config) { Objects.requireNonNull(sources, "sources is null"); - ObjectHelper.verifyPositive(maxConcurrency, "maxConcurrency"); - ObjectHelper.verifyPositive(prefetch, "prefetch"); - return RxJavaPlugins.onAssembly(new FlowableConcatMapEager(new FlowableFromIterable(sources), Functions.identity(), maxConcurrency, prefetch, ErrorMode.BOUNDARY)); + Objects.requireNonNull(config, "config is null"); + return RxJavaPlugins.onAssembly(new FlowableConcatMapEager(new FlowableFromIterable(sources), + Functions.identity(), config.maxConcurrency(), config.bufferSize(), config.errorMode())); } /** @@ -1332,7 +1328,7 @@ public static int bufferSize() { @SchedulerSupport(SchedulerSupport.NONE) @NonNull public static <@NonNull T> Flowable concatEager(@NonNull Publisher<@NonNull ? extends Publisher> sources) { - return concatEager(sources, bufferSize(), bufferSize()); + return concatEager(sources, StandardConcurrentBufferedConfig.DELAY_ERRORS_BOUNDARY); } /** @@ -1354,166 +1350,22 @@ public static int bufferSize() { * * @param the value type * @param sources a sequence of {@code Publisher}s that need to be eagerly concatenated - * @param maxConcurrency the maximum number of concurrently running inner {@code Publisher}s; {@link Integer#MAX_VALUE} - * is interpreted as all inner {@code Publisher}s can be active at the same time - * @param prefetch the number of elements to prefetch from each inner {@code Publisher} source - * @return the new {@code Flowable} instance with the specified concatenation behavior - * @throws NullPointerException if {@code sources} is {@code null} - * @throws IllegalArgumentException if {@code maxConcurrency} or {@code prefetch} is non-positive - * @since 2.0 - */ - @CheckReturnValue - @NonNull - @BackpressureSupport(BackpressureKind.FULL) - @SchedulerSupport(SchedulerSupport.NONE) - @SuppressWarnings({ "rawtypes", "unchecked" }) - public static <@NonNull T> Flowable concatEager(@NonNull Publisher<@NonNull ? extends Publisher> sources, int maxConcurrency, int prefetch) { - Objects.requireNonNull(sources, "sources is null"); - ObjectHelper.verifyPositive(maxConcurrency, "maxConcurrency"); - ObjectHelper.verifyPositive(prefetch, "prefetch"); - return RxJavaPlugins.onAssembly(new FlowableConcatMapEagerPublisher(sources, Functions.identity(), maxConcurrency, prefetch, ErrorMode.IMMEDIATE)); - } - - /** - * Concatenates a sequence of {@link Publisher}s eagerly into a single stream of values, - * delaying errors until all the inner sequences terminate. - *

- * - *

- * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the - * source {@code Publisher}s. The operator buffers the values emitted by these {@code Publisher}s and then drains them - * in order, each one after the previous one completes. - *

- *
Backpressure:
- *
Backpressure is honored towards the downstream and the inner {@code Publisher}s are - * expected to support backpressure. Violating this assumption, the operator will - * signal {@link MissingBackpressureException}.
- *
Scheduler:
- *
This method does not operate by default on a particular {@link Scheduler}.
- *
- * @param the value type - * @param sources a sequence of {@code Publisher}s that need to be eagerly concatenated - * @return the new {@code Flowable} instance with the specified concatenation behavior - * @throws NullPointerException if {@code sources} is {@code null} - * @since 3.0.0 - */ - @CheckReturnValue - @BackpressureSupport(BackpressureKind.FULL) - @SchedulerSupport(SchedulerSupport.NONE) - @NonNull - public static <@NonNull T> Flowable concatEagerDelayError(@NonNull Iterable<@NonNull ? extends Publisher> sources) { - return concatEagerDelayError(sources, bufferSize(), bufferSize()); - } - - /** - * Concatenates a sequence of {@link Publisher}s eagerly into a single stream of values, - * delaying errors until all the inner sequences terminate and runs a limited number - * of inner sequences at once. - *

- * - *

- * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the - * source {@code Publisher}s. The operator buffers the values emitted by these {@code Publisher}s and then drains them - * in order, each one after the previous one completes. - *

- *
Backpressure:
- *
Backpressure is honored towards the downstream and both the outer and inner {@code Publisher}s are - * expected to support backpressure. Violating this assumption, the operator will - * signal {@link MissingBackpressureException}.
- *
Scheduler:
- *
This method does not operate by default on a particular {@link Scheduler}.
- *
- * @param the value type - * @param sources a sequence of {@code Publisher}s that need to be eagerly concatenated - * @param maxConcurrency the maximum number of concurrently running inner {@code Publisher}s; {@link Integer#MAX_VALUE} - * is interpreted as all inner {@code Publisher}s can be active at the same time - * @param prefetch the number of elements to prefetch from each inner {@code Publisher} source - * @return the new {@code Flowable} instance with the specified concatenation behavior - * @throws NullPointerException if {@code sources} is {@code null} - * @throws IllegalArgumentException if {@code maxConcurrency} or {@code prefetch} is non-positive - * @since 3.0.0 - */ - @CheckReturnValue - @NonNull - @BackpressureSupport(BackpressureKind.FULL) - @SchedulerSupport(SchedulerSupport.NONE) - @SuppressWarnings({ "rawtypes", "unchecked" }) - public static <@NonNull T> Flowable concatEagerDelayError(@NonNull Iterable<@NonNull ? extends Publisher> sources, int maxConcurrency, int prefetch) { - Objects.requireNonNull(sources, "sources is null"); - ObjectHelper.verifyPositive(maxConcurrency, "maxConcurrency"); - ObjectHelper.verifyPositive(prefetch, "prefetch"); - return RxJavaPlugins.onAssembly(new FlowableConcatMapEager(new FlowableFromIterable(sources), Functions.identity(), maxConcurrency, prefetch, ErrorMode.END)); - } - - /** - * Concatenates a {@link Publisher} sequence of {@code Publisher}s eagerly into a single stream of values, - * delaying errors until all the inner and the outer sequences terminate. - *

- * - *

- * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the - * emitted source {@code Publisher}s as they are observed. The operator buffers the values emitted by these - * {@code Publisher}s and then drains them in order, each one after the previous one completes. - *

- *
Backpressure:
- *
Backpressure is honored towards the downstream and both the outer and inner {@code Publisher}s are - * expected to support backpressure. Violating this assumption, the operator will - * signal {@link MissingBackpressureException}.
- *
Scheduler:
- *
This method does not operate by default on a particular {@link Scheduler}.
- *
- * @param the value type - * @param sources a sequence of {@code Publisher}s that need to be eagerly concatenated - * @return the new {@code Flowable} instance with the specified concatenation behavior - * @throws NullPointerException if {@code sources} is {@code null} - * @since 3.0.0 - */ - @CheckReturnValue - @BackpressureSupport(BackpressureKind.FULL) - @SchedulerSupport(SchedulerSupport.NONE) - @NonNull - public static <@NonNull T> Flowable concatEagerDelayError(@NonNull Publisher<@NonNull ? extends Publisher> sources) { - return concatEagerDelayError(sources, bufferSize(), bufferSize()); - } - - /** - * Concatenates a {@link Publisher} sequence of {@code Publisher}s eagerly into a single stream of values, - * delaying errors until all the inner and outer sequences terminate and runs a limited number of inner - * sequences at once. - *

- * - *

- * Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the - * emitted source {@code Publisher}s as they are observed. The operator buffers the values emitted by these - * {@code Publisher}s and then drains them in order, each one after the previous one completes. - *

- *
Backpressure:
- *
Backpressure is honored towards the downstream and both the outer and inner {@code Publisher}s are - * expected to support backpressure. Violating this assumption, the operator will - * signal {@link MissingBackpressureException}.
- *
Scheduler:
- *
This method does not operate by default on a particular {@link Scheduler}.
- *
- * @param the value type - * @param sources a sequence of {@code Publisher}s that need to be eagerly concatenated - * @param maxConcurrency the maximum number of concurrently running inner {@code Publisher}s; {@link Integer#MAX_VALUE} - * is interpreted as all inner {@code Publisher}s can be active at the same time - * @param prefetch the number of elements to prefetch from each inner {@code Publisher} source + * @param config the configuration record for this operator * @return the new {@code Flowable} instance with the specified concatenation behavior - * @throws NullPointerException if {@code sources} is {@code null} - * @throws IllegalArgumentException if {@code maxConcurrency} or {@code prefetch} is non-positive - * @since 3.0.0 + * @throws NullPointerException if {@code sources} or {@code config} is {@code null} + * @since 4.0.0 */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @SuppressWarnings({ "rawtypes", "unchecked" }) - public static <@NonNull T> Flowable concatEagerDelayError(@NonNull Publisher<@NonNull ? extends Publisher> sources, int maxConcurrency, int prefetch) { + public static <@NonNull T> Flowable concatEager(@NonNull Publisher<@NonNull ? extends Publisher> sources, + @NonNull StandardConcurrentBufferedConfig config) { Objects.requireNonNull(sources, "sources is null"); - ObjectHelper.verifyPositive(maxConcurrency, "maxConcurrency"); - ObjectHelper.verifyPositive(prefetch, "prefetch"); - return RxJavaPlugins.onAssembly(new FlowableConcatMapEagerPublisher(sources, Functions.identity(), maxConcurrency, prefetch, ErrorMode.END)); + Objects.requireNonNull(config, "config is null"); + return RxJavaPlugins.onAssembly(new FlowableConcatMapEagerPublisher(sources, Functions.identity(), + config.maxConcurrency(), config.bufferSize(), config.errorMode())); } /** @@ -3037,32 +2889,26 @@ public static Flowable intervalRange(long start, long count, long initialD * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s * signaled by source(s) after the returned {@code Flowable} has been cancelled or terminated with a * (composite) error will be sent to the same global error handler. - * Use {@link #mergeDelayError(Iterable, int, int)} to merge sources and terminate only when all source {@code Publisher}s - * have completed or failed with an error. * * * * @param the common element base type * @param sources * the {@code Iterable} of {@code Publisher}s - * @param maxConcurrency - * the maximum number of {@code Publisher}s that may be subscribed to concurrently - * @param bufferSize - * the number of items to prefetch from each inner {@code Publisher} + * @param config + * the configuration record for this operator * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code sources} is {@code null} - * @throws IllegalArgumentException - * if {@code maxConcurrency} or {@code bufferSize} is non-positive + * @throws NullPointerException if {@code sources} or {@code config} is {@code null} * @see ReactiveX operators documentation: Merge - * @see #mergeDelayError(Iterable, int, int) + * @since 4.0.0 */ - @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static <@NonNull T> Flowable merge(@NonNull Iterable<@NonNull ? extends Publisher> sources, int maxConcurrency, int bufferSize) { - return fromIterable(sources).flatMap((Function)Functions.identity(), new StandardConcurrentBufferedConfig(false, maxConcurrency, bufferSize)); + public static <@NonNull T> Flowable merge(@NonNull Iterable<@NonNull ? extends Publisher> sources, + @NonNull StandardConcurrentBufferedConfig config) { + return fromIterable(sources).flatMap(Functions.identity(), config); } /** @@ -3089,33 +2935,27 @@ public static Flowable intervalRange(long start, long count, long initialD * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s * signaled by source(s) after the returned {@code Flowable} has been cancelled or terminated with a * (composite) error will be sent to the same global error handler. - * Use {@link #mergeArrayDelayError(int, int, Publisher[])} to merge sources and terminate only when all source {@code Publisher}s - * have completed or failed with an error. * * * * @param the common element base type * @param sources * the array of {@code Publisher}s - * @param maxConcurrency - * the maximum number of {@code Publisher}s that may be subscribed to concurrently - * @param bufferSize - * the number of items to prefetch from each inner {@code Publisher} + * @param config + * the configuration record for this operator * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code sources} is {@code null} - * @throws IllegalArgumentException - * if {@code maxConcurrency} or {@code bufferSize} is non-positive + * @throws NullPointerException if {@code sources} or {@code config} is {@code null} * @see ReactiveX operators documentation: Merge - * @see #mergeArrayDelayError(int, int, Publisher...) + * @since 4.0.0 */ - @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @SafeVarargs @NonNull - public static <@NonNull T> Flowable mergeArray(int maxConcurrency, int bufferSize, @NonNull Publisher... sources) { - return fromArray(sources).flatMap((Function)Functions.identity(), new StandardConcurrentBufferedConfig(false, maxConcurrency, bufferSize)); + public static <@NonNull T> Flowable mergeArray(@NonNull StandardConcurrentBufferedConfig config, + @NonNull Publisher... sources) { + return fromArray(sources).flatMap(Functions.identity(), config); } /** @@ -3141,8 +2981,6 @@ public static Flowable intervalRange(long start, long count, long initialD * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s * signaled by source(s) after the returned {@code Flowable} has been cancelled or terminated with a * (composite) error will be sent to the same global error handler. - * Use {@link #mergeDelayError(Iterable)} to merge sources and terminate only when all source {@code Publisher}s - * have completed or failed with an error. * * * @@ -3152,65 +2990,13 @@ public static Flowable intervalRange(long start, long count, long initialD * @return the new {@code Flowable} instance * @throws NullPointerException if {@code sources} is {@code null} * @see ReactiveX operators documentation: Merge - * @see #mergeDelayError(Iterable) */ - @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull public static <@NonNull T> Flowable merge(@NonNull Iterable<@NonNull ? extends Publisher> sources) { - return fromIterable(sources).flatMap((Function)Functions.identity()); - } - - /** - * Flattens an {@link Iterable} of {@link Publisher}s into one {@code Publisher}, without any transformation, while limiting the - * number of concurrent subscriptions to these {@code Publisher}s. - *

- * - *

- * You can combine the items emitted by multiple {@code Publisher}s so that they appear as a single {@code Publisher}, by - * using the {@code merge} method. - *

- *
Backpressure:
- *
The operator honors backpressure from downstream. The source {@code Publisher}s are expected to honor - * backpressure; if violated, the operator may signal {@link MissingBackpressureException}.
- *
Scheduler:
- *
{@code merge} does not operate by default on a particular {@link Scheduler}.
- *
Error handling:
- *
If any of the source {@code Publisher}s signal a {@link Throwable} via {@code onError}, the resulting - * {@code Flowable} terminates with that {@code Throwable} and all other source {@code Publisher}s are cancelled. - * If more than one {@code Publisher} signals an error, the resulting {@code Flowable} may terminate with the - * first one's error or, depending on the concurrency of the sources, may terminate with a - * {@link CompositeException} containing two or more of the various error signals. - * {@code Throwable}s that didn't make into the composite will be sent (individually) to the global error handler via - * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s - * signaled by source(s) after the returned {@code Flowable} has been cancelled or terminated with a - * (composite) error will be sent to the same global error handler. - * Use {@link #mergeDelayError(Iterable, int)} to merge sources and terminate only when all source {@code Publisher}s - * have completed or failed with an error. - *
- *
- * - * @param the common element base type - * @param sources - * the {@code Iterable} of {@code Publisher}s - * @param maxConcurrency - * the maximum number of {@code Publisher}s that may be subscribed to concurrently - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code sources} is {@code null} - * @throws IllegalArgumentException - * if {@code maxConcurrency} is less than or equal to 0 - * @see ReactiveX operators documentation: Merge - * @see #mergeDelayError(Iterable, int) - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - @CheckReturnValue - @BackpressureSupport(BackpressureKind.FULL) - @SchedulerSupport(SchedulerSupport.NONE) - @NonNull - public static <@NonNull T> Flowable merge(@NonNull Iterable<@NonNull ? extends Publisher> sources, int maxConcurrency) { - return fromIterable(sources).flatMap((Function)Functions.identity(), new StandardConcurrentBufferedConfig(maxConcurrency)); + return fromIterable(sources).flatMap(Functions.identity()); } /** @@ -3238,8 +3024,6 @@ public static Flowable intervalRange(long start, long count, long initialD * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s * signaled by source(s) after the returned {@code Flowable} has been cancelled or terminated with a * (composite) error will be sent to the same global error handler. - * Use {@link #mergeDelayError(Publisher)} to merge sources and terminate only when all source {@code Publisher}s - * have completed or failed with an error. * * * @@ -3249,14 +3033,14 @@ public static Flowable intervalRange(long start, long count, long initialD * @return the new {@code Flowable} instance * @throws NullPointerException if {@code sources} is {@code null} * @see ReactiveX operators documentation: Merge - * @see #mergeDelayError(Publisher) + * @see #merge(Publisher, StandardConcurrentBufferedConfig) */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull public static <@NonNull T> Flowable merge(@NonNull Publisher<@NonNull ? extends Publisher> sources) { - return merge(sources, bufferSize()); + return merge(sources, StandardConcurrentBufferedConfig.DEFAULT); } /** @@ -3284,31 +3068,26 @@ public static Flowable intervalRange(long start, long count, long initialD * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s * signaled by source(s) after the returned {@code Flowable} has been cancelled or terminated with a * (composite) error will be sent to the same global error handler. - * Use {@link #mergeDelayError(Publisher, int)} to merge sources and terminate only when all source {@code Publisher}s - * have completed or failed with an error. * * * * @param the common element base type * @param sources * a {@code Publisher} that emits {@code Publisher}s - * @param maxConcurrency - * the maximum number of {@code Publisher}s that may be subscribed to concurrently + * @param config + * the configuration record for this operator * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code sources} is {@code null} - * @throws IllegalArgumentException - * if {@code maxConcurrency} is less than or equal to 0 + * @throws NullPointerException if {@code sources} or {@code config} is {@code null} * @see ReactiveX operators documentation: Merge - * @see #mergeDelayError(Publisher, int) - * @since 1.1.0 + * @since 4.0.0 */ - @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static <@NonNull T> Flowable merge(@NonNull Publisher<@NonNull ? extends Publisher> sources, int maxConcurrency) { - return fromPublisher(sources).flatMap((Function)Functions.identity(), new StandardConcurrentBufferedConfig(maxConcurrency)); + public static <@NonNull T> Flowable merge(@NonNull Publisher<@NonNull ? extends Publisher> sources, + @NonNull StandardConcurrentBufferedConfig config) { + return fromPublisher(sources).flatMap(Functions.identity(), config); } /** @@ -3334,8 +3113,6 @@ public static Flowable intervalRange(long start, long count, long initialD * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s * signaled by source(s) after the returned {@code Flowable} has been cancelled or terminated with a * (composite) error will be sent to the same global error handler. - * Use {@link #mergeArrayDelayError(Publisher...)} to merge sources and terminate only when all source {@code Publisher}s - * have completed or failed with an error. * * * @@ -3345,626 +3122,50 @@ public static Flowable intervalRange(long start, long count, long initialD * @return the new {@code Flowable} instance * @throws NullPointerException if {@code sources} is {@code null} * @see ReactiveX operators documentation: Merge - * @see #mergeArrayDelayError(Publisher...) */ - @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @SafeVarargs @NonNull public static <@NonNull T> Flowable mergeArray(@NonNull Publisher... sources) { - return fromArray(sources).flatMap((Function)Functions.identity(), new StandardConcurrentBufferedConfig(sources.length)); + return fromArray(sources).flatMap(Functions.identity(), new StandardConcurrentBufferedConfig(sources.length)); } /** - * Flattens two {@link Publisher}s into a single {@code Publisher}, without any transformation. + * Returns a {@code Flowable} that never sends any items or notifications to a {@link Subscriber}. *

- * + * *

- * You can combine items emitted by multiple {@code Publisher}s so that they appear as a single {@code Publisher}, by - * using the {@code merge} method. + * This {@link Publisher} is useful primarily for testing purposes. *

*
Backpressure:
- *
The operator honors backpressure from downstream. The source {@code Publisher}s are expected to honor - * backpressure; if violated, the operator may signal {@link MissingBackpressureException}.
+ *
This source doesn't produce any elements and effectively ignores downstream backpressure.
*
Scheduler:
- *
{@code merge} does not operate by default on a particular {@link Scheduler}.
- *
Error handling:
- *
If any of the source {@code Publisher}s signal a {@link Throwable} via {@code onError}, the resulting - * {@code Flowable} terminates with that {@code Throwable} and all other source {@code Publisher}s are cancelled. - * If more than one {@code Publisher} signals an error, the resulting {@code Flowable} may terminate with the - * first one's error or, depending on the concurrency of the sources, may terminate with a - * {@link CompositeException} containing two or more of the various error signals. - * {@code Throwable}s that didn't make into the composite will be sent (individually) to the global error handler via - * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s - * signaled by source(s) after the returned {@code Flowable} has been cancelled or terminated with a - * (composite) error will be sent to the same global error handler. - * Use {@link #mergeDelayError(Publisher, Publisher)} to merge sources and terminate only when all source {@code Publisher}s - * have completed or failed with an error. - *
+ *
{@code never} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the common element base type - * @param source1 - * a {@code Publisher} to be merged - * @param source2 - * a {@code Publisher} to be merged - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code source1} or {@code source2} is {@code null} - * @see ReactiveX operators documentation: Merge - * @see #mergeDelayError(Publisher, Publisher) + * @param + * the type of items (not) emitted by the {@code Publisher} + * @return the shared {@code Flowable} instance + * @see ReactiveX operators documentation: Never */ - @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue - @NonNull - @BackpressureSupport(BackpressureKind.FULL) + @BackpressureSupport(BackpressureKind.PASS_THROUGH) @SchedulerSupport(SchedulerSupport.NONE) - public static <@NonNull T> Flowable merge(@NonNull Publisher source1, @NonNull Publisher source2) { - Objects.requireNonNull(source1, "source1 is null"); - Objects.requireNonNull(source2, "source2 is null"); - return fromArray(source1, source2).flatMap((Function)Functions.identity(), new StandardConcurrentBufferedConfig(false, 2)); + @SuppressWarnings("unchecked") + @NonNull + public static <@NonNull T> Flowable never() { + return RxJavaPlugins.onAssembly((Flowable) FlowableNever.INSTANCE); } /** - * Flattens three {@link Publisher}s into a single {@code Publisher}, without any transformation. - *

- * + * Returns a {@code Flowable} that emits a sequence of {@link Integer}s within a specified range. *

- * You can combine items emitted by multiple {@code Publisher}s so that they appear as a single {@code Publisher}, by - * using the {@code merge} method. + * *

*
Backpressure:
- *
The operator honors backpressure from downstream. The source {@code Publisher}s are expected to honor - * backpressure; if violated, the operator may signal {@link MissingBackpressureException}.
- *
Scheduler:
- *
{@code merge} does not operate by default on a particular {@link Scheduler}.
- *
Error handling:
- *
If any of the source {@code Publisher}s signal a {@link Throwable} via {@code onError}, the resulting - * {@code Flowable} terminates with that {@code Throwable} and all other source {@code Publisher}s are cancelled. - * If more than one {@code Publisher} signals an error, the resulting {@code Flowable} may terminate with the - * first one's error or, depending on the concurrency of the sources, may terminate with a - * {@link CompositeException} containing two or more of the various error signals. - * {@code Throwable}s that didn't make into the composite will be sent (individually) to the global error handler via - * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s - * signaled by source(s) after the returned {@code Flowable} has been cancelled or terminated with a - * (composite) error will be sent to the same global error handler. - * Use {@link #mergeDelayError(Publisher, Publisher, Publisher)} to merge sources and terminate only when all source {@code Publisher}s - * have completed or failed with an error. - *
- *
- * - * @param the common element base type - * @param source1 - * a {@code Publisher} to be merged - * @param source2 - * a {@code Publisher} to be merged - * @param source3 - * a {@code Publisher} to be merged - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code source1}, {@code source2} or {@code source3} is {@code null} - * @see ReactiveX operators documentation: Merge - * @see #mergeDelayError(Publisher, Publisher, Publisher) - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - @CheckReturnValue - @NonNull - @BackpressureSupport(BackpressureKind.FULL) - @SchedulerSupport(SchedulerSupport.NONE) - public static <@NonNull T> Flowable merge(@NonNull Publisher source1, @NonNull Publisher source2, @NonNull Publisher source3) { - Objects.requireNonNull(source1, "source1 is null"); - Objects.requireNonNull(source2, "source2 is null"); - Objects.requireNonNull(source3, "source3 is null"); - return fromArray(source1, source2, source3).flatMap((Function)Functions.identity(), new StandardConcurrentBufferedConfig(false, 3)); - } - - /** - * Flattens four {@link Publisher}s into a single {@code Publisher}, without any transformation. - *

- * - *

- * You can combine items emitted by multiple {@code Publisher}s so that they appear as a single {@code Publisher}, by - * using the {@code merge} method. - *

- *
Backpressure:
- *
The operator honors backpressure from downstream. The source {@code Publisher}s are expected to honor - * backpressure; if violated, the operator may signal {@link MissingBackpressureException}.
- *
Scheduler:
- *
{@code merge} does not operate by default on a particular {@link Scheduler}.
- *
Error handling:
- *
If any of the source {@code Publisher}s signal a {@link Throwable} via {@code onError}, the resulting - * {@code Flowable} terminates with that {@code Throwable} and all other source {@code Publisher}s are cancelled. - * If more than one {@code Publisher} signals an error, the resulting {@code Flowable} may terminate with the - * first one's error or, depending on the concurrency of the sources, may terminate with a - * {@link CompositeException} containing two or more of the various error signals. - * {@code Throwable}s that didn't make into the composite will be sent (individually) to the global error handler via - * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. Similarly, {@code Throwable}s - * signaled by source(s) after the returned {@code Flowable} has been cancelled or terminated with a - * (composite) error will be sent to the same global error handler. - * Use {@link #mergeDelayError(Publisher, Publisher, Publisher, Publisher)} to merge sources and terminate only when all source {@code Publisher}s - * have completed or failed with an error. - *
- *
- * - * @param the common element base type - * @param source1 - * a {@code Publisher} to be merged - * @param source2 - * a {@code Publisher} to be merged - * @param source3 - * a {@code Publisher} to be merged - * @param source4 - * a {@code Publisher} to be merged - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3} or {@code source4} is {@code null} - * @see ReactiveX operators documentation: Merge - * @see #mergeDelayError(Publisher, Publisher, Publisher, Publisher) - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - @CheckReturnValue - @NonNull - @BackpressureSupport(BackpressureKind.FULL) - @SchedulerSupport(SchedulerSupport.NONE) - public static <@NonNull T> Flowable merge( - @NonNull Publisher source1, @NonNull Publisher source2, - @NonNull Publisher source3, @NonNull Publisher source4) { - Objects.requireNonNull(source1, "source1 is null"); - Objects.requireNonNull(source2, "source2 is null"); - Objects.requireNonNull(source3, "source3 is null"); - Objects.requireNonNull(source4, "source4 is null"); - return fromArray(source1, source2, source3, source4).flatMap((Function)Functions.identity(), new StandardConcurrentBufferedConfig(false, 4)); - } - - /** - * Flattens an {@link Iterable} of {@link Publisher}s into one {@code Publisher}, in a way that allows a {@link Subscriber} to receive all - * successfully emitted items from each of the source {@code Publisher}s without being interrupted by an error - * notification from one of them. - *

- * This behaves like {@link #merge(Publisher)} except that if any of the merged {@code Publisher}s notify of an - * error via {@link Subscriber#onError onError}, {@code mergeDelayError} will refrain from propagating that - * error notification until all of the merged {@code Publisher}s have finished emitting items. - *

- * - *

- * Even if multiple merged {@code Publisher}s send {@code onError} notifications, {@code mergeDelayError} will only - * invoke the {@code onError} method of its {@code Subscriber}s once. - *

- *
Backpressure:
- *
The operator honors backpressure from downstream. All inner {@code Publisher}s are expected to honor - * backpressure; if violated, the operator may signal {@link MissingBackpressureException}.
- *
Scheduler:
- *
{@code mergeDelayError} does not operate by default on a particular {@link Scheduler}.
- *
- * - * @param the common element base type - * @param sources - * the {@code Iterable} of {@code Publisher}s - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code sources} is {@code null} - * @see ReactiveX operators documentation: Merge - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - @CheckReturnValue - @BackpressureSupport(BackpressureKind.FULL) - @SchedulerSupport(SchedulerSupport.NONE) - @NonNull - public static <@NonNull T> Flowable mergeDelayError(@NonNull Iterable<@NonNull ? extends Publisher> sources) { - return fromIterable(sources).flatMap((Function)Functions.identity(), new StandardConcurrentBufferedConfig(true)); - } - - /** - * Flattens an {@link Iterable} of {@link Publisher}s into one {@code Publisher}, in a way that allows a {@link Subscriber} to receive all - * successfully emitted items from each of the source {@code Publisher}s without being interrupted by an error - * notification from one of them, while limiting the number of concurrent subscriptions to these {@code Publisher}s. - *

- * This behaves like {@link #merge(Publisher)} except that if any of the merged {@code Publisher}s notify of an - * error via {@link Subscriber#onError onError}, {@code mergeDelayError} will refrain from propagating that - * error notification until all of the merged {@code Publisher}s have finished emitting items. - *

- * - *

- * Even if multiple merged {@code Publisher}s send {@code onError} notifications, {@code mergeDelayError} will only - * invoke the {@code onError} method of its {@code Subscriber}s once. - *

- *
Backpressure:
- *
The operator honors backpressure from downstream. All inner {@code Publisher}s are expected to honor - * backpressure; if violated, the operator may signal {@link MissingBackpressureException}.
- *
Scheduler:
- *
{@code mergeDelayError} does not operate by default on a particular {@link Scheduler}.
- *
- * - * @param the common element base type - * @param sources - * the {@code Iterable} of {@code Publisher}s - * @param maxConcurrency - * the maximum number of {@code Publisher}s that may be subscribed to concurrently - * @param bufferSize - * the number of items to prefetch from each inner {@code Publisher} - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code sources} is {@code null} - * @throws IllegalArgumentException if {@code maxConcurrency} or {@code bufferSize} is non-positive - * @see ReactiveX operators documentation: Merge - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - @CheckReturnValue - @BackpressureSupport(BackpressureKind.FULL) - @SchedulerSupport(SchedulerSupport.NONE) - @NonNull - public static <@NonNull T> Flowable mergeDelayError(@NonNull Iterable<@NonNull ? extends Publisher> sources, int maxConcurrency, int bufferSize) { - return fromIterable(sources).flatMap((Function)Functions.identity(), new StandardConcurrentBufferedConfig(true, maxConcurrency, bufferSize)); - } - - /** - * Flattens an array of {@link Publisher}s into one {@code Publisher}, in a way that allows a {@link Subscriber} to receive all - * successfully emitted items from each of the source {@code Publisher}s without being interrupted by an error - * notification from one of them, while limiting the number of concurrent subscriptions to these {@code Publisher}s. - *

- * This behaves like {@link #merge(Publisher)} except that if any of the merged {@code Publisher}s notify of an - * error via {@link Subscriber#onError onError}, {@code mergeDelayError} will refrain from propagating that - * error notification until all of the merged {@code Publisher}s have finished emitting items. - *

- * - *

- * Even if multiple merged {@code Publisher}s send {@code onError} notifications, {@code mergeDelayError} will only - * invoke the {@code onError} method of its {@code Subscriber}s once. - *

- *
Backpressure:
- *
The operator honors backpressure from downstream. All source {@code Publisher}s are expected to honor - * backpressure; if violated, the operator may signal {@link MissingBackpressureException}.
- *
Scheduler:
- *
{@code mergeArrayDelayError} does not operate by default on a particular {@link Scheduler}.
- *
- * - * @param the common element base type - * @param sources - * the array of {@code Publisher}s - * @param maxConcurrency - * the maximum number of {@code Publisher}s that may be subscribed to concurrently - * @param bufferSize - * the number of items to prefetch from each inner {@code Publisher} - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code sources} is {@code null} - * @throws IllegalArgumentException if {@code maxConcurrency} or {@code bufferSize} is non-positive - * @see ReactiveX operators documentation: Merge - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - @CheckReturnValue - @BackpressureSupport(BackpressureKind.FULL) - @SchedulerSupport(SchedulerSupport.NONE) - @SafeVarargs - @NonNull - public static <@NonNull T> Flowable mergeArrayDelayError(int maxConcurrency, int bufferSize, @NonNull Publisher... sources) { - return fromArray(sources).flatMap((Function)Functions.identity(), new StandardConcurrentBufferedConfig(true, maxConcurrency, bufferSize)); - } - - /** - * Flattens an {@link Iterable} of {@link Publisher}s into one {@code Publisher}, in a way that allows a {@link Subscriber} to receive all - * successfully emitted items from each of the source {@code Publisher}s without being interrupted by an error - * notification from one of them, while limiting the number of concurrent subscriptions to these {@code Publisher}s. - *

- * This behaves like {@link #merge(Publisher)} except that if any of the merged {@code Publisher}s notify of an - * error via {@link Subscriber#onError onError}, {@code mergeDelayError} will refrain from propagating that - * error notification until all of the merged {@code Publisher}s have finished emitting items. - *

- * - *

- * Even if multiple merged {@code Publisher}s send {@code onError} notifications, {@code mergeDelayError} will only - * invoke the {@code onError} method of its {@code Subscriber}s once. - *

- *
Backpressure:
- *
The operator honors backpressure from downstream. All inner {@code Publisher}s are expected to honor - * backpressure; if violated, the operator may signal {@link MissingBackpressureException}.
- *
Scheduler:
- *
{@code mergeDelayError} does not operate by default on a particular {@link Scheduler}.
- *
- * - * @param the common element base type - * @param sources - * the {@code Iterable} of {@code Publisher}s - * @param maxConcurrency - * the maximum number of {@code Publisher}s that may be subscribed to concurrently - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code sources} is {@code null} - * @throws IllegalArgumentException if {@code maxConcurrency} is non-positive - * @see ReactiveX operators documentation: Merge - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - @CheckReturnValue - @BackpressureSupport(BackpressureKind.FULL) - @SchedulerSupport(SchedulerSupport.NONE) - @NonNull - public static <@NonNull T> Flowable mergeDelayError(@NonNull Iterable<@NonNull ? extends Publisher> sources, int maxConcurrency) { - return fromIterable(sources).flatMap((Function)Functions.identity(), new StandardConcurrentBufferedConfig(true, maxConcurrency)); - } - - /** - * Flattens a {@link Publisher} that emits {@code Publisher}s into one {@code Publisher}, in a way that allows a {@link Subscriber} to - * receive all successfully emitted items from all of the source {@code Publisher}s without being interrupted by - * an error notification from one of them. - *

- * This behaves like {@link #merge(Publisher)} except that if any of the merged {@code Publisher}s notify of an - * error via {@link Subscriber#onError onError}, {@code mergeDelayError} will refrain from propagating that - * error notification until all of the merged {@code Publisher}s have finished emitting items. - *

- * - *

- * Even if multiple merged {@code Publisher}s send {@code onError} notifications, {@code mergeDelayError} will only - * invoke the {@code onError} method of its {@code Subscriber}s once. - *

- *
Backpressure:
- *
The operator honors backpressure from downstream. The outer {@code Publisher} is consumed - * in unbounded mode (i.e., no backpressure is applied to it). The inner {@code Publisher}s are expected to honor - * backpressure; if violated, the operator may signal {@link MissingBackpressureException}.
- *
Scheduler:
- *
{@code mergeDelayError} does not operate by default on a particular {@link Scheduler}.
- *
- * - * @param the common element base type - * @param sources - * a {@code Publisher} that emits {@code Publisher}s - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code sources} is {@code null} - * @see ReactiveX operators documentation: Merge - */ - @CheckReturnValue - @BackpressureSupport(BackpressureKind.FULL) - @SchedulerSupport(SchedulerSupport.NONE) - @NonNull - public static <@NonNull T> Flowable mergeDelayError(@NonNull Publisher<@NonNull ? extends Publisher> sources) { - return mergeDelayError(sources, bufferSize()); - } - - /** - * Flattens a {@link Publisher} that emits {@code Publisher}s into one {@code Publisher}, in a way that allows a {@link Subscriber} to - * receive all successfully emitted items from all of the source {@code Publisher}s without being interrupted by - * an error notification from one of them, while limiting the - * number of concurrent subscriptions to these {@code Publisher}s. - *

- * This behaves like {@link #merge(Publisher)} except that if any of the merged {@code Publisher}s notify of an - * error via {@link Subscriber#onError onError}, {@code mergeDelayError} will refrain from propagating that - * error notification until all of the merged {@code Publisher}s have finished emitting items. - *

- * - *

- * Even if multiple merged {@code Publisher}s send {@code onError} notifications, {@code mergeDelayError} will only - * invoke the {@code onError} method of its {@code Subscriber}s once. - *

- *
Backpressure:
- *
The operator honors backpressure from downstream. Both the outer and inner {@code Publisher}s are expected to honor - * backpressure; if violated, the operator may signal {@link MissingBackpressureException}.
- *
Scheduler:
- *
{@code mergeDelayError} does not operate by default on a particular {@link Scheduler}.
- *
- * - * @param the common element base type - * @param sources - * a {@code Publisher} that emits {@code Publisher}s - * @param maxConcurrency - * the maximum number of {@code Publisher}s that may be subscribed to concurrently - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code sources} is {@code null} - * @throws IllegalArgumentException if {@code maxConcurrency} is non-positive - * @see ReactiveX operators documentation: Merge - * @since 2.0 - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - @CheckReturnValue - @BackpressureSupport(BackpressureKind.FULL) - @SchedulerSupport(SchedulerSupport.NONE) - @NonNull - public static <@NonNull T> Flowable mergeDelayError(@NonNull Publisher<@NonNull ? extends Publisher> sources, int maxConcurrency) { - return fromPublisher(sources).flatMap((Function)Functions.identity(), new StandardConcurrentBufferedConfig(true, maxConcurrency)); - } - - /** - * Flattens an array of {@link Publisher}s into one {@code Flowable}, in a way that allows a {@link Subscriber} to receive all - * successfully emitted items from each of the source {@code Publisher}s without being interrupted by an error - * notification from one of them. - *

- * This behaves like {@link #merge(Publisher)} except that if any of the merged {@code Publisher}s notify of an - * error via {@link Subscriber#onError onError}, {@code mergeDelayError} will refrain from propagating that - * error notification until all of the merged {@code Publisher}s have finished emitting items. - *

- * - *

- * Even if multiple merged {@code Publisher}s send {@code onError} notifications, {@code mergeDelayError} will only - * invoke the {@code onError} method of its {@code Subscriber}s once. - *

- *
Backpressure:
- *
The operator honors backpressure from downstream. Both the outer and inner {@code Publisher}s are expected to honor - * backpressure; if violated, the operator may signal {@link MissingBackpressureException}.
- *
Scheduler:
- *
{@code mergeArrayDelayError} does not operate by default on a particular {@link Scheduler}.
- *
- * - * @param the common element base type - * @param sources - * the array of {@code Publisher}s - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code sources} is {@code null} - * @see ReactiveX operators documentation: Merge - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - @CheckReturnValue - @BackpressureSupport(BackpressureKind.FULL) - @SchedulerSupport(SchedulerSupport.NONE) - @SafeVarargs - @NonNull - public static <@NonNull T> Flowable mergeArrayDelayError(@NonNull Publisher... sources) { - return fromArray(sources).flatMap((Function)Functions.identity(), new StandardConcurrentBufferedConfig(true, sources.length)); - } - - /** - * Flattens two {@link Publisher}s into one {@code Publisher}, in a way that allows a {@link Subscriber} to receive all - * successfully emitted items from each of the source {@code Publisher}s without being interrupted by an error - * notification from one of them. - *

- * This behaves like {@link #merge(Publisher, Publisher)} except that if any of the merged {@code Publisher}s - * notify of an error via {@link Subscriber#onError onError}, {@code mergeDelayError} will refrain from - * propagating that error notification until all of the merged {@code Publisher}s have finished emitting items. - *

- * - *

- * Even if both merged {@code Publisher}s send {@code onError} notifications, {@code mergeDelayError} will only - * invoke the {@code onError} method of its {@code Subscriber}s once. - *

- *
Backpressure:
- *
The operator honors backpressure from downstream. The source {@code Publisher}s are expected to honor - * backpressure; if violated, the operator may signal {@link MissingBackpressureException}.
- *
Scheduler:
- *
{@code mergeDelayError} does not operate by default on a particular {@link Scheduler}.
- *
- * - * @param the common element base type - * @param source1 - * a {@code Publisher} to be merged - * @param source2 - * a {@code Publisher} to be merged - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code source1} or {@code source2} is {@code null} - * @see ReactiveX operators documentation: Merge - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - @CheckReturnValue - @NonNull - @BackpressureSupport(BackpressureKind.FULL) - @SchedulerSupport(SchedulerSupport.NONE) - public static <@NonNull T> Flowable mergeDelayError(@NonNull Publisher source1, @NonNull Publisher source2) { - Objects.requireNonNull(source1, "source1 is null"); - Objects.requireNonNull(source2, "source2 is null"); - return fromArray(source1, source2).flatMap((Function)Functions.identity(), new StandardConcurrentBufferedConfig(true, 2)); - } - - /** - * Flattens three {@link Publisher}s into one {@code Publisher}, in a way that allows a {@link Subscriber} to receive all - * successfully emitted items from all of the source {@code Publisher}s without being interrupted by an error - * notification from one of them. - *

- * This behaves like {@link #merge(Publisher, Publisher, Publisher)} except that if any of the merged - * {@code Publisher}s notify of an error via {@link Subscriber#onError onError}, {@code mergeDelayError} will refrain - * from propagating that error notification until all of the merged {@code Publisher}s have finished emitting - * items. - *

- * - *

- * Even if multiple merged {@code Publisher}s send {@code onError} notifications, {@code mergeDelayError} will only - * invoke the {@code onError} method of its {@code Subscriber}s once. - *

- *
Backpressure:
- *
The operator honors backpressure from downstream. The source {@code Publisher}s are expected to honor - * backpressure; if violated, the operator may signal {@link MissingBackpressureException}.
- *
Scheduler:
- *
{@code mergeDelayError} does not operate by default on a particular {@link Scheduler}.
- *
- * - * @param the common element base type - * @param source1 - * a {@code Publisher} to be merged - * @param source2 - * a {@code Publisher} to be merged - * @param source3 - * a {@code Publisher} to be merged - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code source1}, {@code source2} or {@code source3} is {@code null} - * @see ReactiveX operators documentation: Merge - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - @CheckReturnValue - @NonNull - @BackpressureSupport(BackpressureKind.FULL) - @SchedulerSupport(SchedulerSupport.NONE) - public static <@NonNull T> Flowable mergeDelayError(@NonNull Publisher source1, - @NonNull Publisher source2, @NonNull Publisher source3) { - Objects.requireNonNull(source1, "source1 is null"); - Objects.requireNonNull(source2, "source2 is null"); - Objects.requireNonNull(source3, "source3 is null"); - return fromArray(source1, source2, source3).flatMap((Function)Functions.identity(), new StandardConcurrentBufferedConfig(true, 3)); - } - - /** - * Flattens four {@link Publisher}s into one {@code Publisher}, in a way that allows a {@link Subscriber} to receive all - * successfully emitted items from all of the source {@code Publisher}s without being interrupted by an error - * notification from one of them. - *

- * This behaves like {@link #merge(Publisher, Publisher, Publisher, Publisher)} except that if any of - * the merged {@code Publisher}s notify of an error via {@link Subscriber#onError onError}, {@code mergeDelayError} - * will refrain from propagating that error notification until all of the merged {@code Publisher}s have finished - * emitting items. - *

- * - *

- * Even if multiple merged {@code Publisher}s send {@code onError} notifications, {@code mergeDelayError} will only - * invoke the {@code onError} method of its {@code Subscriber}s once. - *

- *
Backpressure:
- *
The operator honors backpressure from downstream. The source {@code Publisher}s are expected to honor - * backpressure; if violated, the operator may signal {@link MissingBackpressureException}.
- *
Scheduler:
- *
{@code mergeDelayError} does not operate by default on a particular {@link Scheduler}.
- *
- * - * @param the common element base type - * @param source1 - * a {@code Publisher} to be merged - * @param source2 - * a {@code Publisher} to be merged - * @param source3 - * a {@code Publisher} to be merged - * @param source4 - * a {@code Publisher} to be merged - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code source1}, {@code source2}, {@code source3} or {@code source4} is {@code null} - * @see ReactiveX operators documentation: Merge - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - @CheckReturnValue - @NonNull - @BackpressureSupport(BackpressureKind.FULL) - @SchedulerSupport(SchedulerSupport.NONE) - public static <@NonNull T> Flowable mergeDelayError( - @NonNull Publisher source1, @NonNull Publisher source2, - @NonNull Publisher source3, @NonNull Publisher source4) { - Objects.requireNonNull(source1, "source1 is null"); - Objects.requireNonNull(source2, "source2 is null"); - Objects.requireNonNull(source3, "source3 is null"); - Objects.requireNonNull(source4, "source4 is null"); - return fromArray(source1, source2, source3, source4).flatMap((Function)Functions.identity(), new StandardConcurrentBufferedConfig(true, 4)); - } - - /** - * Returns a {@code Flowable} that never sends any items or notifications to a {@link Subscriber}. - *

- * - *

- * This {@link Publisher} is useful primarily for testing purposes. - *

- *
Backpressure:
- *
This source doesn't produce any elements and effectively ignores downstream backpressure.
- *
Scheduler:
- *
{@code never} does not operate by default on a particular {@link Scheduler}.
- *
- * - * @param - * the type of items (not) emitted by the {@code Publisher} - * @return the shared {@code Flowable} instance - * @see ReactiveX operators documentation: Never - */ - @CheckReturnValue - @BackpressureSupport(BackpressureKind.PASS_THROUGH) - @SchedulerSupport(SchedulerSupport.NONE) - @SuppressWarnings("unchecked") - @NonNull - public static <@NonNull T> Flowable never() { - return RxJavaPlugins.onAssembly((Flowable) FlowableNever.INSTANCE); - } - - /** - * Returns a {@code Flowable} that emits a sequence of {@link Integer}s within a specified range. - *

- * - *

- *
Backpressure:
- *
The operator honors backpressure from downstream and signals values on-demand (i.e., when requested).
+ *
The operator honors backpressure from downstream and signals values on-demand (i.e., when requested).
*
Scheduler:
*
{@code range} does not operate by default on a particular {@link Scheduler}.
*
@@ -4075,42 +3276,7 @@ public static Flowable rangeLong(long start, long count) { @SchedulerSupport(SchedulerSupport.NONE) @NonNull public static <@NonNull T> Single sequenceEqual(@NonNull Publisher source1, @NonNull Publisher source2) { - return sequenceEqual(source1, source2, ObjectHelper.equalsPredicate(), bufferSize()); - } - - /** - * Returns a {@link Single} that emits a {@link Boolean} value that indicates whether two {@link Publisher} sequences are the - * same by comparing the items emitted by each {@code Publisher} pairwise based on the results of a specified - * equality function. - *

- * - *

- *
Backpressure:
- *
The operator honors backpressure from downstream. The source {@code Publisher}s are expected to honor - * backpressure; if violated, the operator signals a {@link MissingBackpressureException}.
- *
Scheduler:
- *
{@code sequenceEqual} does not operate by default on a particular {@link Scheduler}.
- *
- * - * @param source1 - * the first {@code Publisher} to compare - * @param source2 - * the second {@code Publisher} to compare - * @param isEqual - * a function used to compare items emitted by each {@code Publisher} - * @param - * the type of items emitted by each {@code Publisher} - * @return the new {@code Single} instance - * @throws NullPointerException if {@code source1}, {@code source2} or {@code isEqual} is {@code null} - * @see ReactiveX operators documentation: SequenceEqual - */ - @CheckReturnValue - @BackpressureSupport(BackpressureKind.FULL) - @SchedulerSupport(SchedulerSupport.NONE) - @NonNull - public static <@NonNull T> Single sequenceEqual(@NonNull Publisher source1, @NonNull Publisher source2, - @NonNull BiPredicate isEqual) { - return sequenceEqual(source1, source2, isEqual, bufferSize()); + return sequenceEqual(source1, source2, SequenceEqualConfig.DEFAULT); } /** @@ -4131,62 +3297,25 @@ public static Flowable rangeLong(long start, long count) { * the first {@code Publisher} to compare * @param source2 * the second {@code Publisher} to compare - * @param isEqual - * a function used to compare items emitted by each {@code Publisher} - * @param bufferSize - * the number of items to prefetch from the first and second source {@code Publisher} + * @param config + * the configuration record for this operator * @param * the type of items emitted by each {@code Publisher} * @return the new {@code Single} instance - * @throws NullPointerException if {@code source1}, {@code source2} or {@code isEqual} is {@code null} - * @throws IllegalArgumentException if {@code bufferSize} is non-positive + * @throws NullPointerException if {@code source1}, {@code source2} or {@code config} is {@code null} * @see ReactiveX operators documentation: SequenceEqual + * @since 4.0.0 */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) public static <@NonNull T> Single sequenceEqual(@NonNull Publisher source1, @NonNull Publisher source2, - @NonNull BiPredicate isEqual, int bufferSize) { + @NonNull SequenceEqualConfig config) { Objects.requireNonNull(source1, "source1 is null"); Objects.requireNonNull(source2, "source2 is null"); - Objects.requireNonNull(isEqual, "isEqual is null"); - ObjectHelper.verifyPositive(bufferSize, "bufferSize"); - return RxJavaPlugins.onAssembly(new FlowableSequenceEqualSingle<>(source1, source2, isEqual, bufferSize)); - } - - /** - * Returns a {@link Single} that emits a {@link Boolean} value that indicates whether two {@link Publisher} sequences are the - * same by comparing the items emitted by each {@code Publisher} pairwise. - *

- * - *

- *
Backpressure:
- *
This operator honors downstream backpressure and expects both of its sources - * to honor backpressure as well. If violated, the operator will emit a {@link MissingBackpressureException}.
- *
Scheduler:
- *
{@code sequenceEqual} does not operate by default on a particular {@link Scheduler}.
- *
- * - * @param source1 - * the first {@code Publisher} to compare - * @param source2 - * the second {@code Publisher} to compare - * @param bufferSize - * the number of items to prefetch from the first and second source {@code Publisher} - * @param - * the type of items emitted by each {@code Publisher} - * @return the new {@code Single} instance - * @throws NullPointerException if {@code source1} or {@code source2} is {@code null} - * @throws IllegalArgumentException if {@code bufferSize} is non-positive - * @see ReactiveX operators documentation: SequenceEqual - */ - @CheckReturnValue - @BackpressureSupport(BackpressureKind.FULL) - @SchedulerSupport(SchedulerSupport.NONE) - @NonNull - public static <@NonNull T> Single sequenceEqual(@NonNull Publisher source1, @NonNull Publisher source2, int bufferSize) { - return sequenceEqual(source1, source2, ObjectHelper.equalsPredicate(), bufferSize); + Objects.requireNonNull(config, "config is null"); + return RxJavaPlugins.onAssembly(new FlowableSequenceEqualSingle<>(source1, source2, config.isEqual(), config.bufferSize())); } /** @@ -4215,20 +3344,20 @@ public static Flowable rangeLong(long start, long count) { * @param the item type * @param sources * the source {@code Publisher} that emits {@code Publisher}s - * @param bufferSize - * the number of items to prefetch from the inner {@code Publisher}s + * @param config + * the configuration record for this operator * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code sources} is {@code null} - * @throws IllegalArgumentException if {@code bufferSize} is non-positive + * @throws NullPointerException if {@code sources} or {@code config} is {@code null} * @see ReactiveX operators documentation: Switch + * @since 4.0.0 */ - @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public static <@NonNull T> Flowable switchOnNext(@NonNull Publisher> sources, int bufferSize) { - return fromPublisher(sources).switchMap((Function)Functions.identity(), bufferSize); + public static <@NonNull T> Flowable switchOnNext(@NonNull Publisher> sources, + @NonNull StandardBufferedConfig config) { + return fromPublisher(sources).switchMap(Functions.identity(), config); } /** @@ -4261,96 +3390,12 @@ public static Flowable rangeLong(long start, long count) { * @throws NullPointerException if {@code sources} is {@code null} * @see ReactiveX operators documentation: Switch */ - @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull public static <@NonNull T> Flowable switchOnNext(@NonNull Publisher<@NonNull ? extends Publisher> sources) { - return fromPublisher(sources).switchMap((Function)Functions.identity()); - } - - /** - * Converts a {@link Publisher} that emits {@code Publisher}s into a {@code Publisher} that emits the items emitted by the - * most recently emitted of those {@code Publisher}s and delays any exception until all {@code Publisher}s terminate. - *

- * - *

- * {@code switchOnNext} subscribes to a {@code Publisher} that emits {@code Publisher}s. Each time it observes one of - * these emitted {@code Publisher}s, the {@code Publisher} returned by {@code switchOnNext} begins emitting the items - * emitted by that {@code Publisher}. When a new {@code Publisher} is emitted, {@code switchOnNext} stops emitting items - * from the earlier-emitted {@code Publisher} and begins emitting items from the new one. - *

- * The resulting {@code Flowable} completes if both the main {@code Publisher} and the last inner {@code Publisher}, if any, complete. - * If the main {@code Publisher} signals an {@code onError}, the termination of the last inner {@code Publisher} will emit that error as is - * or wrapped into a {@link CompositeException} along with the other possible errors the former inner {@code Publisher}s signaled. - *

- *
Backpressure:
- *
The operator honors backpressure from downstream. The outer {@code Publisher} is consumed in an - * unbounded manner (i.e., without backpressure) and the inner {@code Publisher}s are expected to honor - * backpressure but it is not enforced; the operator won't signal a {@link MissingBackpressureException} - * but the violation may lead to {@link OutOfMemoryError} due to internal buffer bloat.
- *
Scheduler:
- *
{@code switchOnNextDelayError} does not operate by default on a particular {@link Scheduler}.
- *
- * - * @param the item type - * @param sources - * the source {@code Publisher} that emits {@code Publisher}s - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code sources} is {@code null} - * @see ReactiveX operators documentation: Switch - * @since 2.0 - */ - @CheckReturnValue - @BackpressureSupport(BackpressureKind.FULL) - @SchedulerSupport(SchedulerSupport.NONE) - @NonNull - public static <@NonNull T> Flowable switchOnNextDelayError(@NonNull Publisher<@NonNull ? extends Publisher> sources) { - return switchOnNextDelayError(sources, bufferSize()); - } - - /** - * Converts a {@link Publisher} that emits {@code Publisher}s into a {@code Publisher} that emits the items emitted by the - * most recently emitted of those {@code Publisher}s and delays any exception until all {@code Publisher}s terminate. - *

- * - *

- * {@code switchOnNext} subscribes to a {@code Publisher} that emits {@code Publisher}s. Each time it observes one of - * these emitted {@code Publisher}s, the {@code Publisher} returned by {@code switchOnNext} begins emitting the items - * emitted by that {@code Publisher}. When a new {@code Publisher} is emitted, {@code switchOnNext} stops emitting items - * from the earlier-emitted {@code Publisher} and begins emitting items from the new one. - *

- * The resulting {@code Flowable} completes if both the main {@code Publisher} and the last inner {@code Publisher}, if any, complete. - * If the main {@code Publisher} signals an {@code onError}, the termination of the last inner {@code Publisher} will emit that error as is - * or wrapped into a {@link CompositeException} along with the other possible errors the former inner {@code Publisher}s signaled. - *

- *
Backpressure:
- *
The operator honors backpressure from downstream. The outer {@code Publisher} is consumed in an - * unbounded manner (i.e., without backpressure) and the inner {@code Publisher}s are expected to honor - * backpressure but it is not enforced; the operator won't signal a {@link MissingBackpressureException} - * but the violation may lead to {@link OutOfMemoryError} due to internal buffer bloat.
- *
Scheduler:
- *
{@code switchOnNextDelayError} does not operate by default on a particular {@link Scheduler}.
- *
- * - * @param the item type - * @param sources - * the source {@code Publisher} that emits {@code Publisher}s - * @param prefetch - * the number of items to prefetch from the inner {@code Publisher}s - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code sources} is {@code null} - * @throws IllegalArgumentException if {@code prefetch} is non-positive - * @see ReactiveX operators documentation: Switch - * @since 2.0 - */ - @CheckReturnValue - @BackpressureSupport(BackpressureKind.FULL) - @SchedulerSupport(SchedulerSupport.NONE) - @NonNull - public static <@NonNull T> Flowable switchOnNextDelayError(@NonNull Publisher<@NonNull ? extends Publisher> sources, int prefetch) { - return fromPublisher(sources).switchMapDelayError(Functions.>identity(), prefetch); + return fromPublisher(sources).switchMap(Functions.identity()); } /** @@ -4539,63 +3584,7 @@ public static Flowable timer(long delay, @NonNull TimeUnit unit, @NonNull * the second item emitted by the new {@code Publisher} will be the result of the function applied to the second * item emitted by each of those {@code Publisher}s; and so forth. *

- * The resulting {@code Flowable} returned from {@code zip} will invoke {@code onNext} as many times as - * the number of {@code onNext} invocations of the source {@code Publisher} that emits the fewest items. - *

- * The operator subscribes to its sources in the order they are specified and completes eagerly if - * one of the sources is shorter than the rest while canceling the other sources. Therefore, it - * is possible those other sources will never be able to run to completion (and thus not calling - * {@code doOnComplete()}). This can also happen if the sources are exactly the same length; if - * source A completes and B has been consumed and is about to complete, the operator detects A won't - * be sending further values and it will cancel B immediately. For example: - *

zip(Arrays.asList(range(1, 5).doOnComplete(action1), range(6, 5).doOnComplete(action2)), (a) -> a)
- * {@code action1} will be called but {@code action2} won't. - *
To work around this termination property, - * use {@link #doOnCancel(Action)} as well or use {@code using()} to do cleanup in case of completion - * or cancellation. - *

- * - *

- *
Backpressure:
- *
The operator expects backpressure from the sources and honors backpressure from the downstream. - * (I.e., zipping with {@link #interval(long, TimeUnit)} may result in {@link MissingBackpressureException}, use - * one of the {@code onBackpressureX} to handle similar, backpressure-ignoring sources.
- *
Scheduler:
- *
{@code zip} does not operate by default on a particular {@link Scheduler}.
- *
- * - * @param the common value type - * @param the zipped result type - * @param sources - * an {@code Iterable} of source {@code Publisher}s - * @param zipper - * a function that, when applied to an item emitted by each of the source {@code Publisher}s, results in - * an item that will be emitted by the resulting {@code Flowable} - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code sources} or {@code zipper} is {@code null} - * @see ReactiveX operators documentation: Zip - */ - @CheckReturnValue - @NonNull - @BackpressureSupport(BackpressureKind.FULL) - @SchedulerSupport(SchedulerSupport.NONE) - public static <@NonNull T, @NonNull R> Flowable zip(@NonNull Iterable<@NonNull ? extends Publisher> sources, - @NonNull Function zipper) { - Objects.requireNonNull(zipper, "zipper is null"); - Objects.requireNonNull(sources, "sources is null"); - return RxJavaPlugins.onAssembly(new FlowableZip<>(null, sources, zipper, bufferSize(), false)); - } - - /** - * Returns a {@code Flowable} that emits the results of a specified combiner function applied to combinations of - * items emitted, in sequence, by an {@link Iterable} of other {@link Publisher}s. - *

- * {@code zip} applies this function in strict sequence, so the first item emitted by the new {@code Publisher} - * will be the result of the function applied to the first item emitted by each of the source {@code Publisher}s; - * the second item emitted by the new {@code Publisher} will be the result of the function applied to the second - * item emitted by each of those {@code Publisher}s; and so forth. - *

- * The resulting {@code Floawble} returned from {@code zip} will invoke {@code onNext} as many times as + * The resulting {@code Flowable} returned from {@code zip} will invoke {@code onNext} as many times as * the number of {@code onNext} invocations of the source {@code Publisher} that emits the fewest items. *

* The operator subscribes to its sources in the order they are specified and completes eagerly if @@ -4620,21 +3609,15 @@ public static Flowable timer(long delay, @NonNull TimeUnit unit, @NonNull *

{@code zip} does not operate by default on a particular {@link Scheduler}.
* * - * + * @param the common value type + * @param the zipped result type * @param sources * an {@code Iterable} of source {@code Publisher}s * @param zipper * a function that, when applied to an item emitted by each of the source {@code Publisher}s, results in * an item that will be emitted by the resulting {@code Flowable} - * @param delayError - * delay errors signaled by any of the source {@code Publisher} until all {@code Publisher}s terminate - * @param bufferSize - * the number of elements to prefetch from each source {@code Publisher} - * @param the common source value type - * @param the zipped result type * @return the new {@code Flowable} instance * @throws NullPointerException if {@code sources} or {@code zipper} is {@code null} - * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: Zip */ @CheckReturnValue @@ -4642,28 +3625,21 @@ public static Flowable timer(long delay, @NonNull TimeUnit unit, @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) public static <@NonNull T, @NonNull R> Flowable zip(@NonNull Iterable<@NonNull ? extends Publisher> sources, - @NonNull Function zipper, boolean delayError, - int bufferSize) { - Objects.requireNonNull(zipper, "zipper is null"); - Objects.requireNonNull(sources, "sources is null"); - ObjectHelper.verifyPositive(bufferSize, "bufferSize"); - return RxJavaPlugins.onAssembly(new FlowableZip<>(null, sources, zipper, bufferSize, delayError)); + @NonNull Function zipper) { + return zip(sources, zipper, StandardBufferedConfig.DEFAULT); } /** * Returns a {@code Flowable} that emits the results of a specified combiner function applied to combinations of - * two items emitted, in sequence, by two other {@link Publisher}s. - *

- * + * items emitted, in sequence, by an {@link Iterable} of other {@link Publisher}s. *

* {@code zip} applies this function in strict sequence, so the first item emitted by the new {@code Publisher} - * will be the result of the function applied to the first item emitted by {@code o1} and the first item - * emitted by {@code o2}; the second item emitted by the new {@code Publisher} will be the result of the function - * applied to the second item emitted by {@code o1} and the second item emitted by {@code o2}; and so forth. + * will be the result of the function applied to the first item emitted by each of the source {@code Publisher}s; + * the second item emitted by the new {@code Publisher} will be the result of the function applied to the second + * item emitted by each of those {@code Publisher}s; and so forth. *

- * The resulting {@code Flowable} returned from {@code zip} will invoke {@link Subscriber#onNext onNext} - * as many times as the number of {@code onNext} invocations of the source {@code Publisher} that emits the fewest - * items. + * The resulting {@code Floawble} returned from {@code zip} will invoke {@code onNext} as many times as + * the number of {@code onNext} invocations of the source {@code Publisher} that emits the fewest items. *

* The operator subscribes to its sources in the order they are specified and completes eagerly if * one of the sources is shorter than the rest while canceling the other sources. Therefore, it @@ -4671,11 +3647,13 @@ public static Flowable timer(long delay, @NonNull TimeUnit unit, @NonNull * {@code doOnComplete()}). This can also happen if the sources are exactly the same length; if * source A completes and B has been consumed and is about to complete, the operator detects A won't * be sending further values and it will cancel B immediately. For example: - *

zip(range(1, 5).doOnComplete(action1), range(6, 5).doOnComplete(action2), (a, b) -> a + b)
+ *
zip(Arrays.asList(range(1, 5).doOnComplete(action1), range(6, 5).doOnComplete(action2)), (a) -> a)
* {@code action1} will be called but {@code action2} won't. *
To work around this termination property, * use {@link #doOnCancel(Action)} as well or use {@code using()} to do cleanup in case of completion * or cancellation. + *

+ * *

*
Backpressure:
*
The operator expects backpressure from the sources and honors backpressure from the downstream. @@ -4685,31 +3663,31 @@ public static Flowable timer(long delay, @NonNull TimeUnit unit, @NonNull *
{@code zip} does not operate by default on a particular {@link Scheduler}.
*
* - * @param the value type of the first source - * @param the value type of the second source - * @param the zipped result type - * @param source1 - * the first source {@code Publisher} - * @param source2 - * a second source {@code Publisher} + * + * @param sources + * an {@code Iterable} of source {@code Publisher}s * @param zipper - * a function that, when applied to an item emitted by each of the source {@code Publisher}s, results - * in an item that will be emitted by the resulting {@code Flowable} + * a function that, when applied to an item emitted by each of the source {@code Publisher}s, results in + * an item that will be emitted by the resulting {@code Flowable} + * @param config + * the configuration record for this operator + * @param the common source value type + * @param the zipped result type * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code source1}, {@code source2} or {@code zipper} is {@code null} + * @throws NullPointerException if {@code sources} or {@code zipper} or {@code config} is {@code null} * @see ReactiveX operators documentation: Zip + * @since 4.0.0 */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - public static <@NonNull T1, @NonNull T2, @NonNull R> Flowable zip( - @NonNull Publisher source1, @NonNull Publisher source2, - @NonNull BiFunction zipper) { - Objects.requireNonNull(source1, "source1 is null"); - Objects.requireNonNull(source2, "source2 is null"); + public static <@NonNull T, @NonNull R> Flowable zip(@NonNull Iterable<@NonNull ? extends Publisher> sources, + @NonNull Function zipper, @NonNull StandardBufferedConfig config) { + Objects.requireNonNull(sources, "sources is null"); Objects.requireNonNull(zipper, "zipper is null"); - return zipArray(Functions.toFunction(zipper), false, bufferSize(), source1, source2); + Objects.requireNonNull(config, "config is null"); + return RxJavaPlugins.onAssembly(new FlowableZip<>(null, sources, zipper, config.bufferSize(), config.delayErrors())); } /** @@ -4757,7 +3735,6 @@ public static Flowable timer(long delay, @NonNull TimeUnit unit, @NonNull * @param zipper * a function that, when applied to an item emitted by each of the source {@code Publisher}s, results * in an item that will be emitted by the resulting {@code Flowable} - * @param delayError delay errors from any of the source {@code Publisher}s till the other terminates * @return the new {@code Flowable} instance * @throws NullPointerException if {@code source1}, {@code source2} or {@code zipper} is {@code null} * @see ReactiveX operators documentation: Zip @@ -4768,11 +3745,11 @@ public static Flowable timer(long delay, @NonNull TimeUnit unit, @NonNull @SchedulerSupport(SchedulerSupport.NONE) public static <@NonNull T1, @NonNull T2, @NonNull R> Flowable zip( @NonNull Publisher source1, @NonNull Publisher source2, - @NonNull BiFunction zipper, boolean delayError) { + @NonNull BiFunction zipper) { Objects.requireNonNull(source1, "source1 is null"); Objects.requireNonNull(source2, "source2 is null"); Objects.requireNonNull(zipper, "zipper is null"); - return zipArray(Functions.toFunction(zipper), delayError, bufferSize(), source1, source2); + return zip(source1, source2, zipper, StandardBufferedConfig.DEFAULT); } /** @@ -4820,12 +3797,12 @@ public static Flowable timer(long delay, @NonNull TimeUnit unit, @NonNull * @param zipper * a function that, when applied to an item emitted by each of the source {@code Publisher}s, results * in an item that will be emitted by the resulting {@code Flowable} - * @param delayError delay errors from any of the source {@code Publisher}s till the other terminates - * @param bufferSize the number of elements to prefetch from each source {@code Publisher} + * @param config + * the configuration record for this operator * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code source1}, {@code source2} or {@code zipper} is {@code null} - * @throws IllegalArgumentException if {@code bufferSize} is non-positive + * @throws NullPointerException if {@code source1}, {@code source2} or {@code zipper} or {@code config} is {@code null} * @see ReactiveX operators documentation: Zip + * @since 4.0.0 */ @CheckReturnValue @NonNull @@ -4833,11 +3810,14 @@ public static Flowable timer(long delay, @NonNull TimeUnit unit, @NonNull @SchedulerSupport(SchedulerSupport.NONE) public static <@NonNull T1, @NonNull T2, @NonNull R> Flowable zip( @NonNull Publisher source1, @NonNull Publisher source2, - @NonNull BiFunction zipper, boolean delayError, int bufferSize) { + @NonNull BiFunction zipper, + @NonNull StandardBufferedConfig config + ) { Objects.requireNonNull(source1, "source1 is null"); Objects.requireNonNull(source2, "source2 is null"); Objects.requireNonNull(zipper, "zipper is null"); - return zipArray(Functions.toFunction(zipper), delayError, bufferSize, source1, source2); + Objects.requireNonNull(config, "config is null"); + return zipArray(new Publisher<@NonNull ?>[] { source1, source2 }, Functions.toFunction(zipper), config); } /** @@ -4898,13 +3878,15 @@ public static Flowable timer(long delay, @NonNull TimeUnit unit, @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) public static <@NonNull T1, @NonNull T2, @NonNull T3, @NonNull R> Flowable zip( - @NonNull Publisher source1, @NonNull Publisher source2, @NonNull Publisher source3, + @NonNull Publisher source1, @NonNull Publisher source2, + @NonNull Publisher source3, @NonNull Function3 zipper) { Objects.requireNonNull(source1, "source1 is null"); Objects.requireNonNull(source2, "source2 is null"); Objects.requireNonNull(source3, "source3 is null"); Objects.requireNonNull(zipper, "zipper is null"); - return zipArray(Functions.toFunction(zipper), false, bufferSize(), source1, source2, source3); + return zipArray(new Publisher<@NonNull ?>[] { source1, source2, source3 }, + Functions.toFunction(zipper), StandardBufferedConfig.DEFAULT); } /** @@ -4977,7 +3959,8 @@ public static Flowable timer(long delay, @NonNull TimeUnit unit, @NonNull Objects.requireNonNull(source3, "source3 is null"); Objects.requireNonNull(source4, "source4 is null"); Objects.requireNonNull(zipper, "zipper is null"); - return zipArray(Functions.toFunction(zipper), false, bufferSize(), source1, source2, source3, source4); + return zipArray(new Publisher<@NonNull ?>[] { source1, source2, source3, source4 }, + Functions.toFunction(zipper), StandardBufferedConfig.DEFAULT); } /** @@ -5054,7 +4037,8 @@ public static Flowable timer(long delay, @NonNull TimeUnit unit, @NonNull Objects.requireNonNull(source4, "source4 is null"); Objects.requireNonNull(source5, "source5 is null"); Objects.requireNonNull(zipper, "zipper is null"); - return zipArray(Functions.toFunction(zipper), false, bufferSize(), source1, source2, source3, source4, source5); + return zipArray(new Publisher<@NonNull ?>[] { source1, source2, source3, source4, source5 }, + Functions.toFunction(zipper), StandardBufferedConfig.DEFAULT); } /** @@ -5135,7 +4119,9 @@ public static Flowable timer(long delay, @NonNull TimeUnit unit, @NonNull Objects.requireNonNull(source5, "source5 is null"); Objects.requireNonNull(source6, "source6 is null"); Objects.requireNonNull(zipper, "zipper is null"); - return zipArray(Functions.toFunction(zipper), false, bufferSize(), source1, source2, source3, source4, source5, source6); + return zipArray( + new Publisher<@NonNull ?>[] { source1, source2, source3, source4, source5, source6 }, + Functions.toFunction(zipper), StandardBufferedConfig.DEFAULT); } /** @@ -5221,7 +4207,9 @@ public static Flowable timer(long delay, @NonNull TimeUnit unit, @NonNull Objects.requireNonNull(source6, "source6 is null"); Objects.requireNonNull(source7, "source7 is null"); Objects.requireNonNull(zipper, "zipper is null"); - return zipArray(Functions.toFunction(zipper), false, bufferSize(), source1, source2, source3, source4, source5, source6, source7); + return zipArray( + new Publisher<@NonNull ?>[] { source1, source2, source3, source4, source5, source6, source7 }, + Functions.toFunction(zipper), StandardBufferedConfig.DEFAULT); } /** @@ -5311,7 +4299,9 @@ public static Flowable timer(long delay, @NonNull TimeUnit unit, @NonNull Objects.requireNonNull(source7, "source7 is null"); Objects.requireNonNull(source8, "source8 is null"); Objects.requireNonNull(zipper, "zipper is null"); - return zipArray(Functions.toFunction(zipper), false, bufferSize(), source1, source2, source3, source4, source5, source6, source7, source8); + return zipArray( + new Publisher<@NonNull ?>[] { source1, source2, source3, source4, source5, source6, source7, source8 }, + Functions.toFunction(zipper), StandardBufferedConfig.DEFAULT); } /** @@ -5407,7 +4397,9 @@ public static Flowable timer(long delay, @NonNull TimeUnit unit, @NonNull Objects.requireNonNull(source8, "source8 is null"); Objects.requireNonNull(source9, "source9 is null"); Objects.requireNonNull(zipper, "zipper is null"); - return zipArray(Functions.toFunction(zipper), false, bufferSize(), source1, source2, source3, source4, source5, source6, source7, source8, source9); + return zipArray( + new Publisher<@NonNull ?>[] { source1, source2, source3, source4, source5, source6, source7, source8, source9 }, + Functions.toFunction(zipper), StandardBufferedConfig.DEFAULT); } /** @@ -5452,29 +4444,28 @@ public static Flowable timer(long delay, @NonNull TimeUnit unit, @NonNull * @param zipper * a function that, when applied to an item emitted by each of the source {@code Publisher}s, results in * an item that will be emitted by the resulting {@code Flowable} - * @param delayError - * delay errors signaled by any of the source {@code Publisher} until all {@code Publisher}s terminate - * @param bufferSize - * the number of elements to prefetch from each source {@code Publisher} + * @param config + * the configuration record of this operator * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code sources} or {@code zipper} is {@code null} - * @throws IllegalArgumentException if {@code bufferSize} is non-positive + * @throws NullPointerException if {@code sources} or {@code zipper} or {@code config} is {@code null} * @see ReactiveX operators documentation: Zip + * @since 4.0.0 */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) - @SafeVarargs - public static <@NonNull T, @NonNull R> Flowable zipArray(@NonNull Function zipper, - boolean delayError, int bufferSize, @NonNull Publisher... sources) { + public static <@NonNull T, @NonNull R> Flowable zipArray( + @NonNull Publisher[] sources, + @NonNull Function zipper, + @NonNull StandardBufferedConfig config) { Objects.requireNonNull(sources, "sources is null"); + Objects.requireNonNull(config, "config is null"); if (sources.length == 0) { return empty(); } Objects.requireNonNull(zipper, "zipper is null"); - ObjectHelper.verifyPositive(bufferSize, "bufferSize"); - return RxJavaPlugins.onAssembly(new FlowableZip<>(sources, null, zipper, bufferSize, delayError)); + return RxJavaPlugins.onAssembly(new FlowableZip<>(sources, null, zipper, config.bufferSize(), config.delayErrors())); } // *************************************************************************************************** @@ -7337,7 +6328,6 @@ public final Flowable cacheWithInitialCapacity(int initialCapacity) { * be subscribed to * @return the new {@link Completable} instance * @throws NullPointerException if {@code mapper} is {@code null} - * @see #concatMapCompletableDelayError(Function) * @since 2.2 */ @CheckReturnValue @@ -7345,7 +6335,7 @@ public final Flowable cacheWithInitialCapacity(int initialCapacity) { @BackpressureSupport(BackpressureKind.FULL) @NonNull public final Completable concatMapCompletable(@NonNull Function mapper) { - return concatMapCompletable(mapper, 2); + return concatMapCompletable(mapper, StandardBufferedConfig.MIN_DEFAULT); } /** @@ -7364,133 +6354,20 @@ public final Completable concatMapCompletable(@NonNull Function mapper, int prefetch) { - Objects.requireNonNull(mapper, "mapper is null"); - ObjectHelper.verifyPositive(prefetch, "prefetch"); - return RxJavaPlugins.onAssembly(new FlowableConcatMapCompletable<>(this, mapper, ErrorMode.IMMEDIATE, prefetch)); - } - - /** - * Maps the upstream items into {@link CompletableSource}s and subscribes to them one after the - * other terminates, delaying all errors till both this {@code Flowable} and all - * inner {@code CompletableSource}s terminate. - *

- * - *

- *
Backpressure:
- *
The operator expects the upstream to support backpressure. If this {@code Flowable} violates the rule, the operator will - * signal a {@link MissingBackpressureException}.
- *
Scheduler:
- *
{@code concatMapCompletableDelayError} does not operate by default on a particular {@link Scheduler}.
- *
- *

History: 2.1.11 - experimental - * @param mapper the function called with the upstream item and should return - * a {@code CompletableSource} to become the next source to - * be subscribed to - * @return the new {@link Completable} instance - * @throws NullPointerException if {@code mapper} is {@code null} - * @see #concatMapCompletable(Function, int) - * @since 2.2 - */ - @CheckReturnValue - @SchedulerSupport(SchedulerSupport.NONE) - @BackpressureSupport(BackpressureKind.FULL) - @NonNull - public final Completable concatMapCompletableDelayError(@NonNull Function mapper) { - return concatMapCompletableDelayError(mapper, true, 2); - } - - /** - * Maps the upstream items into {@link CompletableSource}s and subscribes to them one after the - * other terminates, optionally delaying all errors till both this {@code Flowable} and all - * inner {@code CompletableSource}s terminate. - *

- * - *

- *
Backpressure:
- *
The operator expects the upstream to support backpressure. If this {@code Flowable} violates the rule, the operator will - * signal a {@link MissingBackpressureException}.
- *
Scheduler:
- *
{@code concatMapCompletableDelayError} does not operate by default on a particular {@link Scheduler}.
- *
- *

History: 2.1.11 - experimental - * @param mapper the function called with the upstream item and should return - * a {@code CompletableSource} to become the next source to - * be subscribed to - * @param tillTheEnd If {@code true}, errors from this {@code Flowable} or any of the - * inner {@code CompletableSource}s are delayed until all - * of them terminate. If {@code false}, an error from this - * {@code Flowable} is delayed until the current inner - * {@code CompletableSource} terminates and only then is - * it emitted to the downstream. - * @return the new {@link Completable} instance - * @throws NullPointerException if {@code mapper} is {@code null} - * @see #concatMapCompletable(Function) - * @since 2.2 - */ - @CheckReturnValue - @SchedulerSupport(SchedulerSupport.NONE) - @BackpressureSupport(BackpressureKind.FULL) - @NonNull - public final Completable concatMapCompletableDelayError(@NonNull Function mapper, boolean tillTheEnd) { - return concatMapCompletableDelayError(mapper, tillTheEnd, 2); - } - - /** - * Maps the upstream items into {@link CompletableSource}s and subscribes to them one after the - * other terminates, optionally delaying all errors till both this {@code Flowable} and all - * inner {@code CompletableSource}s terminate. - *

- * - *

- *
Backpressure:
- *
The operator expects the upstream to support backpressure. If this {@code Flowable} violates the rule, the operator will - * signal a {@link MissingBackpressureException}.
- *
Scheduler:
- *
{@code concatMapCompletableDelayError} does not operate by default on a particular {@link Scheduler}.
- *
- *

History: 2.1.11 - experimental - * @param mapper the function called with the upstream item and should return - * a {@code CompletableSource} to become the next source to - * be subscribed to - * @param tillTheEnd If {@code true}, errors from this {@code Flowable} or any of the - * inner {@code CompletableSource}s are delayed until all - * of them terminate. If {@code false}, an error from this - * {@code Flowable} is delayed until the current inner - * {@code CompletableSource} terminates and only then is - * it emitted to the downstream. - * @param prefetch The number of upstream items to prefetch so that fresh items are - * ready to be mapped when a previous {@code CompletableSource} terminates. - * The operator replenishes after half of the prefetch amount has been consumed - * and turned into {@code CompletableSource}s. + * @param config the configuration record for this operator * @return the new {@link Completable} instance - * @throws NullPointerException if {@code mapper} is {@code null} - * @throws IllegalArgumentException if {@code prefetch} is non-positive - * @see #concatMapCompletable(Function, int) - * @since 2.2 + * @throws NullPointerException if {@code mapper} or {@code config} is {@code null} + * @since 4.0.0 */ @CheckReturnValue @NonNull @SchedulerSupport(SchedulerSupport.NONE) @BackpressureSupport(BackpressureKind.FULL) - public final Completable concatMapCompletableDelayError(@NonNull Function mapper, boolean tillTheEnd, int prefetch) { + public final Completable concatMapCompletable(@NonNull Function mapper, + @NonNull StandardBufferedConfig config) { Objects.requireNonNull(mapper, "mapper is null"); - ObjectHelper.verifyPositive(prefetch, "prefetch"); - return RxJavaPlugins.onAssembly(new FlowableConcatMapCompletable<>(this, mapper, tillTheEnd ? ErrorMode.END : ErrorMode.BOUNDARY, prefetch)); + Objects.requireNonNull(config, "config is null"); + return RxJavaPlugins.onAssembly(new FlowableConcatMapCompletable<>(this, mapper, config.errorMode(), config.bufferSize())); } /** @@ -8094,7 +6971,6 @@ public final Flowable debounce(long timeout, @NonNull TimeUnit unit, @NonNull @NonNull @BackpressureSupport(BackpressureKind.ERROR) @SchedulerSupport(SchedulerSupport.CUSTOM) - @Experimental public final Flowable debounce(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, @NonNull Consumer onDropped) { Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); @@ -8196,37 +7072,6 @@ public final Flowable delay(long time, @NonNull TimeUnit unit) { return delay(time, unit, Schedulers.computation(), false); } - /** - * Returns a {@code Flowable} that emits the items emitted by the current {@code Flowable} shifted forward in time by a - * specified delay. If {@code delayError} is {@code true}, error notifications will also be delayed. - *

- * - *

- *
Backpressure:
- *
The operator doesn't interfere with the backpressure behavior which is determined by the current {@code Flowable}.
- *
Scheduler:
- *
This version of {@code delay} operates by default on the {@code computation} {@link Scheduler}.
- *
- * - * @param time - * the delay to shift the source by - * @param unit - * the {@link TimeUnit} in which {@code period} is defined - * @param delayError - * if {@code true}, the upstream exception is signaled with the given delay, after all preceding normal elements, - * if {@code false}, the upstream exception is signaled immediately - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code unit} is {@code null} - * @see ReactiveX operators documentation: Delay - */ - @CheckReturnValue - @BackpressureSupport(BackpressureKind.FULL) - @SchedulerSupport(SchedulerSupport.COMPUTATION) - @NonNull - public final Flowable delay(long time, @NonNull TimeUnit unit, boolean delayError) { - return delay(time, unit, Schedulers.computation(), delayError); - } - /** * Returns a {@code Flowable} that emits the items emitted by the current {@code Flowable} shifted forward in time by a * specified delay. The {@code onError} notification from the current {@code Flowable} is not delayed. @@ -9529,7 +8374,7 @@ public final Single firstOrError() { Objects.requireNonNull(onErrorMapper, "onErrorMapper is null"); Objects.requireNonNull(onCompleteSupplier, "onCompleteSupplier is null"); return merge(new FlowableMapNotification<>( - this, onNextMapper, onErrorMapper, onCompleteSupplier), config.maxConcurrency()); + this, onNextMapper, onErrorMapper, onCompleteSupplier), config); } /** @@ -9858,6 +8703,7 @@ public final Completable flatMapCompletable(@NonNull Function onNext, @NonN ForEachWhileSubscriber s = new ForEachWhileSubscriber<>(onNext, onError, onComplete); subscribe(s); - return s; - } - - /** - * Groups the items emitted by the current {@code Flowable} according to a specified criterion, and emits these - * grouped items as {@link GroupedFlowable}s. The emitted {@code GroupedFlowable} allows only a single - * {@link Subscriber} during its lifetime and if this {@code Subscriber} cancels before the - * source terminates, the next emission by the source having the same key will trigger a new - * {@code GroupedFlowable} emission. - *

- * - *

- * Note: A {@code GroupedFlowable} will cache the items it is to emit until such time as it - * is subscribed to. For this reason, in order to avoid memory leaks, you should not simply ignore those - * {@code GroupedFlowable}s that do not concern you. Instead, you can signal to them that they may - * discard their buffers by applying an operator like {@link #ignoreElements} to them. - *

- * Note that the {@code GroupedFlowable}s should be subscribed to as soon as possible, otherwise, - * the unconsumed groups may starve other groups due to the internal backpressure - * coordination of the {@code groupBy} operator. Such hangs can be usually avoided by using - * {@link #flatMap(Function, StandardConcurrentBufferedConfig)} or {@link #concatMapEager(Function, StandardConcurrentBufferedConfig)} - * and overriding the default maximum concurrency - * value to be greater or equal to the expected number of groups, possibly using - * {@link Integer#MAX_VALUE} if the number of expected groups is unknown. - *

- * Note also that ignoring groups or subscribing later (i.e., on another thread) will result in - * so-called group abandonment where a group will only contain one element and the group will be - * re-created over and over as new upstream items trigger a new group. The behavior is - * a trade-off between no-dataloss, upstream cancellation and excessive group creation. - * - *

- *
Backpressure:
- *
The consumer of the returned {@code Flowable} has to be ready to receive new {@code GroupedFlowable}s or else - * this operator will signal {@link MissingBackpressureException}. To avoid this exception, make - * sure a combining operator (such as {@code flatMap}) has adequate amount of buffering/prefetch configured. - * The inner {@code GroupedFlowable}s honor backpressure but due to the single-source multiple consumer - * nature of this operator, each group must be consumed so the whole operator can make progress and not hang.
- *
Scheduler:
- *
{@code groupBy} does not operate by default on a particular {@link Scheduler}.
- *
Error handling:
- *
If the upstream signals or the callback(s) throw an exception, the returned {@code Flowable} and - * all active inner {@code GroupedFlowable}s will signal the same exception.
- *
- * - * @param keySelector - * a function that extracts the key for each item - * @param - * the key type - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code keySelector} is {@code null} - * @see ReactiveX operators documentation: GroupBy - * @see #groupBy(Function, boolean) - * @see #groupBy(Function, Function) - */ - @CheckReturnValue - @BackpressureSupport(BackpressureKind.ERROR) - @SchedulerSupport(SchedulerSupport.NONE) - @NonNull - public final <@NonNull K> Flowable> groupBy(@NonNull Function keySelector) { - return groupBy(keySelector, Functions.identity(), false, bufferSize()); + return s; } /** @@ -10124,7 +8912,7 @@ public final Disposable forEachWhile(@NonNull Predicate onNext, @NonN * the unconsumed groups may starve other groups due to the internal backpressure * coordination of the {@code groupBy} operator. Such hangs can be usually avoided by using * {@link #flatMap(Function, StandardConcurrentBufferedConfig)} or {@link #concatMapEager(Function, StandardConcurrentBufferedConfig)} - * and overriding the default maximum concurrency + * and overriding the default maximum concurrency * value to be greater or equal to the expected number of groups, possibly using * {@link Integer#MAX_VALUE} if the number of expected groups is unknown. *

@@ -10151,19 +8939,18 @@ public final Disposable forEachWhile(@NonNull Predicate onNext, @NonN * a function that extracts the key for each item * @param * the key type - * @param delayError - * if {@code true}, the exception from the current {@code Flowable} is delayed in each group until that specific group emitted - * the normal values; if {@code false}, the exception bypasses values in the groups and is reported immediately. * @return the new {@code Flowable} instance * @throws NullPointerException if {@code keySelector} is {@code null} * @see ReactiveX operators documentation: GroupBy + * @see #groupBy(Function, StandardBufferedConfig) + * @see #groupBy(Function, Function) */ @CheckReturnValue @BackpressureSupport(BackpressureKind.ERROR) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final <@NonNull K> Flowable> groupBy(@NonNull Function keySelector, boolean delayError) { - return groupBy(keySelector, Functions.identity(), delayError, bufferSize()); + public final <@NonNull K> Flowable> groupBy(@NonNull Function keySelector) { + return groupBy(keySelector, Functions.identity(), StandardBufferedConfig.DEFAULT); } /** @@ -10209,26 +8996,22 @@ public final Disposable forEachWhile(@NonNull Predicate onNext, @NonN * * @param keySelector * a function that extracts the key for each item - * @param valueSelector - * a function that extracts the return element for each item * @param * the key type - * @param - * the element type + * @param config + * the configuration record of this operator * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code keySelector} or {@code valueSelector} is {@code null} + * @throws NullPointerException if {@code keySelector} is {@code null} * @see ReactiveX operators documentation: GroupBy - * @see #groupBy(Function, Function, boolean) - * @see #groupBy(Function, Function, boolean, int) - * @see #groupBy(Function, Function, boolean, int, Function) + * @since 4.0.0 */ @CheckReturnValue @BackpressureSupport(BackpressureKind.ERROR) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final <@NonNull K, @NonNull V> Flowable> groupBy(@NonNull Function keySelector, - @NonNull Function valueSelector) { - return groupBy(keySelector, valueSelector, false, bufferSize()); + public final <@NonNull K> Flowable> groupBy(@NonNull Function keySelector, + @NonNull StandardBufferedConfig config) { + return groupBy(keySelector, Functions.identity(), config); } /** @@ -10280,21 +9063,18 @@ public final Disposable forEachWhile(@NonNull Predicate onNext, @NonN * the key type * @param * the element type - * @param delayError - * if {@code true}, the exception from the current {@code Flowable} is delayed in each group until that specific group emitted - * the normal values; if {@code false}, the exception bypasses values in the groups and is reported immediately. * @return the new {@code Flowable} instance * @throws NullPointerException if {@code keySelector} or {@code valueSelector} is {@code null} * @see ReactiveX operators documentation: GroupBy - * @see #groupBy(Function, Function, boolean, int) + * @see #groupBy(Function, Function, StandardBufferedConfig) */ @CheckReturnValue @BackpressureSupport(BackpressureKind.ERROR) @SchedulerSupport(SchedulerSupport.NONE) @NonNull public final <@NonNull K, @NonNull V> Flowable> groupBy(@NonNull Function keySelector, - @NonNull Function valueSelector, boolean delayError) { - return groupBy(keySelector, valueSelector, delayError, bufferSize()); + @NonNull Function valueSelector) { + return groupBy(keySelector, valueSelector, StandardBufferedConfig.DEFAULT); } /** @@ -10342,19 +9122,16 @@ public final Disposable forEachWhile(@NonNull Predicate onNext, @NonN * a function that extracts the key for each item * @param valueSelector * a function that extracts the return element for each item - * @param delayError - * if {@code true}, the exception from the current {@code Flowable} is delayed in each group until that specific group emitted - * the normal values; if {@code false}, the exception bypasses values in the groups and is reported immediately. - * @param bufferSize - * the hint for how many {@code GroupedFlowable}s and element in each {@code GroupedFlowable} should be buffered + * @param config + * the configuration record for this operator * @param * the key type * @param * the element type * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code keySelector} or {@code valueSelector} is {@code null} - * @throws IllegalArgumentException if {@code bufferSize} is non-positive + * @throws NullPointerException if {@code keySelector} or {@code valueSelector} or {@code config} is {@code null} * @see ReactiveX operators documentation: GroupBy + * @since 4.0.0 */ @CheckReturnValue @NonNull @@ -10362,12 +9139,12 @@ public final Disposable forEachWhile(@NonNull Predicate onNext, @NonN @SchedulerSupport(SchedulerSupport.NONE) public final <@NonNull K, @NonNull V> Flowable> groupBy(@NonNull Function keySelector, @NonNull Function valueSelector, - boolean delayError, int bufferSize) { + @NonNull StandardBufferedConfig config) { Objects.requireNonNull(keySelector, "keySelector is null"); Objects.requireNonNull(valueSelector, "valueSelector is null"); - ObjectHelper.verifyPositive(bufferSize, "bufferSize"); + Objects.requireNonNull(config, "config is null"); - return RxJavaPlugins.onAssembly(new FlowableGroupBy<>(this, keySelector, valueSelector, bufferSize, delayError, null)); + return RxJavaPlugins.onAssembly(new FlowableGroupBy<>(this, keySelector, valueSelector, config.bufferSize(), config.delayErrors(), null)); } /** @@ -10458,27 +9235,23 @@ public final Disposable forEachWhile(@NonNull Predicate onNext, @NonN * a function that extracts the key for each item * @param valueSelector * a function that extracts the return element for each item - * @param delayError - * if {@code true}, the exception from the current {@code Flowable} is delayed in each group until that specific group emitted - * the normal values; if {@code false}, the exception bypasses values in the groups and is reported immediately. - * @param bufferSize - * the hint for how many {@code GroupedFlowable}s and element in each {@code GroupedFlowable} should be buffered * @param evictingMapFactory * The factory used to create a map that will be used by the implementation to hold the * {@code GroupedFlowable}s. The evicting map created by this factory must * notify the provided {@code Consumer} with the entry value (not the key!) when * an entry in this map has been evicted. The next source emission will bring about the * completion of the evicted {@code GroupedFlowable}s. See example above. + * @param config + * the configuration record for this operator * @param * the key type * @param * the element type * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code keySelector}, {@code valueSelector} or {@code evictingMapFactory} is {@code null} - * @throws IllegalArgumentException if {@code bufferSize} is non-positive + * @throws NullPointerException if {@code keySelector}, {@code valueSelector} or {@code evictingMapFactory} or {@code config} is {@code null} * @see ReactiveX operators documentation: GroupBy * - * @since 2.2 + * @since 4.0.0 */ @CheckReturnValue @NonNull @@ -10486,14 +9259,15 @@ public final Disposable forEachWhile(@NonNull Predicate onNext, @NonN @SchedulerSupport(SchedulerSupport.NONE) public final <@NonNull K, @NonNull V> Flowable> groupBy(@NonNull Function keySelector, @NonNull Function valueSelector, - boolean delayError, int bufferSize, - @NonNull Function, ? extends Map> evictingMapFactory) { + @NonNull Function, ? extends Map> evictingMapFactory, + @NonNull StandardBufferedConfig config + ) { Objects.requireNonNull(keySelector, "keySelector is null"); Objects.requireNonNull(valueSelector, "valueSelector is null"); - ObjectHelper.verifyPositive(bufferSize, "bufferSize"); Objects.requireNonNull(evictingMapFactory, "evictingMapFactory is null"); + Objects.requireNonNull(config, "config is null"); - return RxJavaPlugins.onAssembly(new FlowableGroupBy<>(this, keySelector, valueSelector, bufferSize, delayError, evictingMapFactory)); + return RxJavaPlugins.onAssembly(new FlowableGroupBy<>(this, keySelector, valueSelector, config.bufferSize(), config.delayErrors(), evictingMapFactory)); } /** @@ -10985,7 +9759,7 @@ public final Flowable> materialize() { @SchedulerSupport(SchedulerSupport.NONE) public final Flowable mergeWith(@NonNull Publisher other) { Objects.requireNonNull(other, "other is null"); - return merge(this, other); + return mergeArray(this, other); } /** @@ -11079,7 +9853,7 @@ public final Flowable mergeWith(@NonNull CompletableSource other) { * asynchronously with a bounded buffer of {@link #bufferSize()} slots. * *

Note that {@code onError} notifications will cut ahead of {@code onNext} notifications on the emission thread if {@code Scheduler} is truly - * asynchronous. If strict event ordering is required, consider using the {@link #observeOn(Scheduler, boolean)} overload. + * asynchronous. If strict event ordering is required, consider using the {@link #observeOn(Scheduler, StandardBufferedConfig)} overload. *

* *

@@ -11113,8 +9887,7 @@ public final Flowable mergeWith(@NonNull CompletableSource other) { * @see ReactiveX operators documentation: ObserveOn * @see RxJava Threading Examples * @see #subscribeOn - * @see #observeOn(Scheduler, boolean) - * @see #observeOn(Scheduler, boolean, int) + * @see #observeOn(Scheduler, StandardBufferedConfig) * @see #delay(long, TimeUnit, Scheduler) */ @CheckReturnValue @@ -11122,59 +9895,7 @@ public final Flowable mergeWith(@NonNull CompletableSource other) { @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull public final Flowable observeOn(@NonNull Scheduler scheduler) { - return observeOn(scheduler, false, bufferSize()); - } - - /** - * Signals the items and terminal signals of the current {@code Flowable} on the specified {@link Scheduler}, - * asynchronously with a bounded buffer and optionally delays {@code onError} notifications. - *

- * - *

- * This operator keeps emitting as many signals as it can on the given {@code Scheduler}'s Worker thread, - * which may result in a longer than expected occupation of this thread. In other terms, - * it does not allow per-signal fairness in case the worker runs on a shared underlying thread. - * If such fairness and signal/work interleaving is preferred, use the delay operator with zero time instead. - *

- *
Backpressure:
- *
This operator honors backpressure from downstream and expects it from the current {@code Flowable}. Violating this - * expectation will lead to {@link MissingBackpressureException}. This is the most common operator where the exception - * pops up; look for sources up the chain that don't support backpressure, - * such as {@link #interval(long, TimeUnit)}, {@link #timer(long, TimeUnit)}, - * {@link io.reactivex.rxjava4.processors.PublishProcessor PublishProcessor} or - * {@link io.reactivex.rxjava4.processors.BehaviorProcessor BehaviorProcessor} and apply any - * of the {@code onBackpressureXXX} operators before applying {@code observeOn} itself. - * Note also that request amounts are not preserved between the immediate downstream and the - * immediate upstream. The operator always requests the default {@link #bufferSize()} amount first, then after - * every 75% of that amount delivered, another 75% of this default value. If preserving the request amounts - * is to be preferred over potential excess scheduler infrastructure use, consider applying - * {@link #delay(long, TimeUnit, Scheduler, boolean)} with zero time instead. - *
- *
Scheduler:
- *
You specify which {@code Scheduler} this operator will use.
- *
- * - * @param scheduler - * the {@code Scheduler} to notify {@link Subscriber}s on - * @param delayError - * indicates if the {@code onError} notification may not cut ahead of {@code onNext} notification on the other side of the - * scheduling boundary. If {@code true}, a sequence ending in {@code onError} will be replayed in the same order as was received - * from upstream - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code scheduler} is {@code null} - * @see ReactiveX operators documentation: ObserveOn - * @see RxJava Threading Examples - * @see #subscribeOn - * @see #observeOn(Scheduler) - * @see #observeOn(Scheduler, boolean, int) - * @see #delay(long, TimeUnit, Scheduler, boolean) - */ - @CheckReturnValue - @BackpressureSupport(BackpressureKind.FULL) - @SchedulerSupport(SchedulerSupport.CUSTOM) - @NonNull - public final Flowable observeOn(@NonNull Scheduler scheduler, boolean delayError) { - return observeOn(scheduler, delayError, bufferSize()); + return observeOn(scheduler, StandardBufferedConfig.DEFAULT); } /** @@ -11208,29 +9929,25 @@ public final Flowable observeOn(@NonNull Scheduler scheduler, boolean delayEr * * @param scheduler * the {@code Scheduler} to notify {@link Subscriber}s on - * @param delayError - * indicates if the {@code onError} notification may not cut ahead of {@code onNext} notification on the other side of the - * scheduling boundary. If {@code true}, a sequence ending in {@code onError} will be replayed in the same order as was received - * from upstream - * @param bufferSize the size of the buffer. + * @param config + * the configuration record for this operatror * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code scheduler} is {@code null} - * @throws IllegalArgumentException if {@code bufferSize} is non-positive + * @throws NullPointerException if {@code scheduler} or {@code config} is {@code null} * @see ReactiveX operators documentation: ObserveOn * @see RxJava Threading Examples * @see #subscribeOn * @see #observeOn(Scheduler) - * @see #observeOn(Scheduler, boolean) * @see #delay(long, TimeUnit, Scheduler, boolean) + * @since 4.0.0 */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.CUSTOM) - public final Flowable observeOn(@NonNull Scheduler scheduler, boolean delayError, int bufferSize) { + public final Flowable observeOn(@NonNull Scheduler scheduler, @NonNull StandardBufferedConfig config) { Objects.requireNonNull(scheduler, "scheduler is null"); - ObjectHelper.verifyPositive(bufferSize, "bufferSize"); - return RxJavaPlugins.onAssembly(new FlowableObserveOn<>(this, scheduler, delayError, bufferSize)); + Objects.requireNonNull(config, "config is null"); + return RxJavaPlugins.onAssembly(new FlowableObserveOn<>(this, scheduler, config.delayErrors(), config.bufferSize())); } /** @@ -11267,7 +9984,7 @@ public final Flowable observeOn(@NonNull Scheduler scheduler, boolean delayEr *

* *

- * An error from the current {@code Flowable} will cut ahead of any unconsumed item. Use {@link #onBackpressureBuffer(boolean)} + * An error from the current {@code Flowable} will cut ahead of any unconsumed item. Use {@link #onBackpressureBuffer(OnBackpressureBufferConfig)} * to have the operator keep the original signal order. *

*
Backpressure:
@@ -11279,186 +9996,14 @@ public final Flowable observeOn(@NonNull Scheduler scheduler, boolean delayEr * * @return the new {@code Flowable} instance * @see ReactiveX operators documentation: backpressure operators - * @see #onBackpressureBuffer(boolean) + * @see #onBackpressureBuffer(OnBackpressureBufferConfig) */ @CheckReturnValue @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @SchedulerSupport(SchedulerSupport.NONE) @NonNull public final Flowable onBackpressureBuffer() { - return onBackpressureBuffer(bufferSize(), false, true); - } - - /** - * Buffers an unlimited number of items from the current {@code Flowable} and allows it to emit as fast it can while allowing the - * downstream to consume the items at its own place, optionally delaying an error until all buffered items have been consumed. - *

- * - *

- *
Backpressure:
- *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an unbounded - * manner (i.e., not applying backpressure to it).
- *
Scheduler:
- *
{@code onBackpressureBuffer} does not operate by default on a particular {@link Scheduler}.
- *
- * @param delayError - * if {@code true}, an exception from the current {@code Flowable} is delayed until all buffered elements have been - * consumed by the downstream; if {@code false}, an exception is immediately signaled to the downstream, skipping - * any buffered element - * @return the new {@code Flowable} instance - * @see ReactiveX operators documentation: backpressure operators - */ - @CheckReturnValue - @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) - @SchedulerSupport(SchedulerSupport.NONE) - @NonNull - public final Flowable onBackpressureBuffer(boolean delayError) { - return onBackpressureBuffer(bufferSize(), delayError, true); - } - - /** - * Buffers an limited number of items from the current {@code Flowable} and allows it to emit as fast it can while allowing the - * downstream to consume the items at its own place, however, the resulting {@code Flowable} will signal a - * {@link MissingBackpressureException} via {@code onError} as soon as the buffer's capacity is exceeded, dropping all undelivered - * items, and canceling the flow. - *

- * - *

- * An error from the current {@code Flowable} will cut ahead of any unconsumed item. Use {@link #onBackpressureBuffer(int, boolean)} - * to have the operator keep the original signal order. - *

- *
Backpressure:
- *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an unbounded - * manner (i.e., not applying backpressure to it).
- *
Scheduler:
- *
{@code onBackpressureBuffer} does not operate by default on a particular {@link Scheduler}.
- *
- * - * @param capacity number of slots available in the buffer. - * @return the new {@code Flowable} instance - * @throws IllegalArgumentException if {@code capacity} is non-positive - * @see ReactiveX operators documentation: backpressure operators - * @since 1.1.0 - * @see #onBackpressureBuffer(long, Action, BackpressureOverflowStrategy) - */ - @CheckReturnValue - @BackpressureSupport(BackpressureKind.ERROR) - @SchedulerSupport(SchedulerSupport.NONE) - @NonNull - public final Flowable onBackpressureBuffer(int capacity) { - return onBackpressureBuffer(capacity, false, false); - } - - /** - * Buffers an limited number of items from the current {@code Flowable} and allows it to emit as fast it can while allowing the - * downstream to consume the items at its own place, however, the resulting {@code Flowable} will signal a - * {@link MissingBackpressureException} via {@code onError} as soon as the buffer's capacity is exceeded, dropping all undelivered - * items, and canceling the flow. - *

- * - *

- *
Backpressure:
- *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an unbounded - * manner (i.e., not applying backpressure to it).
- *
Scheduler:
- *
{@code onBackpressureBuffer} does not operate by default on a particular {@link Scheduler}.
- *
- * - * @param capacity number of slots available in the buffer. - * @param delayError - * if {@code true}, an exception from the current {@code Flowable} is delayed until all buffered elements have been - * consumed by the downstream; if {@code false}, an exception is immediately signaled to the downstream, skipping - * any buffered element - * @return the new {@code Flowable} instance - * @throws IllegalArgumentException if {@code capacity} is non-positive - * @see ReactiveX operators documentation: backpressure operators - * @since 1.1.0 - */ - @CheckReturnValue - @BackpressureSupport(BackpressureKind.ERROR) - @SchedulerSupport(SchedulerSupport.NONE) - @NonNull - public final Flowable onBackpressureBuffer(int capacity, boolean delayError) { - return onBackpressureBuffer(capacity, delayError, false); - } - - /** - * Buffers an optionally unlimited number of items from the current {@code Flowable} and allows it to emit as fast it can while allowing the - * downstream to consume the items at its own place. - * If {@code unbounded} is {@code true}, the resulting {@code Flowable} will signal a - * {@link MissingBackpressureException} via {@code onError} as soon as the buffer's capacity is exceeded, dropping all undelivered - * items, and canceling the flow. - *

- * - *

- *
Backpressure:
- *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an unbounded - * manner (i.e., not applying backpressure to it).
- *
Scheduler:
- *
{@code onBackpressureBuffer} does not operate by default on a particular {@link Scheduler}.
- *
- * - * @param capacity number of slots available in the buffer. - * @param delayError - * if {@code true}, an exception from the current {@code Flowable} is delayed until all buffered elements have been - * consumed by the downstream; if {@code false}, an exception is immediately signaled to the downstream, skipping - * any buffered element - * @param unbounded - * if {@code true}, the capacity value is interpreted as the internal "island" size of the unbounded buffer - * @return the new {@code Flowable} instance - * @throws IllegalArgumentException if {@code capacity} is non-positive - * @see ReactiveX operators documentation: backpressure operators - * @since 1.1.0 - */ - @CheckReturnValue - @BackpressureSupport(BackpressureKind.SPECIAL) - @SchedulerSupport(SchedulerSupport.NONE) - @NonNull - public final Flowable onBackpressureBuffer(int capacity, boolean delayError, boolean unbounded) { - ObjectHelper.verifyPositive(capacity, "capacity"); - return RxJavaPlugins.onAssembly(new FlowableOnBackpressureBuffer<>(this, capacity, unbounded, delayError, Functions.EMPTY_ACTION, Functions.emptyConsumer())); - } - - /** - * Buffers an optionally unlimited number of items from the current {@code Flowable} and allows it to emit as fast it can while allowing the - * downstream to consume the items at its own place. - * If {@code unbounded} is {@code true}, the resulting {@code Flowable} will signal a - * {@link MissingBackpressureException} via {@code onError} as soon as the buffer's capacity is exceeded, dropping all undelivered - * items, canceling the flow and calling the {@code onOverflow} action. - *

- * - *

- *
Backpressure:
- *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an unbounded - * manner (i.e., not applying backpressure to it).
- *
Scheduler:
- *
{@code onBackpressureBuffer} does not operate by default on a particular {@link Scheduler}.
- *
- * - * @param capacity number of slots available in the buffer. - * @param delayError - * if {@code true}, an exception from the current {@code Flowable} is delayed until all buffered elements have been - * consumed by the downstream; if {@code false}, an exception is immediately signaled to the downstream, skipping - * any buffered element - * @param unbounded - * if {@code true}, the capacity value is interpreted as the internal "island" size of the unbounded buffer - * @param onOverflow action to execute if an item needs to be buffered, but there are no available slots. - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code onOverflow} is {@code null} - * @throws IllegalArgumentException if {@code capacity} is non-positive - * @see ReactiveX operators documentation: backpressure operators - * @see #onBackpressureBuffer(int, boolean, boolean, Action, Consumer) - * @since 1.1.0 - */ - @CheckReturnValue - @NonNull - @BackpressureSupport(BackpressureKind.SPECIAL) - @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable onBackpressureBuffer(int capacity, boolean delayError, boolean unbounded, - @NonNull Action onOverflow) { - Objects.requireNonNull(onOverflow, "onOverflow is null"); - ObjectHelper.verifyPositive(capacity, "capacity"); - return RxJavaPlugins.onAssembly(new FlowableOnBackpressureBuffer<>(this, capacity, unbounded, delayError, onOverflow, Functions.emptyConsumer())); + return onBackpressureBuffer(OnBackpressureBufferConfig.DEFAULT); } /** @@ -11466,50 +10011,7 @@ public final Flowable onBackpressureBuffer(int capacity, boolean delayError, * downstream to consume the items at its own place. * If {@code unbounded} is {@code true}, the resulting {@code Flowable} will signal a * {@link MissingBackpressureException} via {@code onError} as soon as the buffer's capacity is exceeded, dropping all undelivered - * items, canceling the flow and calling the {@code onOverflow} action. - *

- * - *

- *
Backpressure:
- *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an unbounded - * manner (i.e., not applying backpressure to it).
- *
Scheduler:
- *
{@code onBackpressureBuffer} does not operate by default on a particular {@link Scheduler}.
- *
- * - * @param capacity number of slots available in the buffer. - * @param delayError - * if {@code true}, an exception from the current {@code Flowable} is delayed until all buffered elements have been - * consumed by the downstream; if {@code false}, an exception is immediately signaled to the downstream, skipping - * any buffered element - * @param unbounded - * if {@code true}, the capacity value is interpreted as the internal "island" size of the unbounded buffer - * @param onOverflow action to execute if an item needs to be buffered, but there are no available slots. - * @param onDropped the {@link Consumer} to be called with the item that could not be buffered due to capacity constraints. - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code onOverflow} or {@code onDropped} is {@code null} - * @throws IllegalArgumentException if {@code capacity} is non-positive - * @see ReactiveX operators documentation: backpressure operators - * @since 3.1.7 - */ - @CheckReturnValue - @NonNull - @BackpressureSupport(BackpressureKind.SPECIAL) - @SchedulerSupport(SchedulerSupport.NONE) - @Experimental - public final Flowable onBackpressureBuffer(int capacity, boolean delayError, boolean unbounded, - @NonNull Action onOverflow, @NonNull Consumer onDropped) { - Objects.requireNonNull(onOverflow, "onOverflow is null"); - Objects.requireNonNull(onDropped, "onDropped is null"); - ObjectHelper.verifyPositive(capacity, "capacity"); - return RxJavaPlugins.onAssembly(new FlowableOnBackpressureBuffer<>(this, capacity, unbounded, delayError, onOverflow, onDropped)); - } - - /** - * Buffers an limited number of items from the current {@code Flowable} and allows it to emit as fast it can while allowing the - * downstream to consume the items at its own place, however, the resulting {@code Flowable} will signal a - * {@link MissingBackpressureException} via {@code onError} as soon as the buffer's capacity is exceeded, dropping all undelivered - * items, canceling the flow and calling the {@code onOverflow} action. + * items, canceling the flow and calling the {@code onDropped} action. *

* *

@@ -11520,20 +10022,20 @@ public final Flowable onBackpressureBuffer(int capacity, boolean delayError, *
{@code onBackpressureBuffer} does not operate by default on a particular {@link Scheduler}.
*
* - * @param capacity number of slots available in the buffer. - * @param onOverflow action to execute if an item needs to be buffered, but there are no available slots. Null is allowed. + * @param config the configuration record for this operator * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code onOverflow} is {@code null} - * @throws IllegalArgumentException if {@code capacity} is non-positive + * @throws NullPointerException if {@code config} is {@code null} * @see ReactiveX operators documentation: backpressure operators - * @since 1.1.0 + * @since 4.0.0 */ @CheckReturnValue - @BackpressureSupport(BackpressureKind.ERROR) - @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final Flowable onBackpressureBuffer(int capacity, @NonNull Action onOverflow) { - return onBackpressureBuffer(capacity, false, false, onOverflow); + @BackpressureSupport(BackpressureKind.SPECIAL) + @SchedulerSupport(SchedulerSupport.NONE) + public final Flowable onBackpressureBuffer(@NonNull OnBackpressureBufferConfig config) { + Objects.requireNonNull(config, "config is null"); + return RxJavaPlugins.onAssembly(new FlowableOnBackpressureBuffer<>(this, config.capacity(), + config.unbounded(), config.delayError(), config.onDropped())); } /** @@ -11542,13 +10044,13 @@ public final Flowable onBackpressureBuffer(int capacity, @NonNull Action onOv * The resulting {@code Flowable} will behave as determined by {@code overflowStrategy} if the buffer capacity is exceeded: *
    *
  • {@link BackpressureOverflowStrategy#ERROR} (default) will call {@code onError} dropping all undelivered items, - * canceling the source, and notifying the producer with {@code onOverflow}.
  • + * canceling the source, and notifying the producer with {@code onDropped}. *
  • {@link BackpressureOverflowStrategy#DROP_LATEST} will drop any new items emitted by the producer while - * the buffer is full, without generating any {@code onError}. Each drop will, however, invoke {@code onOverflow} + * the buffer is full, without generating any {@code onError}. Each drop will, however, invoke {@code onDropped} * to signal the overflow to the producer.
  • *
  • {@link BackpressureOverflowStrategy#DROP_OLDEST} will drop the oldest items in the buffer in order to make * room for newly emitted ones. Overflow will not generate an {@code onError}, but each drop will invoke - * {@code onOverflow} to signal the overflow to the producer.
  • + * {@code onDropped} to signal the overflow to the producer. *
* *

@@ -11562,23 +10064,21 @@ public final Flowable onBackpressureBuffer(int capacity, @NonNull Action onOv *

* * @param capacity number of slots available in the buffer. - * @param onOverflow action to execute if an item needs to be buffered, but there are no available slots, {@code null} is allowed. * @param overflowStrategy how should the resulting {@code Flowable} react to buffer overflows, {@code null} is not allowed. * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code onOverflow} or {@code overflowStrategy} is {@code null} + * @throws NullPointerException if {@code overflowStrategy} is {@code null} * @throws IllegalArgumentException if {@code capacity} is non-positive * @see ReactiveX operators documentation: backpressure operators - * @see #onBackpressureBuffer(long, Action, BackpressureOverflowStrategy) - * @since 2.0 + * @since 4.0.0 */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.SPECIAL) @SchedulerSupport(SchedulerSupport.NONE) - public final Flowable onBackpressureBuffer(long capacity, @Nullable Action onOverflow, @NonNull BackpressureOverflowStrategy overflowStrategy) { + public final Flowable onBackpressureBuffer(long capacity, @NonNull BackpressureOverflowStrategy overflowStrategy) { Objects.requireNonNull(overflowStrategy, "overflowStrategy is null"); ObjectHelper.verifyPositive(capacity, "capacity"); - return RxJavaPlugins.onAssembly(new FlowableOnBackpressureBufferStrategy<>(this, capacity, onOverflow, overflowStrategy, null)); + return RxJavaPlugins.onAssembly(new FlowableOnBackpressureBufferStrategy<>(this, capacity, overflowStrategy, null)); } /** @@ -11587,13 +10087,13 @@ public final Flowable onBackpressureBuffer(long capacity, @Nullable Action on * The resulting {@code Flowable} will behave as determined by {@code overflowStrategy} if the buffer capacity is exceeded: *
    *
  • {@link BackpressureOverflowStrategy#ERROR} (default) will call {@code onError} dropping all undelivered items, - * canceling the source, and notifying the producer with {@code onOverflow}.
  • + * canceling the source, and notifying the producer with {@code onDropped}. *
  • {@link BackpressureOverflowStrategy#DROP_LATEST} will drop any new items emitted by the producer while - * the buffer is full, without generating any {@code onError}. Each drop will, however, invoke {@code onOverflow} + * the buffer is full, without generating any {@code onError}. Each drop will, however, invoke {@code onDropped} * to signal the overflow to the producer.
  • *
  • {@link BackpressureOverflowStrategy#DROP_OLDEST} will drop the oldest items in the buffer in order to make * room for newly emitted ones. Overflow will not generate an {@code onError}, but each drop will invoke - * {@code onOverflow} to signal the overflow to the producer.
  • + * {@code onDropped} to signal the overflow to the producer. *
* *

@@ -11607,26 +10107,25 @@ public final Flowable onBackpressureBuffer(long capacity, @Nullable Action on * * * @param capacity number of slots available in the buffer. - * @param onOverflow action to execute if an item needs to be buffered, but there are no available slots, {@code null} is allowed. * @param overflowStrategy how should the resulting {@code Flowable} react to buffer overflows, {@code null} is not allowed. * @param onDropped the {@link Consumer} to be called with the item that could not be buffered due to capacity constraints. * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code onOverflow}, {@code overflowStrategy} or {@code onDropped} is {@code null} + * @throws NullPointerException if {@code overflowStrategy} or {@code onDropped} is {@code null} * @throws IllegalArgumentException if {@code capacity} is non-positive * @see ReactiveX operators documentation: backpressure operators - * @since 3.1.7 + * @since 4.0.0 */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.SPECIAL) @SchedulerSupport(SchedulerSupport.NONE) - @Experimental - public final Flowable onBackpressureBuffer(long capacity, @Nullable Action onOverflow, - @NonNull BackpressureOverflowStrategy overflowStrategy, @NonNull Consumer onDropped) { + public final Flowable onBackpressureBuffer(long capacity, + @NonNull BackpressureOverflowStrategy overflowStrategy, + @NonNull Consumer onDropped) { Objects.requireNonNull(overflowStrategy, "overflowStrategy is null"); Objects.requireNonNull(onDropped, "onDropped is null"); ObjectHelper.verifyPositive(capacity, "capacity"); - return RxJavaPlugins.onAssembly(new FlowableOnBackpressureBufferStrategy<>(this, capacity, onOverflow, overflowStrategy, onDropped)); + return RxJavaPlugins.onAssembly(new FlowableOnBackpressureBufferStrategy<>(this, capacity, overflowStrategy, onDropped)); } /** * Drops items from the current {@code Flowable} if the downstream is not ready to receive new items (indicated @@ -11754,7 +10253,6 @@ public final Flowable onBackpressureLatest() { @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - @Experimental public final Flowable onBackpressureLatest(@NonNull Consumer onDropped) { Objects.requireNonNull(onDropped, "onDropped is null"); return RxJavaPlugins.onAssembly(new FlowableOnBackpressureLatest<>(this, onDropped)); @@ -12334,7 +10832,7 @@ public final ConnectableFlowable publish(int bufferSize) { @SchedulerSupport(SchedulerSupport.NONE) @NonNull public final Flowable rebatchRequests(int n) { - return observeOn(ImmediateThinScheduler.INSTANCE, true, n); + return observeOn(ImmediateThinScheduler.INSTANCE, new StandardBufferedConfig(true, n)); } /** @@ -13664,42 +12162,6 @@ public final Flowable sample(long period, @NonNull TimeUnit unit) { return sample(period, unit, Schedulers.computation()); } - /** - * Returns a {@code Flowable} that emits the most recently emitted item (if any) emitted by the current {@code Flowable} - * within periodic time intervals and optionally emit the very last upstream item when the upstream completes. - *

- * - *

- *
Backpressure:
- *
This operator does not support backpressure as it uses time to control data flow.
- *
Scheduler:
- *
{@code sample} operates by default on the {@code computation} {@link Scheduler}.
- *
- * - *

History: 2.0.5 - experimental - * @param period - * the sampling rate - * @param unit - * the {@link TimeUnit} in which {@code period} is defined - * @param emitLast - * if {@code true}, and the upstream completes while there is still an unsampled item available, - * that item is emitted to downstream before completion - * if {@code false}, an unsampled last item is ignored. - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code unit} is {@code null} - * @see ReactiveX operators documentation: Sample - * @see RxJava wiki: Backpressure - * @see #throttleLast(long, TimeUnit) - * @since 2.1 - */ - @CheckReturnValue - @BackpressureSupport(BackpressureKind.ERROR) - @SchedulerSupport(SchedulerSupport.COMPUTATION) - @NonNull - public final Flowable sample(long period, @NonNull TimeUnit unit, boolean emitLast) { - return sample(period, unit, Schedulers.computation(), emitLast); - } - /** * Returns a {@code Flowable} that emits the most recently emitted item (if any) emitted by the current {@code Flowable} * within periodic time intervals, where the intervals are defined on a particular {@link Scheduler}. @@ -13734,47 +12196,6 @@ public final Flowable sample(long period, @NonNull TimeUnit unit, @NonNull Sc return RxJavaPlugins.onAssembly(new FlowableSampleTimed<>(this, period, unit, scheduler, false, null)); } - /** - * Returns a {@code Flowable} that emits the most recently emitted item (if any) emitted by the current {@code Flowable} - * within periodic time intervals, where the intervals are defined on a particular {@link Scheduler} - * and optionally emit the very last upstream item when the upstream completes. - *

- * - *

- *
Backpressure:
- *
This operator does not support backpressure as it uses time to control data flow.
- *
Scheduler:
- *
You specify which {@code Scheduler} this operator will use.
- *
- * - *

History: 2.0.5 - experimental - * @param period - * the sampling rate - * @param unit - * the {@link TimeUnit} in which {@code period} is defined - * @param scheduler - * the {@code Scheduler} to use when sampling - * @param emitLast - * if {@code true} and the upstream completes while there is still an unsampled item available, - * that item is emitted to downstream before completion - * if {@code false}, an unsampled last item is ignored. - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} - * @see ReactiveX operators documentation: Sample - * @see RxJava wiki: Backpressure - * @see #throttleLast(long, TimeUnit, Scheduler) - * @since 2.1 - */ - @CheckReturnValue - @NonNull - @BackpressureSupport(BackpressureKind.ERROR) - @SchedulerSupport(SchedulerSupport.CUSTOM) - public final Flowable sample(long period, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean emitLast) { - Objects.requireNonNull(unit, "unit is null"); - Objects.requireNonNull(scheduler, "scheduler is null"); - return RxJavaPlugins.onAssembly(new FlowableSampleTimed<>(this, period, unit, scheduler, emitLast, null)); - } - /** * Returns a {@code Flowable} that emits the most recently emitted item (if any) emitted by the current {@code Flowable} * within periodic time intervals, where the intervals are defined on a particular {@link Scheduler} @@ -13794,29 +12215,25 @@ public final Flowable sample(long period, @NonNull TimeUnit unit, @NonNull Sc * the {@link TimeUnit} in which {@code period} is defined * @param scheduler * the {@code Scheduler} to use when sampling - * @param emitLast - * if {@code true} and the upstream completes while there is still an unsampled item available, - * that item is emitted to downstream before completion - * if {@code false}, an unsampled last item is ignored. - * @param onDropped - * called with the current entry when it has been replaced by a new one + * @param config + * the configuration record for this operator * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} or {@code onDropped} is {@code null} + * @throws NullPointerException if {@code unit} or {@code scheduler} or {@code config} is {@code null} * @see ReactiveX operators documentation: Sample * @see RxJava wiki: Backpressure * @see #throttleLast(long, TimeUnit, Scheduler) - * @since 3.1.6 - Experimental + * @since 4.0.0 */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.ERROR) @SchedulerSupport(SchedulerSupport.CUSTOM) - @Experimental - public final Flowable sample(long period, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean emitLast, @NonNull Consumer onDropped) { + public final Flowable sample(long period, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, + @NonNull SampleConfig config) { Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); - Objects.requireNonNull(onDropped, "onDropped is null"); - return RxJavaPlugins.onAssembly(new FlowableSampleTimed<>(this, period, unit, scheduler, emitLast, onDropped)); + Objects.requireNonNull(config, "config is null"); + return RxJavaPlugins.onAssembly(new FlowableSampleTimed<>(this, period, unit, scheduler, config.emitLast(), config.onDropped())); } /** @@ -14317,42 +12734,7 @@ public final Flowable skipLast(int count) { @SchedulerSupport(SchedulerSupport.NONE) @NonNull public final Flowable skipLast(long time, @NonNull TimeUnit unit) { - return skipLast(time, unit, Schedulers.computation(), false, bufferSize()); - } - - /** - * Returns a {@code Flowable} that drops items emitted by the current {@code Flowable} during a specified time window - * before the source completes. - *

- * - *

- * Note: this action will cache the latest items arriving in the specified time window. - *

- *
Backpressure:
- *
The operator doesn't support backpressure as it uses time to skip an arbitrary number of elements and - * thus has to consume the current {@code Flowable} in an unbounded manner (i.e., no backpressure applied to it).
- *
Scheduler:
- *
{@code skipLast} does not operate on any particular scheduler but uses the current time - * from the {@code computation} {@link Scheduler}.
- *
- * - * @param time - * the length of the time window - * @param unit - * the time unit of {@code time} - * @param delayError - * if {@code true}, an exception signaled by the current {@code Flowable} is delayed until the regular elements are consumed - * by the downstream; if {@code false}, an exception is immediately signaled and all regular elements dropped - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code unit} is {@code null} - * @see ReactiveX operators documentation: SkipLast - */ - @CheckReturnValue - @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) - @SchedulerSupport(SchedulerSupport.NONE) - @NonNull - public final Flowable skipLast(long time, @NonNull TimeUnit unit, boolean delayError) { - return skipLast(time, unit, Schedulers.computation(), delayError, bufferSize()); + return skipLast(time, unit, Schedulers.computation(), StandardBufferedConfig.DEFAULT); } /** @@ -14385,43 +12767,7 @@ public final Flowable skipLast(long time, @NonNull TimeUnit unit, boolean del @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull public final Flowable skipLast(long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { - return skipLast(time, unit, scheduler, false, bufferSize()); - } - - /** - * Returns a {@code Flowable} that drops items emitted by the current {@code Flowable} during a specified time window - * (defined on a specified scheduler) before the source completes. - *

- * - *

- * Note: this action will cache the latest items arriving in the specified time window. - *

- *
Backpressure:
- *
The operator doesn't support backpressure as it uses time to skip an arbitrary number of elements and - * thus has to consume the current {@code Flowable} in an unbounded manner (i.e., no backpressure applied to it).
- *
Scheduler:
- *
You specify which {@link Scheduler} this operator will use to track the current time
- *
- * - * @param time - * the length of the time window - * @param unit - * the time unit of {@code time} - * @param scheduler - * the scheduler used as the time source - * @param delayError - * if {@code true}, an exception signaled by the current {@code Flowable} is delayed until the regular elements are consumed - * by the downstream; if {@code false}, an exception is immediately signaled and all regular elements dropped - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} - * @see ReactiveX operators documentation: SkipLast - */ - @CheckReturnValue - @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) - @SchedulerSupport(SchedulerSupport.CUSTOM) - @NonNull - public final Flowable skipLast(long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean delayError) { - return skipLast(time, unit, scheduler, delayError, bufferSize()); + return skipLast(time, unit, scheduler, StandardBufferedConfig.DEFAULT); } /** @@ -14445,27 +12791,25 @@ public final Flowable skipLast(long time, @NonNull TimeUnit unit, @NonNull Sc * the time unit of {@code time} * @param scheduler * the scheduler used as the time source - * @param delayError - * if {@code true}, an exception signaled by the current {@code Flowable} is delayed until the regular elements are consumed - * by the downstream; if {@code false}, an exception is immediately signaled and all regular elements dropped - * @param bufferSize - * the hint about how many elements to expect to be skipped + * @param config + * the configuration record for this operator * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} - * @throws IllegalArgumentException if {@code bufferSize} is non-positive + * @throws NullPointerException if {@code unit} or {@code scheduler} or {@code config} is {@code null} * @see ReactiveX operators documentation: SkipLast + * @since 4.0.0 */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @SchedulerSupport(SchedulerSupport.CUSTOM) - public final Flowable skipLast(long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean delayError, int bufferSize) { + public final Flowable skipLast(long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, + @NonNull StandardBufferedConfig config) { Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); - ObjectHelper.verifyPositive(bufferSize, "bufferSize"); + Objects.requireNonNull(config, "config is null"); // the internal buffer holds pairs of (timestamp, value) so double the default buffer size - int s = bufferSize << 1; - return RxJavaPlugins.onAssembly(new FlowableSkipLastTimed<>(this, time, unit, scheduler, s, delayError)); + int s = config.bufferSize() << 1; + return RxJavaPlugins.onAssembly(new FlowableSkipLastTimed<>(this, time, unit, scheduler, s, config.delayErrors())); } /** @@ -15209,14 +13553,13 @@ public final Flowable switchIfEmpty(@NonNull Publisher other) { * @return the new {@code Flowable} instance * @throws NullPointerException if {@code mapper} is {@code null} * @see ReactiveX operators documentation: FlatMap - * @see #switchMapDelayError(Function) */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull public final <@NonNull R> Flowable switchMap(@NonNull Function> mapper) { - return switchMap(mapper, bufferSize()); + return switchMap(mapper, StandardBufferedConfig.DEFAULT); } /** @@ -15242,20 +13585,30 @@ public final Flowable switchIfEmpty(@NonNull Publisher other) { * @param mapper * a function that, when applied to an item emitted by the current {@code Flowable}, returns a * {@code Publisher} - * @param bufferSize - * the number of elements to prefetch from the current active inner {@code Publisher} + * @param config + * the configuration record for this operator * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code mapper} is {@code null} - * @throws IllegalArgumentException if {@code bufferSize} is non-positive + * @throws NullPointerException if {@code mapper} or {@code config} is {@code null} * @see ReactiveX operators documentation: FlatMap - * @see #switchMapDelayError(Function, int) + * @since 4.0.0 */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final <@NonNull R> Flowable switchMap(@NonNull Function> mapper, int bufferSize) { - return switchMap0(mapper, bufferSize, false); + public final <@NonNull R> Flowable switchMap(@NonNull Function> mapper, + @NonNull StandardBufferedConfig config) { + Objects.requireNonNull(mapper, "mapper is null"); + Objects.requireNonNull(config, "config is null"); + if (this instanceof ScalarSupplier) { + @SuppressWarnings("unchecked") + T v = ((ScalarSupplier)this).get(); + if (v == null) { + return empty(); + } + return FlowableScalarXMap.scalarXMap(v, mapper); + } + return RxJavaPlugins.onAssembly(new FlowableSwitchMap<>(this, mapper, config.bufferSize(), config.delayErrors())); } /** @@ -15322,128 +13675,35 @@ public final Completable switchMapCompletable(@NonNull FunctionThe operator consumes the current {@code Flowable} in an unbounded manner and otherwise * does not have backpressure in its return type because no items are ever produced. *
Scheduler:
- *
{@code switchMapCompletableDelayError} does not operate by default on a particular {@link Scheduler}.
- *
Error handling:
- *
The errors of this {@code Flowable} and all the {@code CompletableSource}s, who had the chance - * to run to their completion, are delayed until - * all of them terminate in some fashion. At this point, if there was only one failure, the respective - * {@link Throwable} is emitted to the downstream. If there was more than one failure, the - * operator combines all {@code Throwable}s into a {@link io.reactivex.rxjava4.exceptions.CompositeException CompositeException} - * and signals that to the downstream. - * If any inactivated (switched out) {@code CompletableSource} - * signals an {@code onError} late, the {@code Throwable}s will be signaled to the global error handler via - * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. - *
- * - *

History: 2.1.11 - experimental - * @param mapper the function called with each upstream item and should return a - * {@code CompletableSource} to be subscribed to and awaited for - * (non blockingly) for its terminal event - * @return the new {@code Completable} instance - * @throws NullPointerException if {@code mapper} is {@code null} - * @see #switchMapCompletable(Function) - * @since 2.2 - */ - @CheckReturnValue - @NonNull - @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) - @SchedulerSupport(SchedulerSupport.NONE) - public final Completable switchMapCompletableDelayError(@NonNull Function mapper) { - Objects.requireNonNull(mapper, "mapper is null"); - return RxJavaPlugins.onAssembly(new FlowableSwitchMapCompletable<>(this, mapper, true)); - } - - /** - * Returns a new {@code Flowable} by applying a function that you supply to each item emitted by the current - * {@code Flowable} that returns a {@link Publisher}, and then emitting the items emitted by the most recently emitted - * of these {@code Publisher}s and delays any error until all {@code Publisher}s terminate. - *

- * The resulting {@code Flowable} completes if both the current {@code Flowable} and the last inner {@code Publisher}, if any, complete. - * If the current {@code Flowable} signals an {@code onError}, the termination of the last inner {@code Publisher} will emit that error as is - * or wrapped into a {@link CompositeException} along with the other possible errors the former inner {@code Publisher}s signaled. - *

- * - *

- *
Backpressure:
- *
The operator honors backpressure from downstream. The outer {@code Publisher} is consumed in an - * unbounded manner (i.e., without backpressure) and the inner {@code Publisher}s are expected to honor - * backpressure but it is not enforced; the operator won't signal a {@link MissingBackpressureException} - * but the violation may lead to {@link OutOfMemoryError} due to internal buffer bloat.
- *
Scheduler:
- *
{@code switchMapDelayError} does not operate by default on a particular {@link Scheduler}.
- *
- * - * @param the element type of the inner {@code Publisher}s and the output - * @param mapper - * a function that, when applied to an item emitted by the current {@code Flowable}, returns a - * {@code Publisher} - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code mapper} is {@code null} - * @see ReactiveX operators documentation: FlatMap - * @see #switchMap(Function) - * @since 2.0 - */ - @CheckReturnValue - @BackpressureSupport(BackpressureKind.SPECIAL) - @SchedulerSupport(SchedulerSupport.NONE) - @NonNull - public final <@NonNull R> Flowable switchMapDelayError(@NonNull Function> mapper) { - return switchMapDelayError(mapper, bufferSize()); - } - - /** - * Returns a new {@code Flowable} by applying a function that you supply to each item emitted by the current - * {@code Flowable} that returns a {@link Publisher}, and then emitting the items emitted by the most recently emitted - * of these {@code Publisher}s and delays any error until all {@code Publisher}s terminate. - *

- * The resulting {@code Flowable} completes if both the current {@code Flowable} and the last inner {@code Publisher}, if any, complete. - * If the current {@code Flowable} signals an {@code onError}, the termination of the last inner {@code Publisher} will emit that error as is - * or wrapped into a {@link CompositeException} along with the other possible errors the former inner {@code Publisher}s signaled. - *

- * - *

- *
Backpressure:
- *
The operator honors backpressure from downstream. The outer {@code Publisher} is consumed in an - * unbounded manner (i.e., without backpressure) and the inner {@code Publisher}s are expected to honor - * backpressure but it is not enforced; the operator won't signal a {@link MissingBackpressureException} - * but the violation may lead to {@link OutOfMemoryError} due to internal buffer bloat.
- *
Scheduler:
- *
{@code switchMapDelayError} does not operate by default on a particular {@link Scheduler}.
+ *
{@code switchMapCompletableDelayError} does not operate by default on a particular {@link Scheduler}.
+ *
Error handling:
+ *
The errors of this {@code Flowable} and all the {@code CompletableSource}s, who had the chance + * to run to their completion, are delayed until + * all of them terminate in some fashion. At this point, if there was only one failure, the respective + * {@link Throwable} is emitted to the downstream. If there was more than one failure, the + * operator combines all {@code Throwable}s into a {@link io.reactivex.rxjava4.exceptions.CompositeException CompositeException} + * and signals that to the downstream. + * If any inactivated (switched out) {@code CompletableSource} + * signals an {@code onError} late, the {@code Throwable}s will be signaled to the global error handler via + * {@link RxJavaPlugins#onError(Throwable)} method as {@link UndeliverableException} errors. + *
*
- * - * @param the element type of the inner {@code Publisher}s and the output - * @param mapper - * a function that, when applied to an item emitted by the current {@code Flowable}, returns a - * {@code Publisher} - * @param bufferSize - * the number of elements to prefetch from the current active inner {@code Publisher} - * @return the new {@code Flowable} instance + *

History: 2.1.11 - experimental + * @param mapper the function called with each upstream item and should return a + * {@code CompletableSource} to be subscribed to and awaited for + * (non blockingly) for its terminal event + * @return the new {@code Completable} instance * @throws NullPointerException if {@code mapper} is {@code null} - * @throws IllegalArgumentException if {@code bufferSize} is non-positive - * @see ReactiveX operators documentation: FlatMap - * @see #switchMap(Function, int) - * @since 2.0 + * @see #switchMapCompletable(Function) + * @since 2.2 */ @CheckReturnValue - @BackpressureSupport(BackpressureKind.SPECIAL) - @SchedulerSupport(SchedulerSupport.NONE) @NonNull - public final <@NonNull R> Flowable switchMapDelayError(@NonNull Function> mapper, int bufferSize) { - return switchMap0(mapper, bufferSize, true); - } - - Flowable switchMap0(Function> mapper, int bufferSize, boolean delayError) { + @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) + @SchedulerSupport(SchedulerSupport.NONE) + public final Completable switchMapCompletableDelayError(@NonNull Function mapper) { Objects.requireNonNull(mapper, "mapper is null"); - ObjectHelper.verifyPositive(bufferSize, "bufferSize"); - if (this instanceof ScalarSupplier) { - @SuppressWarnings("unchecked") - T v = ((ScalarSupplier)this).get(); - if (v == null) { - return empty(); - } - return FlowableScalarXMap.scalarXMap(v, mapper); - } - return RxJavaPlugins.onAssembly(new FlowableSwitchMap<>(this, mapper, bufferSize, delayError)); + return RxJavaPlugins.onAssembly(new FlowableSwitchMapCompletable<>(this, mapper, true)); } /** @@ -15779,7 +14039,7 @@ public final Flowable takeLast(int count) { @SchedulerSupport(SchedulerSupport.NONE) @NonNull public final Flowable takeLast(long count, long time, @NonNull TimeUnit unit) { - return takeLast(count, time, unit, Schedulers.computation(), false, bufferSize()); + return takeLast(count, time, unit, Schedulers.computation()); } /** @@ -15815,7 +14075,7 @@ public final Flowable takeLast(long count, long time, @NonNull TimeUnit unit) @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull public final Flowable takeLast(long count, long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { - return takeLast(count, time, unit, scheduler, false, bufferSize()); + return takeLast(count, time, unit, scheduler, StandardBufferedConfig.DEFAULT); } /** @@ -15840,29 +14100,28 @@ public final Flowable takeLast(long count, long time, @NonNull TimeUnit unit, * the time unit of {@code time} * @param scheduler * the {@code Scheduler} that provides the timestamps for the observed items - * @param delayError - * if {@code true}, an exception signaled by the current {@code Flowable} is delayed until the regular elements are consumed - * by the downstream; if {@code false}, an exception is immediately signaled and all regular elements dropped - * @param bufferSize - * the hint about how many elements to expect to be last + * @param config + * the configuration record for this operator * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @throws NullPointerException if {@code unit} or {@code scheduler} or {@code config} is {@code null} * @throws IllegalArgumentException * if {@code count} is negative or {@code bufferSize} is non-positive * @see ReactiveX operators documentation: TakeLast + * @since 4.0.0 */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.CUSTOM) - public final Flowable takeLast(long count, long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean delayError, int bufferSize) { + public final Flowable takeLast(long count, long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, + @NonNull StandardBufferedConfig config) { Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); - ObjectHelper.verifyPositive(bufferSize, "bufferSize"); + Objects.requireNonNull(config, "config is null"); if (count < 0) { throw new IllegalArgumentException("count >= 0 required but it was " + count); } - return RxJavaPlugins.onAssembly(new FlowableTakeLastTimed<>(this, count, time, unit, scheduler, bufferSize, delayError)); + return RxJavaPlugins.onAssembly(new FlowableTakeLastTimed<>(this, count, time, unit, scheduler, config.bufferSize(), config.delayErrors())); } /** @@ -15893,41 +14152,7 @@ public final Flowable takeLast(long count, long time, @NonNull TimeUnit unit, @SchedulerSupport(SchedulerSupport.COMPUTATION) @NonNull public final Flowable takeLast(long time, @NonNull TimeUnit unit) { - return takeLast(time, unit, Schedulers.computation(), false, bufferSize()); - } - - /** - * Returns a {@code Flowable} that emits the items from the current {@code Flowable} that were emitted in a specified - * window of time before the current {@code Flowable} completed. - *

- * - *

- *
Backpressure:
- *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an - * unbounded manner (i.e., no backpressure is applied to it) but note that this may - * lead to {@link OutOfMemoryError} due to internal buffer bloat. - * Consider using {@link #takeLast(long, long, TimeUnit)} in this case.
- *
Scheduler:
- *
This version of {@code takeLast} operates by default on the {@code computation} {@link Scheduler}.
- *
- * - * @param time - * the length of the time window - * @param unit - * the time unit of {@code time} - * @param delayError - * if {@code true}, an exception signaled by the current {@code Flowable} is delayed until the regular elements are consumed - * by the downstream; if {@code false}, an exception is immediately signaled and all regular elements dropped - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code unit} is {@code null} - * @see ReactiveX operators documentation: TakeLast - */ - @CheckReturnValue - @BackpressureSupport(BackpressureKind.FULL) - @SchedulerSupport(SchedulerSupport.COMPUTATION) - @NonNull - public final Flowable takeLast(long time, @NonNull TimeUnit unit, boolean delayError) { - return takeLast(time, unit, Schedulers.computation(), delayError, bufferSize()); + return takeLast(time, unit, Schedulers.computation(), StandardBufferedConfig.DEFAULT); } /** @@ -15961,44 +14186,7 @@ public final Flowable takeLast(long time, @NonNull TimeUnit unit, boolean del @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull public final Flowable takeLast(long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { - return takeLast(time, unit, scheduler, false, bufferSize()); - } - - /** - * Returns a {@code Flowable} that emits the items from the current {@code Flowable} that were emitted in a specified - * window of time before the current {@code Flowable} completed, where the timing information is provided by a specified - * {@link Scheduler}. - *

- * - *

- *
Backpressure:
- *
The operator honors backpressure from downstream and consumes the current {@code Flowable} in an - * unbounded manner (i.e., no backpressure is applied to it) but note that this may - * lead to {@link OutOfMemoryError} due to internal buffer bloat. - * Consider using {@link #takeLast(long, long, TimeUnit, Scheduler)} in this case.
- *
Scheduler:
- *
You specify which {@code Scheduler} this operator will use.
- *
- * - * @param time - * the length of the time window - * @param unit - * the time unit of {@code time} - * @param scheduler - * the {@code Scheduler} that provides the timestamps for the observed items - * @param delayError - * if {@code true}, an exception signaled by the current {@code Flowable} is delayed until the regular elements are consumed - * by the downstream; if {@code false}, an exception is immediately signaled and all regular elements dropped - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} - * @see ReactiveX operators documentation: TakeLast - */ - @CheckReturnValue - @BackpressureSupport(BackpressureKind.FULL) - @SchedulerSupport(SchedulerSupport.CUSTOM) - @NonNull - public final Flowable takeLast(long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean delayError) { - return takeLast(time, unit, scheduler, delayError, bufferSize()); + return takeLast(time, unit, scheduler, StandardBufferedConfig.DEFAULT); } /** @@ -16023,22 +14211,20 @@ public final Flowable takeLast(long time, @NonNull TimeUnit unit, @NonNull Sc * the time unit of {@code time} * @param scheduler * the {@code Scheduler} that provides the timestamps for the observed items - * @param delayError - * if {@code true}, an exception signaled by the current {@code Flowable} is delayed until the regular elements are consumed - * by the downstream; if {@code false}, an exception is immediately signaled and all regular elements dropped - * @param bufferSize - * the hint about how many elements to expect to be last + * @param config + * the configuration record for this operator * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} - * @throws IllegalArgumentException if {@code bufferSize} is non-positive + * @throws NullPointerException if {@code unit} or {@code scheduler} or {@code config} is {@code null} * @see ReactiveX operators documentation: TakeLast + * @since 4.0.0 */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - public final Flowable takeLast(long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean delayError, int bufferSize) { - return takeLast(Long.MAX_VALUE, time, unit, scheduler, delayError, bufferSize); + public final Flowable takeLast(long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, + @NonNull StandardBufferedConfig config) { + return takeLast(Long.MAX_VALUE, time, unit, scheduler, config); } /** @@ -16239,7 +14425,6 @@ public final Flowable throttleFirst(long skipDuration, @NonNull TimeUnit unit @NonNull @BackpressureSupport(BackpressureKind.ERROR) @SchedulerSupport(SchedulerSupport.CUSTOM) - @Experimental public final Flowable throttleFirst(long skipDuration, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, @NonNull Consumer onDropped) { Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); @@ -16354,9 +14539,8 @@ public final Flowable throttleLast(long intervalDuration, @NonNull TimeUnit u @BackpressureSupport(BackpressureKind.ERROR) @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - @Experimental public final Flowable throttleLast(long intervalDuration, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, @NonNull Consumer onDropped) { - return sample(intervalDuration, unit, scheduler, false, onDropped); + return sample(intervalDuration, unit, scheduler, new SampleConfig<>(false, onDropped)); } /** @@ -16366,7 +14550,7 @@ public final Flowable throttleLast(long intervalDuration, @NonNull TimeUnit u *

* *

- * Unlike the option with {@link #throttleLatest(long, TimeUnit, boolean)}, the very last item being held back + * Unlike the option with {@link #throttleLatest(long, TimeUnit, Scheduler, SampleConfig)}, the very last item being held back * (if any) is not emitted when the upstream completes. *

* If no items were emitted from the upstream during this timeout phase, the next @@ -16387,7 +14571,6 @@ public final Flowable throttleLast(long intervalDuration, @NonNull TimeUnit u * @return the new {@code Flowable} instance * @throws NullPointerException if {@code unit} is {@code null} * @since 2.2 - * @see #throttleLatest(long, TimeUnit, boolean) * @see #throttleLatest(long, TimeUnit, Scheduler) */ @CheckReturnValue @@ -16395,46 +14578,7 @@ public final Flowable throttleLast(long intervalDuration, @NonNull TimeUnit u @SchedulerSupport(SchedulerSupport.COMPUTATION) @NonNull public final Flowable throttleLatest(long timeout, @NonNull TimeUnit unit) { - return throttleLatest(timeout, unit, Schedulers.computation(), false); - } - - /** - * Throttles items from the upstream {@code Flowable} by first emitting the next - * item from upstream, then periodically emitting the latest item (if any) when - * the specified timeout elapses between them. - *

- * - *

- * If no items were emitted from the upstream during this timeout phase, the next - * upstream item is emitted immediately and the timeout window starts from then. - *

- *
Backpressure:
- *
This operator does not support backpressure as it uses time to control data flow. - * If the downstream is not ready to receive items, a - * {@link io.reactivex.rxjava4.exceptions.MissingBackpressureException MissingBackpressureException} - * will be signaled.
- *
Scheduler:
- *
{@code throttleLatest} operates by default on the {@code computation} {@link Scheduler}.
- *
- *

History: 2.1.14 - experimental - * @param timeout the time to wait after an item emission towards the downstream - * before trying to emit the latest item from upstream again - * @param unit the time unit - * @param emitLast If {@code true}, the very last item from the upstream will be emitted - * immediately when the upstream completes, regardless if there is - * a timeout window active or not. If {@code false}, the very last - * upstream item is ignored and the flow terminates. - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code unit} is {@code null} - * @see #throttleLatest(long, TimeUnit, Scheduler, boolean) - * @since 2.2 - */ - @CheckReturnValue - @BackpressureSupport(BackpressureKind.ERROR) - @SchedulerSupport(SchedulerSupport.COMPUTATION) - @NonNull - public final Flowable throttleLatest(long timeout, @NonNull TimeUnit unit, boolean emitLast) { - return throttleLatest(timeout, unit, Schedulers.computation(), emitLast); + return throttleLatest(timeout, unit, Schedulers.computation(), SampleConfig.DEFAULT); } /** @@ -16444,7 +14588,7 @@ public final Flowable throttleLatest(long timeout, @NonNull TimeUnit unit, bo *

* *

- * Unlike the option with {@link #throttleLatest(long, TimeUnit, Scheduler, boolean)}, the very last item being held back + * Unlike the option with {@link #throttleLatest(long, TimeUnit, Scheduler, SampleConfig)}, the very last item being held back * (if any) is not emitted when the upstream completes. *

* If no items were emitted from the upstream during this timeout phase, the next @@ -16466,7 +14610,7 @@ public final Flowable throttleLatest(long timeout, @NonNull TimeUnit unit, bo * emission will be performed * @return the new {@code Flowable} instance * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} - * @see #throttleLatest(long, TimeUnit, Scheduler, boolean) + * @see #throttleLatest(long, TimeUnit, Scheduler, SampleConfig) * @since 2.2 */ @CheckReturnValue @@ -16474,49 +14618,7 @@ public final Flowable throttleLatest(long timeout, @NonNull TimeUnit unit, bo @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull public final Flowable throttleLatest(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { - return throttleLatest(timeout, unit, scheduler, false); - } - - /** - * Throttles items from the upstream {@code Flowable} by first emitting the next - * item from upstream, then periodically emitting the latest item (if any) when - * the specified timeout elapses between them. - *

- * - *

- * If no items were emitted from the upstream during this timeout phase, the next - * upstream item is emitted immediately and the timeout window starts from then. - *

- *
Backpressure:
- *
This operator does not support backpressure as it uses time to control data flow. - * If the downstream is not ready to receive items, a - * {@link io.reactivex.rxjava4.exceptions.MissingBackpressureException MissingBackpressureException} - * will be signaled.
- *
Scheduler:
- *
You specify which {@link Scheduler} this operator will use.
- *
- *

History: 2.1.14 - experimental - * @param timeout the time to wait after an item emission towards the downstream - * before trying to emit the latest item from upstream again - * @param unit the time unit - * @param scheduler the {@code Scheduler} where the timed wait and latest item - * emission will be performed - * @param emitLast If {@code true}, the very last item from the upstream will be emitted - * immediately when the upstream completes, regardless if there is - * a timeout window active or not. If {@code false}, the very last - * upstream item is ignored and the flow terminates. - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} - * @since 2.2 - */ - @CheckReturnValue - @NonNull - @BackpressureSupport(BackpressureKind.ERROR) - @SchedulerSupport(SchedulerSupport.CUSTOM) - public final Flowable throttleLatest(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean emitLast) { - Objects.requireNonNull(unit, "unit is null"); - Objects.requireNonNull(scheduler, "scheduler is null"); - return RxJavaPlugins.onAssembly(new FlowableThrottleLatest<>(this, timeout, unit, scheduler, emitLast, null)); + return throttleLatest(timeout, unit, scheduler, SampleConfig.DEFAULT); } /** @@ -16550,27 +14652,22 @@ public final Flowable throttleLatest(long timeout, @NonNull TimeUnit unit, @N * @param unit the time unit * @param scheduler the {@code Scheduler} where the timed wait and latest item * emission will be performed - * @param emitLast If {@code true}, the very last item from the upstream will be emitted - * immediately when the upstream completes, regardless if there is - * a timeout window active or not. If {@code false}, the very last - * upstream item is ignored and the flow terminates. - * @param onDropped called when an item is replaced by a newer item that doesn't get delivered - * to the downstream, including the very last item if {@code emitLast} is {@code false} - * and the current undelivered item when the sequence gets cancelled. - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code unit}, {@code scheduler} or {@code onDropped} is {@code null} - * @since 3.1.6 - Experimental + * @param config + * the configuration record for this operator + * @return the new {@code Flowable} instance + * @throws NullPointerException if {@code unit}, {@code scheduler} or {@code config} is {@code null} + * @since 4.0.0 */ @CheckReturnValue @NonNull @BackpressureSupport(BackpressureKind.ERROR) @SchedulerSupport(SchedulerSupport.CUSTOM) - @Experimental - public final Flowable throttleLatest(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean emitLast, @NonNull Consumer onDropped) { + public final Flowable throttleLatest(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, + @NonNull SampleConfig config) { Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); - Objects.requireNonNull(onDropped, "onDropped is null"); - return RxJavaPlugins.onAssembly(new FlowableThrottleLatest<>(this, timeout, unit, scheduler, emitLast, onDropped)); + Objects.requireNonNull(config, "config is null"); + return RxJavaPlugins.onAssembly(new FlowableThrottleLatest<>(this, timeout, unit, scheduler, config.emitLast(), config.onDropped())); } /** @@ -16686,7 +14783,6 @@ public final Flowable throttleWithTimeout(long timeout, @NonNull TimeUnit uni @BackpressureSupport(BackpressureKind.ERROR) @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - @Experimental public final Flowable throttleWithTimeout(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, @NonNull Consumer onDropped) { return debounce(timeout, unit, scheduler, onDropped); } @@ -18949,74 +17045,22 @@ public final Flowable> window( * @param zipper * a function that combines the pairs of items from the two {@code Publisher}s to generate the items to * be emitted by the resulting {@code Flowable} - * @param delayError - * if {@code true}, errors from the current {@code Flowable} or the other {@code Publisher} is delayed until both terminate - * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code other} or {@code zipper} is {@code null} - * @see ReactiveX operators documentation: Zip - * @since 2.0 - */ - @CheckReturnValue - @BackpressureSupport(BackpressureKind.FULL) - @SchedulerSupport(SchedulerSupport.NONE) - @NonNull - public final <@NonNull U, @NonNull R> Flowable zipWith(@NonNull Publisher other, - @NonNull BiFunction zipper, boolean delayError) { - return zip(this, other, zipper, delayError); - } - - /** - * Returns a {@code Flowable} that emits items that are the result of applying a specified function to pairs of - * values, one each from the current {@code Flowable} and another specified {@link Publisher}. - *

- * The operator subscribes to its sources in the order they are specified and completes eagerly if - * one of the sources is shorter than the rest while canceling the other sources. Therefore, it - * is possible those other sources will never be able to run to completion (and thus not calling - * {@code doOnComplete()}). This can also happen if the sources are exactly the same length; if - * source A completes and B has been consumed and is about to complete, the operator detects A won't - * be sending further values and it will cancel B immediately. For example: - *

range(1, 5).doOnComplete(action1).zipWith(range(6, 5).doOnComplete(action2), (a, b) -> a + b)
- * {@code action1} will be called but {@code action2} won't. - *
To work around this termination property, - * use {@link #doOnCancel(Action)} as well or use {@code using()} to do cleanup in case of completion - * or cancellation. - *

- * - *

- *
Backpressure:
- *
The operator expects backpressure from the sources and honors backpressure from the downstream. - * (I.e., zipping with {@link #interval(long, TimeUnit)} may result in {@link MissingBackpressureException}, use - * one of the {@code onBackpressureX} to handle similar, backpressure-ignoring sources.
- *
Scheduler:
- *
{@code zipWith} does not operate by default on a particular {@link Scheduler}.
- *
- * - * @param - * the type of items emitted by the {@code other} {@code Publisher} - * @param - * the type of items emitted by the resulting {@code Flowable} - * @param other - * the other {@code Publisher} - * @param zipper - * a function that combines the pairs of items from the two {@code Publisher}s to generate the items to - * be emitted by the resulting {@code Flowable} - * @param bufferSize - * the capacity hint for the buffer in the inner windows - * @param delayError - * if {@code true}, errors from the current {@code Flowable} or the other {@code Publisher} is delayed until both terminate + * @param config + * the configuration record for this operator * @return the new {@code Flowable} instance - * @throws NullPointerException if {@code other} or {@code zipper} is {@code null} - * @throws IllegalArgumentException if {@code bufferSize} is non-positive + * @throws NullPointerException if {@code other} or {@code zipper} or {@code config} is {@code null} * @see ReactiveX operators documentation: Zip - * @since 2.0 + * @since 4.0.0 */ @CheckReturnValue @BackpressureSupport(BackpressureKind.FULL) @SchedulerSupport(SchedulerSupport.NONE) @NonNull public final <@NonNull U, @NonNull R> Flowable zipWith(@NonNull Publisher other, - @NonNull BiFunction zipper, boolean delayError, int bufferSize) { - return zip(this, other, zipper, delayError, bufferSize); + @NonNull BiFunction zipper, + @NonNull StandardBufferedConfig config + ) { + return zip(this, other, zipper, config); } // ------------------------------------------------------------------------- diff --git a/src/main/java/io/reactivex/rxjava4/core/Maybe.java b/src/main/java/io/reactivex/rxjava4/core/Maybe.java index 646b6d24c60..ae2cbb58516 100644 --- a/src/main/java/io/reactivex/rxjava4/core/Maybe.java +++ b/src/main/java/io/reactivex/rxjava4/core/Maybe.java @@ -234,7 +234,6 @@ public abstract class Maybe<@NonNull T> implements MaybeSource { * @param sources the {@code Publisher} of {@code MaybeSource} instances * @param config the configuration record for this operator * @throws NullPointerException if {@code sources} or {@code config} is {@code null} - * @throws IllegalArgumentException if {@code prefetch} is non-positive * @return the new {@code Flowable} instance * @since 4.0.0 */ @@ -521,7 +520,6 @@ public abstract class Maybe<@NonNull T> implements MaybeSource { * @param config the configuration record for this operator * @return the new {@code Flowable} instance with the specified concatenation behavior * @throws NullPointerException if {@code sources} or {@code config} is {@code null} - * @throws IllegalArgumentException if {@code maxConcurrency} is non-positive * @since 4.0.0 */ @SuppressWarnings({ "rawtypes", "unchecked" }) @@ -1135,7 +1133,6 @@ public abstract class Maybe<@NonNull T> implements MaybeSource { * @param config the configuration record for this operator * @return the new {@code Flowable} instance * @throws NullPointerException if {@code sources} or {@code config} is {@code null} - * @throws IllegalArgumentException if {@code maxConcurrency} is non-positive * @since 4.0.0 */ @BackpressureSupport(BackpressureKind.FULL) @@ -2686,32 +2683,6 @@ public final Maybe delay(long time, @NonNull TimeUnit unit) { return delay(time, unit, Schedulers.computation(), false); } - /** - * Returns a {@code Maybe} that signals the events emitted by the current {@code Maybe} shifted forward in time by a - * specified delay. - *

- * - *

- *
Scheduler:
- *
This version of {@code delay} operates by default on the {@code computation} {@link Scheduler}.
- *
- * - * @param time the delay to shift the source by - * @param unit the {@link TimeUnit} in which {@code time} is defined - * @param delayError if {@code true}, both success and error signals are delayed. if {@code false}, only success signals are delayed. - * @return the new {@code Maybe} instance - * @throws NullPointerException if {@code unit} is {@code null} - * @see ReactiveX operators documentation: Delay - * @see #delay(long, TimeUnit, Scheduler, boolean) - * @since 3.0.0 - */ - @CheckReturnValue - @SchedulerSupport(SchedulerSupport.COMPUTATION) - @NonNull - public final Maybe delay(long time, @NonNull TimeUnit unit, boolean delayError) { - return delay(time, unit, Schedulers.computation(), delayError); - } - /** * Returns a {@code Maybe} that signals the events emitted by the current {@code Maybe} shifted forward in time by a * specified delay. diff --git a/src/main/java/io/reactivex/rxjava4/core/Observable.java b/src/main/java/io/reactivex/rxjava4/core/Observable.java index 72c7637d55a..fe6234bedd7 100644 --- a/src/main/java/io/reactivex/rxjava4/core/Observable.java +++ b/src/main/java/io/reactivex/rxjava4/core/Observable.java @@ -1077,14 +1077,13 @@ public static int bufferSize() { * @throws NullPointerException if {@code sources} or {@code config} is {@code null} * @since 4.0.0 */ - @SuppressWarnings({ "rawtypes", "unchecked" }) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull @SafeVarargs public static <@NonNull T> Observable concatArrayEager(@NonNull StandardConcurrentBufferedConfig config, @NonNull ObservableSource... sources) { Objects.requireNonNull(config, "config is null"); - return fromArray(sources).concatMapEager((Function)Functions.identity(), config); + return fromArray(sources).concatMapEager(Functions.identity(), config); } /** @@ -1132,14 +1131,13 @@ public static int bufferSize() { * @throws NullPointerException if {@code sources} or {@code config} is {@code null} * @since 4.0.0 */ - @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull public static <@NonNull T> Observable concatEager(@NonNull Iterable<@NonNull ? extends ObservableSource> sources, @NonNull StandardConcurrentBufferedConfig config) { Objects.requireNonNull(config, "config is null"); - return fromIterable(sources).concatMapEager((Function)Functions.identity(), config); + return fromIterable(sources).concatMapEager(Functions.identity(), config); } /** @@ -2559,12 +2557,11 @@ public static Observable intervalRange(long start, long count, long initia * @throws NullPointerException if {@code sources} is {@code null} * @see ReactiveX operators documentation: Merge */ - @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull public static <@NonNull T> Observable merge(@NonNull Iterable<@NonNull ? extends ObservableSource> sources) { - return fromIterable(sources).flatMap((Function)Functions.identity()); + return fromIterable(sources).flatMap(Functions.identity()); } /** @@ -2601,14 +2598,13 @@ public static Observable intervalRange(long start, long count, long initia * @see ReactiveX operators documentation: Merge * @since 4.0.0 */ - @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull public static <@NonNull T> Observable merge(@NonNull Iterable<@NonNull ? extends ObservableSource> sources, @NonNull StandardConcurrentBufferedConfig config) { Objects.requireNonNull(config, "config is null"); - return fromIterable(sources).flatMap((Function)Functions.identity(), config); + return fromIterable(sources).flatMap(Functions.identity(), config); } /** @@ -2727,13 +2723,12 @@ public static Observable intervalRange(long start, long count, long initia * @throws NullPointerException if {@code sources} is {@code null} * @see ReactiveX operators documentation: Merge */ - @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull @SafeVarargs public static <@NonNull T> Observable mergeArray(@NonNull ObservableSource... sources) { - return fromArray(sources).flatMap((Function)Functions.identity(), StandardConcurrentBufferedConfig.DEFAULT); + return fromArray(sources).flatMap(Functions.identity(), StandardConcurrentBufferedConfig.DEFAULT); } /** @@ -2912,7 +2907,7 @@ public static Observable rangeLong(long start, long count) { @SchedulerSupport(SchedulerSupport.NONE) @NonNull public static <@NonNull T> Single sequenceEqual(@NonNull ObservableSource source1, @NonNull ObservableSource source2) { - return sequenceEqual(source1, source2, ObservableSequenceEqualConfig.DEFAULT); + return sequenceEqual(source1, source2, SequenceEqualConfig.DEFAULT); } /** @@ -2944,7 +2939,7 @@ public static Observable rangeLong(long start, long count) { @NonNull public static <@NonNull T> Single sequenceEqual( @NonNull ObservableSource source1, @NonNull ObservableSource source2, - @NonNull ObservableSequenceEqualConfig config) { + @NonNull SequenceEqualConfig config) { Objects.requireNonNull(source1, "source1 is null"); Objects.requireNonNull(source2, "source2 is null"); Objects.requireNonNull(config, "config is null"); @@ -3254,7 +3249,7 @@ public static Observable timer(long delay, @NonNull TimeUnit unit, @NonNul @NonNull public static <@NonNull T, @NonNull R> Observable zip(@NonNull Iterable<@NonNull ? extends ObservableSource> sources, @NonNull Function zipper) { - return zip(sources, StandardBufferedConfig.DEFAULT, zipper); + return zip(sources, zipper, StandardBufferedConfig.DEFAULT); } /** @@ -3311,8 +3306,8 @@ public static Observable timer(long delay, @NonNull TimeUnit unit, @NonNul @SchedulerSupport(SchedulerSupport.NONE) @NonNull public static <@NonNull T, @NonNull R> Observable zip(@NonNull Iterable<@NonNull ? extends ObservableSource> sources, - @NonNull StandardBufferedConfig config, - @NonNull Function zipper + @NonNull Function zipper, + @NonNull StandardBufferedConfig config ) { Objects.requireNonNull(zipper, "zipper is null"); Objects.requireNonNull(sources, "sources is null"); @@ -3435,9 +3430,9 @@ public static Observable timer(long delay, @NonNull TimeUnit unit, @NonNul Objects.requireNonNull(source2, "source2 is null"); Objects.requireNonNull(zipper, "zipper is null"); Objects.requireNonNull(config, "config is null"); - return zipArray(new Observable[] { - (Observable) source1, (Observable) source2 }, - config, Functions.toFunction(zipper)); + return zipArray(new ObservableSource[] { + source1, source2 }, + Functions.toFunction(zipper), config); } /** @@ -3500,9 +3495,9 @@ public static Observable timer(long delay, @NonNull TimeUnit unit, @NonNul Objects.requireNonNull(source2, "source2 is null"); Objects.requireNonNull(source3, "source3 is null"); Objects.requireNonNull(zipper, "zipper is null"); - return zipArray(new Observable[] { - (Observable) source1, (Observable) source2, (Observable) source3 }, - StandardBufferedConfig.DEFAULT, Functions.toFunction(zipper)); + return zipArray(new ObservableSource[] { + source1, source2, source3 }, + Functions.toFunction(zipper), StandardBufferedConfig.DEFAULT); } /** @@ -3570,11 +3565,11 @@ public static Observable timer(long delay, @NonNull TimeUnit unit, @NonNul Objects.requireNonNull(source3, "source3 is null"); Objects.requireNonNull(source4, "source4 is null"); Objects.requireNonNull(zipper, "zipper is null"); - return zipArray(new Observable[] { - (Observable) source1, (Observable) source2, (Observable) source3, - (Observable) source4 + return zipArray(new ObservableSource[] { + source1, source2, source3, + source4 }, - StandardBufferedConfig.DEFAULT, Functions.toFunction(zipper)); + Functions.toFunction(zipper), StandardBufferedConfig.DEFAULT); } /** @@ -3646,11 +3641,11 @@ public static Observable timer(long delay, @NonNull TimeUnit unit, @NonNul Objects.requireNonNull(source4, "source4 is null"); Objects.requireNonNull(source5, "source5 is null"); Objects.requireNonNull(zipper, "zipper is null"); - return zipArray(new Observable[] { - (Observable) source1, (Observable) source2, (Observable) source3, - (Observable) source4, (Observable) source5 + return zipArray(new ObservableSource[] { + source1, source2, source3, + source4, source5 }, - StandardBufferedConfig.DEFAULT, Functions.toFunction(zipper)); + Functions.toFunction(zipper), StandardBufferedConfig.DEFAULT); } /** @@ -3725,11 +3720,11 @@ public static Observable timer(long delay, @NonNull TimeUnit unit, @NonNul Objects.requireNonNull(source5, "source5 is null"); Objects.requireNonNull(source6, "source6 is null"); Objects.requireNonNull(zipper, "zipper is null"); - return zipArray(new Observable[] { - (Observable) source1, (Observable) source2, (Observable) source3, - (Observable) source4, (Observable) source5, (Observable) source6 + return zipArray(new ObservableSource[] { + source1, source2, source3, + source4, source5, source6 }, - StandardBufferedConfig.DEFAULT, Functions.toFunction(zipper)); + Functions.toFunction(zipper), StandardBufferedConfig.DEFAULT); } /** @@ -3810,12 +3805,12 @@ public static Observable timer(long delay, @NonNull TimeUnit unit, @NonNul Objects.requireNonNull(source6, "source6 is null"); Objects.requireNonNull(source7, "source7 is null"); Objects.requireNonNull(zipper, "zipper is null"); - return zipArray(new Observable[] { - (Observable) source1, (Observable) source2, (Observable) source3, - (Observable) source4, (Observable) source5, (Observable) source6, - (Observable) source7 + return zipArray(new ObservableSource[] { + source1, source2, source3, + source4, source5, source6, + source7 }, - StandardBufferedConfig.DEFAULT, Functions.toFunction(zipper)); + Functions.toFunction(zipper), StandardBufferedConfig.DEFAULT); } /** @@ -3900,12 +3895,12 @@ public static Observable timer(long delay, @NonNull TimeUnit unit, @NonNul Objects.requireNonNull(source7, "source7 is null"); Objects.requireNonNull(source8, "source8 is null"); Objects.requireNonNull(zipper, "zipper is null"); - return zipArray(new Observable[] { - (Observable) source1, (Observable) source2, (Observable) source3, - (Observable) source4, (Observable) source5, (Observable) source6, - (Observable) source7, (Observable) source8 + return zipArray(new ObservableSource[] { + source1, source2, source3, + source4, source5, source6, + source7, source8 }, - StandardBufferedConfig.DEFAULT, Functions.toFunction(zipper)); + Functions.toFunction(zipper), StandardBufferedConfig.DEFAULT); } /** @@ -3994,12 +3989,12 @@ public static Observable timer(long delay, @NonNull TimeUnit unit, @NonNul Objects.requireNonNull(source8, "source8 is null"); Objects.requireNonNull(source9, "source9 is null"); Objects.requireNonNull(zipper, "zipper is null"); - return zipArray(new Observable[] { - (Observable) source1, (Observable) source2, (Observable) source3, - (Observable) source4, (Observable) source5, (Observable) source6, - (Observable) source7, (Observable) source8, (Observable) source9 + return zipArray(new ObservableSource[] { + source1, source2, source3, + source4, source5, source6, + source7, source8, source9 }, - StandardBufferedConfig.DEFAULT, Functions.toFunction(zipper)); + Functions.toFunction(zipper), StandardBufferedConfig.DEFAULT); } /** @@ -4050,14 +4045,15 @@ public static Observable timer(long delay, @NonNull TimeUnit unit, @NonNul * @return the new {@code Observable} instance * @throws NullPointerException if {@code sources} or {@code zipper} or {@code config} is {@code null} * @see ReactiveX operators documentation: Zip + * @since 4.0.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull public static <@NonNull T, @NonNull R> Observable zipArray( @NonNull ObservableSource[] sources, - @NonNull StandardBufferedConfig config, - @NonNull Function zipper + @NonNull Function zipper, + @NonNull StandardBufferedConfig config ) { Objects.requireNonNull(sources, "sources is null"); if (sources.length == 0) { @@ -6187,7 +6183,6 @@ public final Observable debounce(long timeout, @NonNull TimeUnit unit, @NonNu @CheckReturnValue @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - @Experimental public final Observable debounce(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, @NonNull Consumer onDropped) { Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); @@ -6267,7 +6262,6 @@ public final Observable defaultIfEmpty(@NonNull T defaultItem) { * @return the new {@code Observable} instance * @throws NullPointerException if {@code unit} is {@code null} * @see ReactiveX operators documentation: Delay - * @see #delay(long, TimeUnit, boolean) * @see #delay(long, TimeUnit, Scheduler) */ @CheckReturnValue @@ -6277,35 +6271,6 @@ public final Observable delay(long time, @NonNull TimeUnit unit) { return delay(time, unit, Schedulers.computation(), false); } - /** - * Returns an {@code Observable} that emits the items emitted by the current {@code Observable} shifted forward in time by a - * specified delay. If {@code delayError} is {@code true}, error notifications will also be delayed. - *

- * - *

- *
Scheduler:
- *
This version of {@code delay} operates by default on the {@code computation} {@link Scheduler}.
- *
- * - * @param time - * the delay to shift the source by - * @param unit - * the {@link TimeUnit} in which {@code period} is defined - * @param delayError - * if {@code true}, the upstream exception is signaled with the given delay, after all preceding normal elements, - * if {@code false}, the upstream exception is signaled immediately - * @return the new {@code Observable} instance - * @throws NullPointerException if {@code unit} is {@code null} - * @see ReactiveX operators documentation: Delay - * @see #delay(long, TimeUnit, Scheduler, boolean) - */ - @CheckReturnValue - @SchedulerSupport(SchedulerSupport.COMPUTATION) - @NonNull - public final Observable delay(long time, @NonNull TimeUnit unit, boolean delayError) { - return delay(time, unit, Schedulers.computation(), delayError); - } - /** * Returns an {@code Observable} that emits the items emitted by the current {@code Observable} shifted forward in time by a * specified delay. An error notification from the current {@code Observable} is not delayed. @@ -7489,7 +7454,7 @@ public final Single firstOrError() { * @return the new {@code Observable} instance * @throws NullPointerException if {@code mapper} or {@code combiner} or {@code config} is {@code null} * @see ReactiveX operators documentation: FlatMap - * @since 2.0 + * @since 4.0.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @@ -7856,12 +7821,11 @@ public final Disposable forEachWhile(@NonNull Predicate onNext, @NonN * @throws NullPointerException if {@code keySelector} is {@code null} * @see ReactiveX operators documentation: GroupBy */ - @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull public final <@NonNull K> Observable> groupBy(@NonNull Function keySelector) { - return groupBy(keySelector, (Function)Functions.identity(), StandardBufferedConfig.DEFAULT); + return groupBy(keySelector, Functions.identity(), StandardBufferedConfig.DEFAULT); } /** @@ -7901,13 +7865,12 @@ public final Disposable forEachWhile(@NonNull Predicate onNext, @NonN * @see ReactiveX operators documentation: GroupBy * @since 4.0.0 */ - @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue @SchedulerSupport(SchedulerSupport.NONE) @NonNull public final <@NonNull K> Observable> groupBy(@NonNull Function keySelector, @NonNull StandardBufferedConfig config) { - return groupBy(keySelector, (Function)Functions.identity(), config); + return groupBy(keySelector, Functions.identity(), config); } /** @@ -8597,6 +8560,7 @@ public final Observable observeOn(@NonNull Scheduler scheduler) { * @see #subscribeOn * @see #observeOn(Scheduler) * @see #delay(long, TimeUnit, Scheduler, boolean) + * @since 4.0.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.CUSTOM) @@ -10066,38 +10030,6 @@ public final Observable sample(long period, @NonNull TimeUnit unit) { return sample(period, unit, Schedulers.computation()); } - /** - * Returns an {@code Observable} that emits the most recently emitted item (if any) emitted by the current {@code Observable} - * within periodic time intervals and optionally emit the very last upstream item when the upstream completes. - *

- * - *

- *
Scheduler:
- *
{@code sample} operates by default on the {@code computation} {@link Scheduler}.
- *
- * - *

History: 2.0.5 - experimental - * @param period - * the sampling rate - * @param unit - * the {@link TimeUnit} in which {@code period} is defined - * @param emitLast - * if {@code true} and the upstream completes while there is still an unsampled item available, - * that item is emitted to downstream before completion - * if {@code false}, an unsampled last item is ignored. - * @return the new {@code Observable} instance - * @throws NullPointerException if {@code unit} is {@code null} - * @see ReactiveX operators documentation: Sample - * @see #throttleLast(long, TimeUnit) - * @since 2.1 - */ - @CheckReturnValue - @SchedulerSupport(SchedulerSupport.COMPUTATION) - @NonNull - public final Observable sample(long period, @NonNull TimeUnit unit, boolean emitLast) { - return sample(period, unit, Schedulers.computation(), emitLast); - } - /** * Returns an {@code Observable} that emits the most recently emitted item (if any) emitted by the current {@code Observable} * within periodic time intervals, where the intervals are defined on a particular {@link Scheduler}. @@ -10128,43 +10060,6 @@ public final Observable sample(long period, @NonNull TimeUnit unit, @NonNull return RxJavaPlugins.onAssembly(new ObservableSampleTimed<>(this, period, unit, scheduler, false, null)); } - /** - * Returns an {@code Observable} that emits the most recently emitted item (if any) emitted by the current {@code Observable} - * within periodic time intervals, where the intervals are defined on a particular {@link Scheduler} - * and optionally emit the very last upstream item when the upstream completes. - *

- * - *

- *
Scheduler:
- *
You specify which {@code Scheduler} this operator will use.
- *
- * - *

History: 2.0.5 - experimental - * @param period - * the sampling rate - * @param unit - * the {@link TimeUnit} in which {@code period} is defined - * @param scheduler - * the {@code Scheduler} to use when sampling - * @param emitLast - * if {@code true} and the upstream completes while there is still an unsampled item available, - * that item is emitted to downstream before completion - * if {@code false}, an unsampled last item is ignored. - * @return the new {@code Observable} instance - * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} - * @see ReactiveX operators documentation: Sample - * @see #throttleLast(long, TimeUnit, Scheduler) - * @since 2.1 - */ - @CheckReturnValue - @SchedulerSupport(SchedulerSupport.CUSTOM) - @NonNull - public final Observable sample(long period, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean emitLast) { - Objects.requireNonNull(unit, "unit is null"); - Objects.requireNonNull(scheduler, "scheduler is null"); - return RxJavaPlugins.onAssembly(new ObservableSampleTimed<>(this, period, unit, scheduler, emitLast, null)); - } - /** * Returns an {@code Observable} that emits the most recently emitted item (if any) emitted by the current {@code Observable} * within periodic time intervals, where the intervals are defined on a particular {@link Scheduler}. @@ -10181,27 +10076,23 @@ public final Observable sample(long period, @NonNull TimeUnit unit, @NonNull * the {@link TimeUnit} in which {@code period} is defined * @param scheduler * the {@code Scheduler} to use when sampling - * @param emitLast - * if {@code true} and the upstream completes while there is still an unsampled item available, - * that item is emitted to downstream before completion - * if {@code false}, an unsampled last item is ignored. - * @param onDropped - * called with the current entry when it has been replaced by a new one + * @param config + * the configuration record for the operator * @return the new {@code Observable} instance - * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} or {@code onDropped} is {@code null} + * @throws NullPointerException if {@code unit} or {@code scheduler} or {@code config} is {@code null} * @see ReactiveX operators documentation: Sample * @see #throttleLast(long, TimeUnit, Scheduler) - * @since 3.1.6 - Experimental + * @since 4.0.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - @Experimental - public final Observable sample(long period, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean emitLast, @NonNull Consumer onDropped) { + public final Observable sample(long period, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, + @NonNull SampleConfig config) { Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); - Objects.requireNonNull(onDropped, "onDropped is null"); - return RxJavaPlugins.onAssembly(new ObservableSampleTimed<>(this, period, unit, scheduler, emitLast, onDropped)); + Objects.requireNonNull(config, "config is null"); + return RxJavaPlugins.onAssembly(new ObservableSampleTimed<>(this, period, unit, scheduler, config.emitLast(), config.onDropped())); } /** @@ -10635,38 +10526,7 @@ public final Observable skipLast(int count) { @SchedulerSupport(SchedulerSupport.TRAMPOLINE) @NonNull public final Observable skipLast(long time, @NonNull TimeUnit unit) { - return skipLast(time, unit, Schedulers.trampoline(), false, bufferSize()); - } - - /** - * Returns an {@code Observable} that drops items emitted by the current {@code Observable} during a specified time window - * before the source completes. - *

- * - *

- * Note: this action will cache the latest items arriving in the specified time window. - *

- *
Scheduler:
- *
{@code skipLast} does not operate on any particular scheduler but uses the current time - * from the {@code computation} {@link Scheduler}.
- *
- * - * @param time - * the length of the time window - * @param unit - * the time unit of {@code time} - * @param delayError - * if {@code true}, an exception signaled by the current {@code Observable} is delayed until the regular elements are consumed - * by the downstream; if {@code false}, an exception is immediately signaled and all regular elements dropped - * @return the new {@code Observable} instance - * @throws NullPointerException if {@code unit} is {@code null} - * @see ReactiveX operators documentation: SkipLast - */ - @CheckReturnValue - @SchedulerSupport(SchedulerSupport.TRAMPOLINE) - @NonNull - public final Observable skipLast(long time, @NonNull TimeUnit unit, boolean delayError) { - return skipLast(time, unit, Schedulers.trampoline(), delayError, bufferSize()); + return skipLast(time, unit, Schedulers.trampoline(), StandardBufferedConfig.DEFAULT); } /** @@ -10695,39 +10555,7 @@ public final Observable skipLast(long time, @NonNull TimeUnit unit, boolean d @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull public final Observable skipLast(long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { - return skipLast(time, unit, scheduler, false, bufferSize()); - } - - /** - * Returns an {@code Observable} that drops items emitted by the current {@code Observable} during a specified time window - * (defined on a specified scheduler) before the source completes. - *

- * - *

- * Note: this action will cache the latest items arriving in the specified time window. - *

- *
Scheduler:
- *
You specify which {@link Scheduler} this operator will use to track the current time
- *
- * - * @param time - * the length of the time window - * @param unit - * the time unit of {@code time} - * @param scheduler - * the scheduler used as the time source - * @param delayError - * if {@code true}, an exception signaled by the current {@code Observable} is delayed until the regular elements are consumed - * by the downstream; if {@code false}, an exception is immediately signaled and all regular elements dropped - * @return the new {@code Observable} instance - * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} - * @see ReactiveX operators documentation: SkipLast - */ - @CheckReturnValue - @SchedulerSupport(SchedulerSupport.CUSTOM) - @NonNull - public final Observable skipLast(long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean delayError) { - return skipLast(time, unit, scheduler, delayError, bufferSize()); + return skipLast(time, unit, scheduler, StandardBufferedConfig.DEFAULT); } /** @@ -10748,26 +10576,24 @@ public final Observable skipLast(long time, @NonNull TimeUnit unit, @NonNull * the time unit of {@code time} * @param scheduler * the scheduler used as the time source - * @param delayError - * if {@code true}, an exception signaled by the current {@code Observable} is delayed until the regular elements are consumed - * by the downstream; if {@code false}, an exception is immediately signaled and all regular elements dropped - * @param bufferSize - * the hint about how many elements to expect to be skipped + * @param config + * the configuration record for this operator * @return the new {@code Observable} instance - * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} - * @throws IllegalArgumentException if {@code bufferSize} is non-positive + * @throws NullPointerException if {@code unit} or {@code scheduler} or {@code config} is {@code null} * @see ReactiveX operators documentation: SkipLast + * @since 4.0.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - public final Observable skipLast(long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean delayError, int bufferSize) { + public final Observable skipLast(long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, + @NonNull StandardBufferedConfig config) { Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); - ObjectHelper.verifyPositive(bufferSize, "bufferSize"); + Objects.requireNonNull(config, "config is null"); // the internal buffer holds pairs of (timestamp, value) so double the default buffer size - int s = bufferSize << 1; - return RxJavaPlugins.onAssembly(new ObservableSkipLastTimed<>(this, time, unit, scheduler, s, delayError)); + int s = config.bufferSize() << 1; + return RxJavaPlugins.onAssembly(new ObservableSkipLastTimed<>(this, time, unit, scheduler, s, config.delayErrors())); } /** @@ -11760,7 +11586,7 @@ public final Observable takeLast(int count) { @SchedulerSupport(SchedulerSupport.TRAMPOLINE) @NonNull public final Observable takeLast(long count, long time, @NonNull TimeUnit unit) { - return takeLast(count, time, unit, Schedulers.trampoline(), false, bufferSize()); + return takeLast(count, time, unit, Schedulers.trampoline()); } /** @@ -11792,7 +11618,7 @@ public final Observable takeLast(long count, long time, @NonNull TimeUnit uni @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull public final Observable takeLast(long count, long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { - return takeLast(count, time, unit, scheduler, false, bufferSize()); + return takeLast(count, time, unit, scheduler, StandardBufferedConfig.DEFAULT); } /** @@ -11814,28 +11640,27 @@ public final Observable takeLast(long count, long time, @NonNull TimeUnit uni * the time unit of {@code time} * @param scheduler * the {@code Scheduler} that provides the timestamps for the observed items - * @param delayError - * if {@code true}, an exception signaled by the current {@code Observable} is delayed until the regular elements are consumed - * by the downstream; if {@code false}, an exception is immediately signaled and all regular elements dropped - * @param bufferSize - * the hint about how many elements to expect to be last + * @param config + * the configuration record for this operator * @return the new {@code Observable} instance - * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} + * @throws NullPointerException if {@code unit} or {@code scheduler} or {@code config} is {@code null} * @throws IllegalArgumentException - * if {@code count} is negative or {@code bufferSize} is non-positive + * if {@code count} is negative * @see ReactiveX operators documentation: TakeLast + * @since 4.0.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - public final Observable takeLast(long count, long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean delayError, int bufferSize) { + public final Observable takeLast(long count, long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, + @NonNull StandardBufferedConfig config) { Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); - ObjectHelper.verifyPositive(bufferSize, "bufferSize"); + Objects.requireNonNull(config, "config is null"); if (count < 0) { throw new IllegalArgumentException("count >= 0 required but it was " + count); } - return RxJavaPlugins.onAssembly(new ObservableTakeLastTimed<>(this, count, time, unit, scheduler, bufferSize, delayError)); + return RxJavaPlugins.onAssembly(new ObservableTakeLastTimed<>(this, count, time, unit, scheduler, config.bufferSize(), config.delayErrors())); } /** @@ -11861,37 +11686,7 @@ public final Observable takeLast(long count, long time, @NonNull TimeUnit uni @SchedulerSupport(SchedulerSupport.TRAMPOLINE) @NonNull public final Observable takeLast(long time, @NonNull TimeUnit unit) { - return takeLast(time, unit, Schedulers.trampoline(), false, bufferSize()); - } - - /** - * Returns an {@code Observable} that emits the items from the current {@code Observable} that were emitted in a specified - * window of time before the current {@code Observable} completed. - *

- * - *

- *
Scheduler:
- *
{@code takeLast} does not operate on any particular scheduler but uses the current time - * from the {@code trampoline} {@link Scheduler}.
- *
- * - * @param time - * the length of the time window - * @param unit - * the time unit of {@code time} - * @param delayError - * if {@code true}, an exception signaled by the current {@code Observable} is delayed until the regular elements are consumed - * by the downstream; if {@code false}, an exception is immediately signaled and all regular elements dropped - * @return the new {@code Observable} instance - * @throws NullPointerException if {@code unit} is {@code null} - * @throws IllegalArgumentException if {@code count} is non-positive - * @see ReactiveX operators documentation: TakeLast - */ - @CheckReturnValue - @SchedulerSupport(SchedulerSupport.TRAMPOLINE) - @NonNull - public final Observable takeLast(long time, @NonNull TimeUnit unit, boolean delayError) { - return takeLast(time, unit, Schedulers.trampoline(), delayError, bufferSize()); + return takeLast(time, unit, Schedulers.trampoline()); } /** @@ -11919,7 +11714,7 @@ public final Observable takeLast(long time, @NonNull TimeUnit unit, boolean d @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull public final Observable takeLast(long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { - return takeLast(time, unit, scheduler, false, bufferSize()); + return takeLast(time, unit, scheduler, StandardBufferedConfig.DEFAULT); } /** @@ -11939,52 +11734,19 @@ public final Observable takeLast(long time, @NonNull TimeUnit unit, @NonNull * the time unit of {@code time} * @param scheduler * the {@code Scheduler} that provides the timestamps for the observed items - * @param delayError - * if {@code true}, an exception signaled by the current {@code Observable} is delayed until the regular elements are consumed - * by the downstream; if {@code false}, an exception is immediately signaled and all regular elements dropped - * @return the new {@code Observable} instance - * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} - * @see ReactiveX operators documentation: TakeLast - */ - @CheckReturnValue - @SchedulerSupport(SchedulerSupport.CUSTOM) - @NonNull - public final Observable takeLast(long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean delayError) { - return takeLast(time, unit, scheduler, delayError, bufferSize()); - } - - /** - * Returns an {@code Observable} that emits the items from the current {@code Observable} that were emitted in a specified - * window of time before the current {@code Observable} completed, where the timing information is provided by a specified - * {@link Scheduler}. - *

- * - *

- *
Scheduler:
- *
You specify which {@code Scheduler} this operator will use.
- *
- * - * @param time - * the length of the time window - * @param unit - * the time unit of {@code time} - * @param scheduler - * the {@code Scheduler} that provides the timestamps for the observed items - * @param delayError - * if {@code true}, an exception signaled by the current {@code Observable} is delayed until the regular elements are consumed - * by the downstream; if {@code false}, an exception is immediately signaled and all regular elements dropped - * @param bufferSize - * the hint about how many elements to expect to be last + * @param config + * the configuration record for this operator * @return the new {@code Observable} instance * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} - * @throws IllegalArgumentException if {@code bufferSize} is non-positive * @see ReactiveX operators documentation: TakeLast + * @since 4.0.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - public final Observable takeLast(long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean delayError, int bufferSize) { - return takeLast(Long.MAX_VALUE, time, unit, scheduler, delayError, bufferSize); + public final Observable takeLast(long time, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, + @NonNull StandardBufferedConfig config) { + return takeLast(Long.MAX_VALUE, time, unit, scheduler, config); } /** @@ -12161,7 +11923,6 @@ public final Observable throttleFirst(long skipDuration, @NonNull TimeUnit un @CheckReturnValue @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - @Experimental public final Observable throttleFirst(long skipDuration, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, @NonNull Consumer onDropped) { Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); @@ -12231,9 +11992,8 @@ public final Observable throttleLast(long intervalDuration, @NonNull TimeUnit @CheckReturnValue @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - @Experimental public final Observable throttleLast(long intervalDuration, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, @NonNull Consumer onDropped) { - return sample(intervalDuration, unit, scheduler, false, onDropped); + return sample(intervalDuration, unit, scheduler, new SampleConfig<>(false, onDropped)); } /** @@ -12276,7 +12036,7 @@ public final Observable throttleLast(long intervalDuration, @NonNull TimeUnit *

* *

- * Unlike the option with {@link #throttleLatest(long, TimeUnit, boolean)}, the very last item being held back + * Unlike the option with {@link #throttleLatest(long, TimeUnit, Scheduler, SampleConfig)}, the very last item being held back * (if any) is not emitted when the upstream completes. *

* If no items were emitted from the upstream during this timeout phase, the next @@ -12291,7 +12051,6 @@ public final Observable throttleLast(long intervalDuration, @NonNull TimeUnit * @param unit the time unit * @return the new {@code Observable} instance * @throws NullPointerException if {@code unit} is {@code null} - * @see #throttleLatest(long, TimeUnit, boolean) * @see #throttleLatest(long, TimeUnit, Scheduler) * @since 2.2 */ @@ -12299,40 +12058,7 @@ public final Observable throttleLast(long intervalDuration, @NonNull TimeUnit @SchedulerSupport(SchedulerSupport.COMPUTATION) @NonNull public final Observable throttleLatest(long timeout, @NonNull TimeUnit unit) { - return throttleLatest(timeout, unit, Schedulers.computation(), false); - } - - /** - * Throttles items from the current {@code Observable} by first emitting the next - * item from upstream, then periodically emitting the latest item (if any) when - * the specified timeout elapses between them. - *

- * - *

- * If no items were emitted from the upstream during this timeout phase, the next - * upstream item is emitted immediately and the timeout window starts from then. - *

- *
Scheduler:
- *
{@code throttleLatest} operates by default on the {@code computation} {@link Scheduler}.
- *
- *

History: 2.1.14 - experimental - * @param timeout the time to wait after an item emission towards the downstream - * before trying to emit the latest item from upstream again - * @param unit the time unit - * @param emitLast If {@code true}, the very last item from the upstream will be emitted - * immediately when the upstream completes, regardless if there is - * a timeout window active or not. If {@code false}, the very last - * upstream item is ignored and the flow terminates. - * @return the new {@code Observable} instance - * @throws NullPointerException if {@code unit} is {@code null} - * @see #throttleLatest(long, TimeUnit, Scheduler, boolean) - * @since 2.2 - */ - @CheckReturnValue - @SchedulerSupport(SchedulerSupport.COMPUTATION) - @NonNull - public final Observable throttleLatest(long timeout, @NonNull TimeUnit unit, boolean emitLast) { - return throttleLatest(timeout, unit, Schedulers.computation(), emitLast); + return throttleLatest(timeout, unit, Schedulers.computation(), SampleConfig.DEFAULT); } /** @@ -12342,7 +12068,7 @@ public final Observable throttleLatest(long timeout, @NonNull TimeUnit unit, *

* *

- * Unlike the option with {@link #throttleLatest(long, TimeUnit, Scheduler, boolean)}, the very last item being held back + * Unlike the option with {@link #throttleLatest(long, TimeUnit, Scheduler, SampleConfig)}, the very last item being held back * (if any) is not emitted when the upstream completes. *

* If no items were emitted from the upstream during this timeout phase, the next @@ -12359,50 +12085,14 @@ public final Observable throttleLatest(long timeout, @NonNull TimeUnit unit, * emission will be performed * @return the new {@code Observable} instance * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} - * @see #throttleLatest(long, TimeUnit, Scheduler, boolean) + * @see #throttleLatest(long, TimeUnit, Scheduler, SampleConfig) * @since 2.2 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull public final Observable throttleLatest(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) { - return throttleLatest(timeout, unit, scheduler, false); - } - - /** - * Throttles items from the current {@code Observable} by first emitting the next - * item from upstream, then periodically emitting the latest item (if any) when - * the specified timeout elapses between them. - *

- * - *

- * If no items were emitted from the upstream during this timeout phase, the next - * upstream item is emitted immediately and the timeout window starts from then. - *

- *
Scheduler:
- *
You specify which {@link Scheduler} this operator will use.
- *
- *

History: 2.1.14 - experimental - * @param timeout the time to wait after an item emission towards the downstream - * before trying to emit the latest item from upstream again - * @param unit the time unit - * @param scheduler the {@code Scheduler} where the timed wait and latest item - * emission will be performed - * @param emitLast If {@code true}, the very last item from the upstream will be emitted - * immediately when the upstream completes, regardless if there is - * a timeout window active or not. If {@code false}, the very last - * upstream item is ignored and the flow terminates. - * @return the new {@code Observable} instance - * @throws NullPointerException if {@code unit} or {@code scheduler} is {@code null} - * @since 2.2 - */ - @CheckReturnValue - @SchedulerSupport(SchedulerSupport.CUSTOM) - @NonNull - public final Observable throttleLatest(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean emitLast) { - Objects.requireNonNull(unit, "unit is null"); - Objects.requireNonNull(scheduler, "scheduler is null"); - return RxJavaPlugins.onAssembly(new ObservableThrottleLatest<>(this, timeout, unit, scheduler, emitLast, null)); + return throttleLatest(timeout, unit, scheduler, SampleConfig.DEFAULT); } /** @@ -12431,26 +12121,21 @@ public final Observable throttleLatest(long timeout, @NonNull TimeUnit unit, * @param unit the time unit * @param scheduler the {@code Scheduler} where the timed wait and latest item * emission will be performed - * @param emitLast If {@code true}, the very last item from the upstream will be emitted - * immediately when the upstream completes, regardless if there is - * a timeout window active or not. If {@code false}, the very last - * upstream item is ignored and the flow terminates. - * @param onDropped called when an item is replaced by a newer item that doesn't get delivered - * to the downstream, including the very last item if {@code emitLast} is {@code false} - * and the current undelivered item when the sequence gets disposed. - * @return the new {@code Observable} instance - * @throws NullPointerException if {@code unit}, {@code scheduler} or {@code onDropped} is {@code null} - * @since 3.1.6 - Experimental + * @param config + * the configuration record for this operator + * @return the new {@code Observable} instance + * @throws NullPointerException if {@code unit}, {@code scheduler} or {@code config} is {@code null} + * @since 4.0.0 */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - @Experimental - public final Observable throttleLatest(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, boolean emitLast, @NonNull Consumer onDropped) { + public final Observable throttleLatest(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, + @NonNull SampleConfig config) { Objects.requireNonNull(unit, "unit is null"); Objects.requireNonNull(scheduler, "scheduler is null"); - Objects.requireNonNull(onDropped, "onDropped is null"); - return RxJavaPlugins.onAssembly(new ObservableThrottleLatest<>(this, timeout, unit, scheduler, emitLast, onDropped)); + Objects.requireNonNull(config, "config is null"); + return RxJavaPlugins.onAssembly(new ObservableThrottleLatest<>(this, timeout, unit, scheduler, config.emitLast(), config.onDropped())); } /** @@ -12554,7 +12239,6 @@ public final Observable throttleWithTimeout(long timeout, @NonNull TimeUnit u @CheckReturnValue @SchedulerSupport(SchedulerSupport.CUSTOM) @NonNull - @Experimental public final Observable throttleWithTimeout(long timeout, @NonNull TimeUnit unit, @NonNull Scheduler scheduler, @NonNull Consumer onDropped) { return debounce(timeout, unit, scheduler, onDropped); } diff --git a/src/main/java/io/reactivex/rxjava4/core/Single.java b/src/main/java/io/reactivex/rxjava4/core/Single.java index 5fc26538a38..554ed0a7e42 100644 --- a/src/main/java/io/reactivex/rxjava4/core/Single.java +++ b/src/main/java/io/reactivex/rxjava4/core/Single.java @@ -465,7 +465,7 @@ public abstract class Single<@NonNull T> implements SingleSource { * @param config the configuration record for this operator * @return the new {@link Flowable} instance with the specified concatenation behavior * @throws NullPointerException if {@code sources} or {@code config} is {@code null} - * @since 3.0.0 + * @since 4.0.0 */ @BackpressureSupport(BackpressureKind.FULL) @CheckReturnValue @@ -2233,7 +2233,7 @@ public final Flowable concatWith(@NonNull SingleSource other) { * @return the new {@code Single} instance * @since 2.0 * @throws NullPointerException if {@code unit} is {@code null} - * @see #delay(long, TimeUnit, boolean) + * @see #delay(long, TimeUnit, Scheduler) */ @CheckReturnValue @SchedulerSupport(SchedulerSupport.COMPUTATION) @@ -2242,29 +2242,6 @@ public final Single delay(long time, @NonNull TimeUnit unit) { return delay(time, unit, Schedulers.computation(), false); } - /** - * Delays the emission of the success or error signal from the current {@code Single} by the specified amount. - *

- * - *

- *
Scheduler:
- *
{@code delay} operates by default on the {@code computation} {@link Scheduler}.
- *
- *

History: 2.1.5 - experimental - * @param time the amount of time the success or error signal should be delayed for - * @param unit the time unit - * @param delayError if {@code true}, both success and error signals are delayed. if {@code false}, only success signals are delayed. - * @return the new {@code Single} instance - * @throws NullPointerException if {@code unit} is {@code null} - * @since 2.2 - */ - @CheckReturnValue - @SchedulerSupport(SchedulerSupport.COMPUTATION) - @NonNull - public final Single delay(long time, @NonNull TimeUnit unit, boolean delayError) { - return delay(time, unit, Schedulers.computation(), delayError); - } - /** * Delays the emission of the success signal from the current {@code Single} by the specified amount. * An error signal will not be delayed. diff --git a/src/main/java/io/reactivex/rxjava4/core/config/OnBackpressureBufferConfig.java b/src/main/java/io/reactivex/rxjava4/core/config/OnBackpressureBufferConfig.java new file mode 100644 index 00000000000..00f9a5fee88 --- /dev/null +++ b/src/main/java/io/reactivex/rxjava4/core/config/OnBackpressureBufferConfig.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava4.core.config; + +import java.util.Objects; + +import io.reactivex.rxjava4.annotations.NonNull; +import io.reactivex.rxjava4.core.Flowable; +import io.reactivex.rxjava4.functions.*; +import io.reactivex.rxjava4.internal.functions.*; + +/** + * Configuration record for onBackpressureBuffer() operators. + * @param the element type of the sequences being compared + * @param capacity + * number of slots available in the buffer. + * @param delayError + * if {@code true}, an exception from the current {@code Flowable} is delayed until all buffered elements have been + * consumed by the downstream; if {@code false}, an exception is immediately signaled to the downstream, skipping + * any buffered element + * @param unbounded + * if {@code true}, the capacity value is interpreted as the internal "island" size of the unbounded buffer + * @param onDropped + * the {@link Consumer} to be called with the item that could not be buffered due to capacity constraints. + * @since 4.0.0 + */ + +public record OnBackpressureBufferConfig( + int capacity, + boolean delayError, + boolean unbounded, + @NonNull Consumer onDropped) { + + /** + * The default settings with no error delay, unbounded, no onOverflow or onDropped activity. + */ + public static final OnBackpressureBufferConfig DEFAULT = new OnBackpressureBufferConfig<>(false, true); + + /** + * Creates a config with the given capacity, no error delay, bounded, no callbacks. + * @param capacity + * number of slots available in the buffer. + */ + public OnBackpressureBufferConfig(int capacity) { + this(capacity, false, false, Functions.emptyConsumer()); + } + + /** + * Creates a config with the given error delay mode, capacity of {@link Flowable#bufferSize()}, + * bounded, and no callback. + * @param delayError + * if {@code true}, an exception from the current {@code Flowable} is delayed until all buffered elements have been + * consumed by the downstream; if {@code false}, an exception is immediately signaled to the downstream, skipping + * any buffered element + */ + public OnBackpressureBufferConfig(boolean delayError) { + this(Flowable.bufferSize(), delayError, false, Functions.emptyConsumer()); + } + + /** + * Creates a config with the given capacity, given error delay mode, + * bounded, and no callback. + * @param capacity + * number of slots available in the buffer. + * @param delayError + * if {@code true}, an exception from the current {@code Flowable} is delayed until all buffered elements have been + * consumed by the downstream; if {@code false}, an exception is immediately signaled to the downstream, skipping + * any buffered element + */ + public OnBackpressureBufferConfig(int capacity, boolean delayError) { + this(capacity, delayError, false, Functions.emptyConsumer()); + } + + /** + * Creates a config with the given error delay mode, given boundedneess, + * capacity of {@link Flowable#bufferSize()} and no callback. + * @param delayError + * if {@code true}, an exception from the current {@code Flowable} is delayed until all buffered elements have been + * consumed by the downstream; if {@code false}, an exception is immediately signaled to the downstream, skipping + * any buffered element + * @param unbounded + * if {@code true}, the capacity value is interpreted as the internal "island" size of the unbounded buffer + */ + public OnBackpressureBufferConfig(boolean delayError, boolean unbounded) { + this(Flowable.bufferSize(), delayError, unbounded, Functions.emptyConsumer()); + } + + /** + * Creates a config with the given capacity, error delay mode and unboundedness, + * and no callback. + * @param capacity + * number of slots available in the buffer. + * @param delayError + * if {@code true}, an exception from the current {@code Flowable} is delayed until all buffered elements have been + * consumed by the downstream; if {@code false}, an exception is immediately signaled to the downstream, skipping + * any buffered element + * @param unbounded + * if {@code true}, the capacity value is interpreted as the internal "island" size of the unbounded buffer + */ + public OnBackpressureBufferConfig(int capacity, boolean delayError, boolean unbounded) { + this(capacity, delayError, unbounded, Functions.emptyConsumer()); + } + + /** + * Creates a config with the given onDropped callback, capacity of {@link Flowable#bufferSize()}, + * no error delay, bounded, and no callback. + * @param onDropped + * the {@link Consumer} to be called with the item that could not be buffered due to capacity constraints. + */ + public OnBackpressureBufferConfig(@NonNull Consumer onDropped) { + this(Flowable.bufferSize(), false, false, onDropped); + } + + /** + * Creates a config with the given capacity, given onDropped callback + * no error delay, bounded, and no callback. + * @param capacity + * number of slots available in the buffer. + * @param onDropped + * the {@link Consumer} to be called with the item that could not be buffered due to capacity constraints. + */ + public OnBackpressureBufferConfig(int capacity, @NonNull Consumer onDropped) { + this(capacity, false, false, onDropped); + } + + /** + * Creates a config with all the provided values. + * @param capacity + * number of slots available in the buffer. + * @param delayError + * if {@code true}, an exception from the current {@code Flowable} is delayed until all buffered elements have been + * consumed by the downstream; if {@code false}, an exception is immediately signaled to the downstream, skipping + * any buffered element + * @param unbounded + * if {@code true}, the capacity value is interpreted as the internal "island" size of the unbounded buffer + * @param onDropped + * the {@link Consumer} to be called with the item that could not be buffered due to capacity constraints. + */ + public OnBackpressureBufferConfig { + ObjectHelper.verifyPositive(capacity, "capacity"); + Objects.requireNonNull(onDropped, "onDropped is null"); + } +} diff --git a/src/main/java/io/reactivex/rxjava4/core/config/SampleConfig.java b/src/main/java/io/reactivex/rxjava4/core/config/SampleConfig.java new file mode 100644 index 00000000000..5863e3f8591 --- /dev/null +++ b/src/main/java/io/reactivex/rxjava4/core/config/SampleConfig.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava4.core.config; + +import java.util.Objects; + +import io.reactivex.rxjava4.annotations.NonNull; +import io.reactivex.rxjava4.functions.Consumer; +import io.reactivex.rxjava4.internal.functions.Functions; + +/** + * Configuration record for the timed sample() operator. + * @param the element type of the sequence being sampled + * @param emitLast + * if {@code true} and the upstream completes while there is still an unsampled item available, + * that item is emitted to downstream before completion + * if {@code false}, an unsampled last item is ignored. + * @param onDropped + * called with the current entry when it has been replaced by a new one + * @since 4.0.0 + */ +public record SampleConfig(boolean emitLast, @NonNull Consumer onDropped) { + + /** + * Default configuration with no emit last and an empty onDropped consumer. + */ + public static final SampleConfig DEFAULT = new SampleConfig<>(false, Functions.emptyConsumer()); + /** + * Default configuration with emit last setting and an empty onDropped consumer. + */ + public static final SampleConfig EMIT_LAST = new SampleConfig<>(true, Functions.emptyConsumer()); + + /** + * Creates a config with the given emit last option ad an empty onDropped callback. + * @param emitLast + * if {@code true} and the upstream completes while there is still an unsampled item available, + * that item is emitted to downstream before completion + * if {@code false}, an unsampled last item is ignored. + */ + public SampleConfig(boolean emitLast) { + this(emitLast, Functions.emptyConsumer()); + } + + /** + * Creates a config with the given onDropped callback and an no-emit last. + * @param onDropped + * called with the current entry when it has been replaced by a new one + */ + public SampleConfig(@NonNull Consumer onDropped) { + this(false, onDropped); + } + + /** + * Creates a config with the given parameters. + * @param emitLast + * if {@code true} and the upstream completes while there is still an unsampled item available, + * that item is emitted to downstream before completion + * if {@code false}, an unsampled last item is ignored. + * @param onDropped + * called with the current entry when it has been replaced by a new one + */ + public SampleConfig { + Objects.requireNonNull(onDropped, "onDropped is null"); + } +} diff --git a/src/main/java/io/reactivex/rxjava4/core/config/ObservableSequenceEqualConfig.java b/src/main/java/io/reactivex/rxjava4/core/config/SequenceEqualConfig.java similarity index 78% rename from src/main/java/io/reactivex/rxjava4/core/config/ObservableSequenceEqualConfig.java rename to src/main/java/io/reactivex/rxjava4/core/config/SequenceEqualConfig.java index 6e35d8fdd29..16027dcc4f1 100644 --- a/src/main/java/io/reactivex/rxjava4/core/config/ObservableSequenceEqualConfig.java +++ b/src/main/java/io/reactivex/rxjava4/core/config/SequenceEqualConfig.java @@ -15,30 +15,31 @@ import java.util.Objects; +import io.reactivex.rxjava4.annotations.NonNull; import io.reactivex.rxjava4.core.Observable; import io.reactivex.rxjava4.functions.BiPredicate; import io.reactivex.rxjava4.internal.functions.ObjectHelper; /** - * Configuration record for Observable.sequenceEqual() operators. + * Configuration record for sequenceEqual() operators. * @param the element type of the sequences being compared * @param bufferSize the expected number of items to cache from the inner {@code ObservableSource}s * @param isEqual the custom lambda to compare two elements * @since 4.0.0 */ -public record ObservableSequenceEqualConfig(int bufferSize, BiPredicate isEqual) { +public record SequenceEqualConfig(int bufferSize, @NonNull BiPredicate isEqual) { /** * The default configuration with bufferSize of Observable.bufferSize() and a default Objects.equals predicate. */ - public static final ObservableSequenceEqualConfig DEFAULT = - new ObservableSequenceEqualConfig<>(Observable.bufferSize(), ObjectHelper.equalsPredicate()); + public static final SequenceEqualConfig DEFAULT = + new SequenceEqualConfig<>(Observable.bufferSize(), ObjectHelper.equalsPredicate()); /** * Constructs a configuration record. * @param bufferSize the expected number of row combination items to be buffered internally */ - public ObservableSequenceEqualConfig(int bufferSize) { + public SequenceEqualConfig(int bufferSize) { this(bufferSize, ObjectHelper.equalsPredicate()); } @@ -46,7 +47,7 @@ public ObservableSequenceEqualConfig(int bufferSize) { * Constructs a configuration record. * @param isEqual the custom lambda to compare two elements */ - public ObservableSequenceEqualConfig(BiPredicate isEqual) { + public SequenceEqualConfig(@NonNull BiPredicate isEqual) { this(Observable.bufferSize(), isEqual); } @@ -55,7 +56,7 @@ public ObservableSequenceEqualConfig(BiPredicate isEqual) * @param bufferSize the expected number of items to cache from the inner {@code ObservableSource}s * @param isEqual the custom lambda to compare two elements */ - public ObservableSequenceEqualConfig { + public SequenceEqualConfig { ObjectHelper.verifyPositive(bufferSize, "bufferSize"); Objects.requireNonNull(isEqual, "isEqual is null"); } diff --git a/src/main/java/io/reactivex/rxjava4/core/config/StandardBufferedConfig.java b/src/main/java/io/reactivex/rxjava4/core/config/StandardBufferedConfig.java index ff621c76789..88d0a48511f 100644 --- a/src/main/java/io/reactivex/rxjava4/core/config/StandardBufferedConfig.java +++ b/src/main/java/io/reactivex/rxjava4/core/config/StandardBufferedConfig.java @@ -16,9 +16,8 @@ import java.util.Objects; import io.reactivex.rxjava4.annotations.NonNull; -import io.reactivex.rxjava4.core.Observable; +import io.reactivex.rxjava4.core.*; import io.reactivex.rxjava4.internal.functions.ObjectHelper; -import io.reactivex.rxjava4.core.ErrorMode; /** * Configuration record for operators which have three error handling modes and a buffer size or prefetch like parameter. @@ -59,15 +58,15 @@ public record StandardBufferedConfig(@NonNull ErrorMode errorMode, int bufferSiz public static final StandardBufferedConfig MIN_DELAY_ERRORS_BOUNDARY = new StandardBufferedConfig(ErrorMode.BOUNDARY, 2); /** - * Constructs a configuration record. + * Sets the error mode to the provided value and the bufferSize to {@link Flowable#bufferSize()} * @param errorMode how to handle when errors appear from the inner or outer sources */ public StandardBufferedConfig(@NonNull ErrorMode errorMode) { - this(errorMode, Observable.bufferSize()); + this(errorMode, Flowable.bufferSize()); } /** - * Constructs a configuration record with convenience for the basic no-delay/delay error management. + * Sets the error mode to IMMEDIATE (false) or END (true) and the bufferSize to {@link Flowable#bufferSize()}. * @param delayErrors if true, ErrorMode.END is used, ErrorMode.IMMEDIATE otherwise */ public StandardBufferedConfig(boolean delayErrors) { @@ -75,7 +74,7 @@ public StandardBufferedConfig(boolean delayErrors) { } /** - * Constructs a configuration record. + * Sets the error mode to IMMEDIATE and the bufferSize to the provided value. * @param bufferSize the expected number of outer sources to buffer while processing an inner source */ public StandardBufferedConfig(int bufferSize) { @@ -83,7 +82,7 @@ public StandardBufferedConfig(int bufferSize) { } /** - * Constructs a configuration record. + * Sets the error mode to IMMEDIATE (false) or END (true) and the bufferSize to the provided value. * @param delayErrors if true, ErrorMode.END is used, ErrorMode.IMMEDIATE otherwise * @param bufferSize the expected number of outer sources to buffer while processing an inner source */ @@ -92,7 +91,7 @@ public StandardBufferedConfig(boolean delayErrors, int bufferSize) { } /** - * Constructs a configuration record. + * Sets the error mode and the bufferSize to the provided values. * @param errorMode how to handle when errors appear from the inner or outer sources * @param bufferSize the expected number of outer sources to buffer while processing an inner source */ diff --git a/src/main/java/io/reactivex/rxjava4/core/config/StandardConcurrentBufferedConfig.java b/src/main/java/io/reactivex/rxjava4/core/config/StandardConcurrentBufferedConfig.java index 3bec9d7d652..22605234366 100644 --- a/src/main/java/io/reactivex/rxjava4/core/config/StandardConcurrentBufferedConfig.java +++ b/src/main/java/io/reactivex/rxjava4/core/config/StandardConcurrentBufferedConfig.java @@ -66,7 +66,8 @@ public record StandardConcurrentBufferedConfig(@NonNull ErrorMode errorMode, int new StandardConcurrentBufferedConfig(ErrorMode.BOUNDARY, Integer.MAX_VALUE, Flowable.bufferSize()); /** - * Optionally delay error, {@link Flowable#bufferSize()} sizes + * Sets the error mode to provided IMMEDIATE (false) or END (true), the maxConcurrency + * and bufferSize to {@link Flowable#bufferSize()}. * @param delayErrors should the error be delayed? */ public StandardConcurrentBufferedConfig(boolean delayErrors) { @@ -74,7 +75,8 @@ public StandardConcurrentBufferedConfig(boolean delayErrors) { } /** - * Optionally delay error, {@link Flowable#bufferSize()} sizes + * Sets the error mode to provided value, the maxConcurrency + * and bufferSize to {@link Flowable#bufferSize()}. * @param errorMode how to handle when errors appear from the inner or outer sources */ public StandardConcurrentBufferedConfig(ErrorMode errorMode) { @@ -82,7 +84,8 @@ public StandardConcurrentBufferedConfig(ErrorMode errorMode) { } /** - * Optionally set the buffer size, no delay errors. + * Sets the error mode to IMMEDIATE, the maxConcurrency to the provided value + * and bufferSize to {@link Flowable#bufferSize()}. * @param maxConcurrency the maximum number of concurrent flows */ public StandardConcurrentBufferedConfig(int maxConcurrency) { @@ -90,7 +93,8 @@ public StandardConcurrentBufferedConfig(int maxConcurrency) { } /** - * Optionally delays errors and sets the buffer size too. + * Sets the error mode to provided IMMEDIATE (false) or END (true), the maxConcurrency + * to the provided value and bufferSize to {@link Flowable#bufferSize()}. * @param delayErrors should the errors be delayed? * @param maxConcurrency the maximum number of concurrent flows */ @@ -99,7 +103,8 @@ public StandardConcurrentBufferedConfig(boolean delayErrors, int maxConcurrency) } /** - * Optionally delay error, {@link Flowable#bufferSize()} sizes + * Sets the error mode to provided value, the maxConcurrency to the provided value + * and bufferSize to {@link Flowable#bufferSize()}. * @param errorMode how to handle when errors appear from the inner or outer sources * @param maxConcurrency the maximum number of concurrent flows */ @@ -108,10 +113,11 @@ public StandardConcurrentBufferedConfig(ErrorMode errorMode, int maxConcurrency) } /** - * Optionally delay error, {@link Flowable#bufferSize()} sizes + * Sets the error mode to provided IMMEDIATE (false) or END (true), the maxConcurrency + * to the provided value and bufferSize to the provided value too. * @param delayErrors should the error be delayed? * @param maxConcurrency the maximum number of concurrent flows - * @param bufferSize what would be the buffer size + * @param bufferSize the expected number of items to buffer or prefetch from the various sources */ public StandardConcurrentBufferedConfig(boolean delayErrors, int maxConcurrency, int bufferSize) { this(delayErrors ? ErrorMode.END : ErrorMode.IMMEDIATE, maxConcurrency, bufferSize); @@ -121,7 +127,7 @@ public StandardConcurrentBufferedConfig(boolean delayErrors, int maxConcurrency, * Fully customize the configuration. * @param errorMode how to handle when errors appear from the inner or outer sources * @param maxConcurrency the maximum number of concurrent flows? - * @param bufferSize what would be the buffer size + * @param bufferSize the expected number of items to buffer or prefetch from the various sources */ public StandardConcurrentBufferedConfig { Objects.requireNonNull(errorMode, "errorMode is null"); diff --git a/src/main/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureBuffer.java b/src/main/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureBuffer.java index bec82de3313..8f5c6854e35 100644 --- a/src/main/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureBuffer.java +++ b/src/main/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureBuffer.java @@ -30,22 +30,20 @@ public final class FlowableOnBackpressureBuffer extends AbstractFlowableWithU final int bufferSize; final boolean unbounded; final boolean delayError; - final Action onOverflow; final Consumer onDropped; public FlowableOnBackpressureBuffer(Flowable source, int bufferSize, boolean unbounded, - boolean delayError, Action onOverflow, Consumer onDropped) { + boolean delayError, Consumer onDropped) { super(source); this.bufferSize = bufferSize; this.unbounded = unbounded; this.delayError = delayError; - this.onOverflow = onOverflow; this.onDropped = onDropped; } @Override protected void subscribeActual(Subscriber s) { - source.subscribe(new BackpressureBufferSubscriber<>(s, bufferSize, unbounded, delayError, onOverflow, onDropped)); + source.subscribe(new BackpressureBufferSubscriber<>(s, bufferSize, unbounded, delayError, onDropped)); } static final class BackpressureBufferSubscriber extends BasicIntQueueSubscription implements FlowableSubscriber { @@ -56,7 +54,6 @@ static final class BackpressureBufferSubscriber extends BasicIntQueueSubscrip final Subscriber downstream; final SimplePlainQueue queue; final boolean delayError; - final Action onOverflow; final Consumer onDropped; Subscription upstream; @@ -71,9 +68,8 @@ static final class BackpressureBufferSubscriber extends BasicIntQueueSubscrip boolean outputFused; BackpressureBufferSubscriber(Subscriber actual, int bufferSize, - boolean unbounded, boolean delayError, Action onOverflow, Consumer onDropped) { + boolean unbounded, boolean delayError, Consumer onDropped) { this.downstream = actual; - this.onOverflow = onOverflow; this.delayError = delayError; this.onDropped = onDropped; @@ -103,7 +99,6 @@ public void onNext(T t) { upstream.cancel(); MissingBackpressureException ex = new MissingBackpressureException("Buffer is full"); try { - onOverflow.run(); onDropped.accept(t); } catch (Throwable e) { Exceptions.throwIfFatal(e); diff --git a/src/main/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureBufferStrategy.java b/src/main/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureBufferStrategy.java index 7de125b664c..50f4309fcf4 100644 --- a/src/main/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureBufferStrategy.java +++ b/src/main/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureBufferStrategy.java @@ -35,25 +35,23 @@ public final class FlowableOnBackpressureBufferStrategy extends AbstractFlowa final long bufferSize; - final Action onOverflow; - final BackpressureOverflowStrategy strategy; final Consumer onDropped; public FlowableOnBackpressureBufferStrategy(Flowable source, - long bufferSize, Action onOverflow, BackpressureOverflowStrategy strategy, + long bufferSize, + BackpressureOverflowStrategy strategy, Consumer onDropped) { super(source); this.bufferSize = bufferSize; - this.onOverflow = onOverflow; this.strategy = strategy; this.onDropped = onDropped; } @Override protected void subscribeActual(Subscriber s) { - source.subscribe(new OnBackpressureBufferStrategySubscriber<>(s, onOverflow, strategy, bufferSize, onDropped)); + source.subscribe(new OnBackpressureBufferStrategySubscriber<>(s, strategy, bufferSize, onDropped)); } static final class OnBackpressureBufferStrategySubscriber @@ -65,8 +63,6 @@ static final class OnBackpressureBufferStrategySubscriber final Subscriber downstream; - final Action onOverflow; - final Consumer onDropped; final BackpressureOverflowStrategy strategy; @@ -84,11 +80,10 @@ static final class OnBackpressureBufferStrategySubscriber volatile boolean done; Throwable error; - OnBackpressureBufferStrategySubscriber(Subscriber actual, Action onOverflow, + OnBackpressureBufferStrategySubscriber(Subscriber actual, BackpressureOverflowStrategy strategy, long bufferSize, Consumer onDropped) { this.downstream = actual; - this.onOverflow = onOverflow; this.strategy = strategy; this.bufferSize = bufferSize; this.requested = new AtomicLong(); @@ -112,7 +107,6 @@ public void onNext(T t) { if (done) { return; } - boolean callOnOverflow = false; boolean callError = false; boolean callDrain = false; Deque dq = deque; @@ -123,12 +117,10 @@ public void onNext(T t) { case DROP_LATEST: toDrop = dq.pollLast(); dq.offer(t); - callOnOverflow = true; break; case DROP_OLDEST: toDrop = dq.poll(); dq.offer(t); - callOnOverflow = true; break; default: // signal error @@ -142,16 +134,6 @@ public void onNext(T t) { } } - if (callOnOverflow && onOverflow != null) { - try { - onOverflow.run(); - } catch (Throwable ex) { - Exceptions.throwIfFatal(ex); - upstream.cancel(); - onError(ex); - } - } - if (onDropped != null && toDrop != null) { try { onDropped.accept(toDrop); diff --git a/src/test/java/io/reactivex/rxjava4/core/config/OnBackpressureBufferConfigTest.java b/src/test/java/io/reactivex/rxjava4/core/config/OnBackpressureBufferConfigTest.java new file mode 100644 index 00000000000..de028b50334 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava4/core/config/OnBackpressureBufferConfigTest.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava4.core.config; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +import io.reactivex.rxjava4.core.RxJavaTest; +import io.reactivex.rxjava4.functions.Consumer; + +public class OnBackpressureBufferConfigTest extends RxJavaTest { + + @Test + public void validation() { + Consumer consumer = _ -> { }; + + assertEquals(5, new OnBackpressureBufferConfig<>(5).capacity(), "capacity - 5"); + assertFalse(new OnBackpressureBufferConfig<>(false).delayError(), "delayError - 5"); + assertTrue(new OnBackpressureBufferConfig<>(true).delayError(), "delayError - 5"); + + assertFalse(new OnBackpressureBufferConfig<>(5, false).delayError(), "delayError - 5"); + assertTrue(new OnBackpressureBufferConfig<>(5, true).delayError(), "delayError - 5"); + assertEquals(5, new OnBackpressureBufferConfig<>(5, false).capacity(), "delayError - 5"); + assertEquals(5, new OnBackpressureBufferConfig<>(5, true).capacity(), "delayError - 5"); + + assertFalse(new OnBackpressureBufferConfig<>(false,false).delayError(), "delayError - 5"); + assertFalse(new OnBackpressureBufferConfig<>(false, false).unbounded(), "unbounded - 5"); + assertTrue(new OnBackpressureBufferConfig<>(true, true).delayError(), "delayError - 5"); + assertTrue(new OnBackpressureBufferConfig<>(true, true).unbounded(), "unbounded - 5"); + + assertFalse(new OnBackpressureBufferConfig<>(false, true).delayError(), "delayError - 5"); + assertTrue(new OnBackpressureBufferConfig<>(false, true).unbounded(), "unbounded - 5"); + assertTrue(new OnBackpressureBufferConfig<>(true, false).delayError(), "delayError - 5"); + assertFalse(new OnBackpressureBufferConfig<>(true, false).unbounded(), "unbounded - 5"); + + assertEquals(consumer, new OnBackpressureBufferConfig<>(consumer).onDropped(), "capacity - 5"); + + assertEquals(5, new OnBackpressureBufferConfig<>(5, consumer).capacity(), "capacity - 5"); + assertEquals(consumer, new OnBackpressureBufferConfig<>(5, consumer).onDropped(), "onDropped - 5"); + + assertFalse(new OnBackpressureBufferConfig<>(5, false,false).delayError(), "delayError - 5"); + assertFalse(new OnBackpressureBufferConfig<>(5, false, false).unbounded(), "unbounded - 5"); + assertEquals(5, new OnBackpressureBufferConfig<>(5, false, false).capacity(), "capacity - 5"); + assertTrue(new OnBackpressureBufferConfig<>(5, true, true).delayError(), "delayError - 5"); + assertTrue(new OnBackpressureBufferConfig<>(5, true, true).unbounded(), "unbounded - 5"); + assertEquals(5, new OnBackpressureBufferConfig<>(5, false, true).capacity(), "capacity - 5"); + + assertFalse(new OnBackpressureBufferConfig<>(5, false, true).delayError(), "delayError - 5"); + assertTrue(new OnBackpressureBufferConfig<>(5, false, true).unbounded(), "unbounded - 5"); + assertEquals(5, new OnBackpressureBufferConfig<>(5, false, true).capacity(), "capacity - 5"); + assertTrue(new OnBackpressureBufferConfig<>(5, true, false).delayError(), "delayError - 5"); + assertFalse(new OnBackpressureBufferConfig<>(5, true, false).unbounded(), "unbounded - 5"); + assertEquals(5, new OnBackpressureBufferConfig<>(5, true, false).capacity(), "capacity - 5"); + } +} \ No newline at end of file diff --git a/src/test/java/io/reactivex/rxjava4/core/config/SampleConfigTest.java b/src/test/java/io/reactivex/rxjava4/core/config/SampleConfigTest.java new file mode 100644 index 00000000000..ca89a0ebf65 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava4/core/config/SampleConfigTest.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava4.core.config; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +import io.reactivex.rxjava4.core.RxJavaTest; +import io.reactivex.rxjava4.functions.Consumer; + +public class SampleConfigTest extends RxJavaTest { + + @Test + public void validation() { + Consumer consumer = _ -> { }; + + assertFalse(new SampleConfig<>(false).emitLast(), "emitLast - false"); + assertTrue(new SampleConfig<>(true).emitLast(), "emitLast - true"); + + assertEquals(consumer, new SampleConfig<>(consumer).onDropped(), "onDropped"); + assertFalse(new SampleConfig<>(consumer).emitLast(), "emitLast"); + + assertEquals(consumer, new SampleConfig<>(false, consumer).onDropped(), "onDropped"); + assertFalse(new SampleConfig<>(false, consumer).emitLast(), "emitLast"); + + assertEquals(consumer, new SampleConfig<>(true, consumer).onDropped(), "onDropped"); + assertTrue(new SampleConfig<>(true, consumer).emitLast(), "emitLast"); + } +} \ No newline at end of file diff --git a/src/test/java/io/reactivex/rxjava4/core/config/ObservableSequenceEqualConfigTest.java b/src/test/java/io/reactivex/rxjava4/core/config/SequenceEqualConfigTest.java similarity index 67% rename from src/test/java/io/reactivex/rxjava4/core/config/ObservableSequenceEqualConfigTest.java rename to src/test/java/io/reactivex/rxjava4/core/config/SequenceEqualConfigTest.java index 99fce368312..7a6c9942426 100644 --- a/src/test/java/io/reactivex/rxjava4/core/config/ObservableSequenceEqualConfigTest.java +++ b/src/test/java/io/reactivex/rxjava4/core/config/SequenceEqualConfigTest.java @@ -23,15 +23,15 @@ import io.reactivex.rxjava4.functions.BiPredicate; import io.reactivex.rxjava4.internal.functions.ObjectHelper; -public class ObservableSequenceEqualConfigTest extends RxJavaTest { +public class SequenceEqualConfigTest extends RxJavaTest { @Test public void validation() { BiPredicate predicate = Objects::equals; - assertEquals(5, new ObservableSequenceEqualConfig<>(5).bufferSize(), "bufferSize - 5"); - assertEquals(ObjectHelper.equalsPredicate(), new ObservableSequenceEqualConfig<>(5).isEqual(), "isEqual - std"); - assertEquals(5, new ObservableSequenceEqualConfig<>(5, predicate).bufferSize(), "bufferSize - 5"); - assertEquals(predicate, new ObservableSequenceEqualConfig<>(5, predicate).isEqual(), "isEqual - custom"); + assertEquals(5, new SequenceEqualConfig<>(5).bufferSize(), "bufferSize - 5"); + assertEquals(ObjectHelper.equalsPredicate(), new SequenceEqualConfig<>(5).isEqual(), "isEqual - std"); + assertEquals(5, new SequenceEqualConfig<>(5, predicate).bufferSize(), "bufferSize - 5"); + assertEquals(predicate, new SequenceEqualConfig<>(5, predicate).isEqual(), "isEqual - custom"); } } \ No newline at end of file diff --git a/src/test/java/io/reactivex/rxjava4/flowable/FlowableBackpressureTests.java b/src/test/java/io/reactivex/rxjava4/flowable/FlowableBackpressureTests.java index 763b5007864..c7d93de77b2 100644 --- a/src/test/java/io/reactivex/rxjava4/flowable/FlowableBackpressureTests.java +++ b/src/test/java/io/reactivex/rxjava4/flowable/FlowableBackpressureTests.java @@ -122,7 +122,7 @@ public void mergeSync() { AtomicInteger c1 = new AtomicInteger(); AtomicInteger c2 = new AtomicInteger(); TestSubscriber ts = new TestSubscriber<>(); - Flowable merged = Flowable.merge(incrementingIntegers(c1), incrementingIntegers(c2)); + Flowable merged = Flowable.mergeArray(incrementingIntegers(c1), incrementingIntegers(c2)); merged.take(num).subscribe(ts); ts.awaitDone(5, TimeUnit.SECONDS); @@ -143,7 +143,7 @@ public void mergeAsync() { AtomicInteger c1 = new AtomicInteger(); AtomicInteger c2 = new AtomicInteger(); TestSubscriber ts = new TestSubscriber<>(); - Flowable merged = Flowable.merge( + Flowable merged = Flowable.mergeArray( incrementingIntegers(c1).subscribeOn(Schedulers.computation()), incrementingIntegers(c2).subscribeOn(Schedulers.computation())); @@ -172,7 +172,7 @@ public void mergeAsyncThenObserveOnLoop() { AtomicInteger c2 = new AtomicInteger(); TestSubscriber ts = new TestSubscriber<>(); - Flowable merged = Flowable.merge( + Flowable merged = Flowable.mergeArray( incrementingIntegers(c1).subscribeOn(Schedulers.computation()), incrementingIntegers(c2).subscribeOn(Schedulers.computation())); @@ -195,7 +195,7 @@ public void mergeAsyncThenObserveOn() { AtomicInteger c1 = new AtomicInteger(); AtomicInteger c2 = new AtomicInteger(); TestSubscriber ts = new TestSubscriber<>(); - Flowable merged = Flowable.merge( + Flowable merged = Flowable.mergeArray( incrementingIntegers(c1).subscribeOn(Schedulers.computation()), incrementingIntegers(c2).subscribeOn(Schedulers.computation())); @@ -580,10 +580,13 @@ public void onBackpressureBuffer() { AtomicInteger c = new AtomicInteger(); TestSubscriber ts = new TestSubscriber<>(); - firehose(c).takeWhile(t1 -> t1 < 100000) + firehose(c) + .takeWhile(t1 -> t1 < 100000) .onBackpressureBuffer() .observeOn(Schedulers.computation()) - .map(SLOW_PASS_THRU).take(num).subscribe(ts); + .map(SLOW_PASS_THRU) + .take(num) + .subscribe(ts); ts.awaitDone(5, TimeUnit.SECONDS); ts.assertNoErrors(); diff --git a/src/test/java/io/reactivex/rxjava4/flowable/FlowableGroupByTests.java b/src/test/java/io/reactivex/rxjava4/flowable/FlowableGroupByTests.java index 7d6f6d79d84..cbaf94f37e4 100644 --- a/src/test/java/io/reactivex/rxjava4/flowable/FlowableGroupByTests.java +++ b/src/test/java/io/reactivex/rxjava4/flowable/FlowableGroupByTests.java @@ -28,7 +28,7 @@ public class FlowableGroupByTests extends RxJavaTest { @Test public void takeUnsubscribesOnGroupBy() { - Flowable.merge( + Flowable.mergeArray( FlowableEventStream.getEventStream("HTTP-ClusterA", 50), FlowableEventStream.getEventStream("HTTP-ClusterB", 20) ) @@ -45,7 +45,7 @@ public void takeUnsubscribesOnGroupBy() { @Test public void takeUnsubscribesOnFlatMapOfGroupBy() { - Flowable.merge( + Flowable.mergeArray( FlowableEventStream.getEventStream("HTTP-ClusterA", 50), FlowableEventStream.getEventStream("HTTP-ClusterB", 20) ) diff --git a/src/test/java/io/reactivex/rxjava4/flowable/FlowableMergeTests.java b/src/test/java/io/reactivex/rxjava4/flowable/FlowableMergeTests.java index 2b7ff264d13..e7c1d17cdaa 100644 --- a/src/test/java/io/reactivex/rxjava4/flowable/FlowableMergeTests.java +++ b/src/test/java/io/reactivex/rxjava4/flowable/FlowableMergeTests.java @@ -65,7 +65,7 @@ public void mergeCovariance3() { Flowable f1 = Flowable.just(new HorrorMovie(), new Movie()); Flowable f2 = Flowable.just(new Media(), new HorrorMovie()); - List values = Flowable.merge(f1, f2).toList().blockingGet(); + List values = Flowable.mergeArray(f1, f2).toList().blockingGet(); assertTrue(values.get(0) instanceof HorrorMovie); assertTrue(values.get(1) instanceof Movie); @@ -83,7 +83,7 @@ public void mergeCovariance4() { Flowable f2 = Flowable.just(new Media(), new HorrorMovie()); - List values = Flowable.merge(f1, f2).toList().blockingGet(); + List values = Flowable.mergeArray(f1, f2).toList().blockingGet(); assertTrue(values.get(0) instanceof HorrorMovie); assertTrue(values.get(1) instanceof Movie); diff --git a/src/test/java/io/reactivex/rxjava4/flowable/FlowableZipTests.java b/src/test/java/io/reactivex/rxjava4/flowable/FlowableZipTests.java index be422300676..82a0b37c8c3 100644 --- a/src/test/java/io/reactivex/rxjava4/flowable/FlowableZipTests.java +++ b/src/test/java/io/reactivex/rxjava4/flowable/FlowableZipTests.java @@ -21,6 +21,7 @@ import org.junit.Test; import io.reactivex.rxjava4.core.*; +import io.reactivex.rxjava4.core.config.StandardBufferedConfig; import io.reactivex.rxjava4.flowable.FlowableCovarianceTest.*; import io.reactivex.rxjava4.flowable.FlowableEventStream.Event; import io.reactivex.rxjava4.flowables.GroupedFlowable; @@ -97,7 +98,7 @@ public void nonBlockingObservable() { @Test public void zipWithDelayError() { Flowable.just(1) - .zipWith(Flowable.just(2), Integer::sum, true) + .zipWith(Flowable.just(2), Integer::sum, new StandardBufferedConfig(true)) .test() .assertResult(3); } @@ -105,7 +106,7 @@ public void zipWithDelayError() { @Test public void zipWithDelayErrorBufferSize() { Flowable.just(1) - .zipWith(Flowable.just(2), Integer::sum, true, 16) + .zipWith(Flowable.just(2), Integer::sum, new StandardBufferedConfig(true, 16)) .test() .assertResult(3); } diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableConcatMapEagerTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableConcatMapEagerTest.java index f509e163044..49ed4e1475f 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableConcatMapEagerTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableConcatMapEagerTest.java @@ -530,7 +530,8 @@ public void capacityHint() { Flowable source = Flowable.just(1); TestSubscriber ts = TestSubscriber.create(); - Flowable.concatEager(Arrays.asList(source, source, source), 1, 1).subscribe(ts); + Flowable.concatEager(Arrays.asList(source, source, source), new StandardConcurrentBufferedConfig(ErrorMode.BOUNDARY, 1, 1)) + .subscribe(ts); ts.assertValues(1, 1, 1); ts.assertNoErrors(); @@ -554,7 +555,7 @@ public void flowableCapacityHint() { Flowable source = Flowable.just(1); TestSubscriber ts = TestSubscriber.create(); - Flowable.concatEager(Flowable.just(source, source, source), 1, 1).subscribe(ts); + Flowable.concatEager(Flowable.just(source, source, source), new StandardConcurrentBufferedConfig(ErrorMode.BOUNDARY, 1, 1)).subscribe(ts); ts.assertValues(1, 1, 1); ts.assertNoErrors(); @@ -565,9 +566,10 @@ public void flowableCapacityHint() { public void badCapacityHint() throws Exception { Flowable source = Flowable.just(1); try { - Flowable.concatEager(Arrays.asList(source, source, source), 1, -99); + Flowable.concatEager(Arrays.asList(source, source, source), + new StandardConcurrentBufferedConfig(ErrorMode.BOUNDARY, 1, -99)); } catch (IllegalArgumentException ex) { - assertEquals("prefetch > 0 required but it was -99", ex.getMessage()); + assertEquals("bufferSize > 0 required but it was -99", ex.getMessage()); } } @@ -577,7 +579,8 @@ public void badCapacityHint() throws Exception { public void mappingBadCapacityHint() throws Exception { Flowable source = Flowable.just(1); try { - Flowable.just(source, source, source).concatMapEager((Function)Functions.identity(), new StandardConcurrentBufferedConfig(ErrorMode.IMMEDIATE, 10, -99)); + Flowable.just(source, source, source).concatMapEager((Function)Functions.identity(), + new StandardConcurrentBufferedConfig(ErrorMode.IMMEDIATE, 10, -99)); } catch (IllegalArgumentException ex) { assertEquals("bufferSize > 0 required but it was -99", ex.getMessage()); } @@ -622,7 +625,8 @@ public void publisherCapacityHint() { Flowable source = Flowable.just(1); TestSubscriber ts = TestSubscriber.create(); - Flowable.concatEager(Flowable.just(source, source, source), 1, 1).subscribe(ts); + Flowable.concatEager(Flowable.just(source, source, source), new StandardConcurrentBufferedConfig(ErrorMode.BOUNDARY, 1, 1)) + .subscribe(ts); ts.assertValues(1, 1, 1); ts.assertNoErrors(); @@ -1087,44 +1091,44 @@ public void undeliverableUponCancelDelayErrorTillEnd() { @Test public void iterableDelayError() { - Flowable.concatEagerDelayError(Arrays.asList( + Flowable.concatEager(Arrays.asList( Flowable.range(1, 2), Flowable.error(new TestException()), Flowable.range(3, 3) - )) + ), StandardConcurrentBufferedConfig.DELAY_ERRORS) .test() .assertFailure(TestException.class, 1, 2, 3, 4, 5); } @Test public void iterableDelayErrorMaxConcurrency() { - Flowable.concatEagerDelayError(Arrays.asList( + Flowable.concatEager(Arrays.asList( Flowable.range(1, 2), Flowable.error(new TestException()), Flowable.range(3, 3) - ), 1, 1) + ), new StandardConcurrentBufferedConfig(ErrorMode.END, 1, 1)) .test() .assertFailure(TestException.class, 1, 2, 3, 4, 5); } @Test public void publisherDelayError() { - Flowable.concatEagerDelayError(Flowable.fromArray( + Flowable.concatEager(Flowable.fromArray( Flowable.range(1, 2), Flowable.error(new TestException()), Flowable.range(3, 3) - )) + ), StandardConcurrentBufferedConfig.DELAY_ERRORS) .test() .assertFailure(TestException.class, 1, 2, 3, 4, 5); } @Test public void publisherDelayErrorMaxConcurrency() { - Flowable.concatEagerDelayError(Flowable.fromArray( + Flowable.concatEager(Flowable.fromArray( Flowable.range(1, 2), Flowable.error(new TestException()), Flowable.range(3, 3) - ), 1, 1) + ), new StandardConcurrentBufferedConfig(ErrorMode.END, 1, 1)) .test() .assertFailure(TestException.class, 1, 2, 3, 4, 5); } diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableDebounceTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableDebounceTest.java index 9dc9cde8c2a..89fc530830d 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableDebounceTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableDebounceTest.java @@ -309,7 +309,7 @@ public void debounceSelectorLastIsNotLost() { public void debounceWithTimeBackpressure() throws InterruptedException { TestScheduler scheduler = new TestScheduler(); TestSubscriberEx subscriber = new TestSubscriberEx<>(); - Flowable.merge( + Flowable.mergeArray( Flowable.just(1), Flowable.just(2).delay(10, TimeUnit.MILLISECONDS, scheduler) ).debounce(20, TimeUnit.MILLISECONDS, scheduler).take(1).subscribe(subscriber); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableDelayTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableDelayTest.java index 9ad9201087f..51f34c5a7de 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableDelayTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableDelayTest.java @@ -766,7 +766,7 @@ public void delayAndTakeUntilNeverSubscribeToSource() { @Test public void delayWithTimeDelayError() throws Exception { Flowable.just(1).concatWith(Flowable.error(new TestException())) - .delay(100, TimeUnit.MILLISECONDS, true) + .delay(100, TimeUnit.MILLISECONDS, Schedulers.computation(), true) .test() .awaitDone(5, TimeUnit.SECONDS) .assertFailure(TestException.class, 1); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableFlatMapTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableFlatMapTest.java index b957c1c15e4..ccb3e087fea 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableFlatMapTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableFlatMapTest.java @@ -640,7 +640,7 @@ public void onNext(Integer t) { } }; - Flowable.merge(pp, 2) + Flowable.merge(pp, new StandardConcurrentBufferedConfig(2)) .subscribe(ts); pp.onNext(Flowable.just(1)); @@ -701,7 +701,7 @@ public void scalarXMap() { @Test public void noCrossBoundaryFusion() { for (int i = 0; i < 500; i++) { - TestSubscriber ts = Flowable.merge( + TestSubscriber ts = Flowable.mergeArray( Flowable.just(1).observeOn(Schedulers.single()).map(_ -> Thread.currentThread().getName().substring(0, 4)), Flowable.just(1).observeOn(Schedulers.computation()).map(_ -> Thread.currentThread().getName().substring(0, 4)) ) diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableGroupByTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableGroupByTest.java index be94d235a9c..ea46301c7a9 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableGroupByTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableGroupByTest.java @@ -31,7 +31,7 @@ import com.google.common.cache.*; import io.reactivex.rxjava4.core.*; -import io.reactivex.rxjava4.core.config.StandardConcurrentBufferedConfig; +import io.reactivex.rxjava4.core.config.*; import io.reactivex.rxjava4.exceptions.*; import io.reactivex.rxjava4.flowables.GroupedFlowable; import io.reactivex.rxjava4.functions.*; @@ -1002,8 +1002,8 @@ public void backpressureObserveOnOuter() { Flowable.merge( Flowable.range(0, n) .groupBy(i -> i % (Flowable.bufferSize() + 2)) - .observeOn(Schedulers.computation(), false, n) - , n) + .observeOn(Schedulers.computation(), new StandardBufferedConfig(false, n)) + , new StandardConcurrentBufferedConfig(n)) .blockingLast(); } } @@ -1110,7 +1110,7 @@ public void outerInnerFusion() { @SuppressUndeliverable public void keySelectorAndDelayError() { Flowable.just(1).concatWith(Flowable.error(new TestException())) - .groupBy(Functions.identity(), true) + .groupBy(Functions.identity(), new StandardBufferedConfig(true)) .flatMap((Function, Flowable>) g -> g) .test() .assertFailure(TestException.class, 1); @@ -1120,7 +1120,7 @@ public void keySelectorAndDelayError() { @SuppressUndeliverable public void keyAndValueSelectorAndDelayError() { Flowable.just(1).concatWith(Flowable.error(new TestException())) - .groupBy(Functions.identity(), Functions.identity(), true) + .groupBy(Functions.identity(), Functions.identity(), new StandardBufferedConfig(true)) .flatMap((Function, Flowable>) g -> g) .test() .assertFailure(TestException.class, 1); @@ -1184,7 +1184,7 @@ public void onNext(Integer t) { @Test public void delayErrorSimpleComplete() { Flowable.just(1) - .groupBy(Functions.justFunction(1), true) + .groupBy(Functions.justFunction(1), new StandardBufferedConfig(true)) .flatMap(Functions.>identity()) .test() .assertResult(1); @@ -1242,7 +1242,7 @@ public void nullKeyTakeInner() { @SuppressUndeliverable public void groupError() { Flowable.just(1).concatWith(Flowable.error(new TestException())) - .groupBy(Functions.justFunction(1), true) + .groupBy(Functions.justFunction(1), new StandardBufferedConfig(true)) .flatMap((Function, Publisher>) GroupedFlowable::hide) .test() .assertFailure(TestException.class, 1); @@ -1251,7 +1251,7 @@ public void groupError() { @Test public void groupComplete() { Flowable.just(1) - .groupBy(Functions.justFunction(1), true) + .groupBy(Functions.justFunction(1), new StandardBufferedConfig(true)) .flatMap((Function, Publisher>) GroupedFlowable::hide) .test() .assertResult(1); @@ -1265,7 +1265,7 @@ public void mapFactoryThrows() { throw ex; }; Flowable.just(1) - .groupBy(Functions.identity(), Functions.identity(), true, 16, evictingMapFactory) + .groupBy(Functions.identity(), Functions.identity(), evictingMapFactory, new StandardBufferedConfig(true, 16)) .test() .assertNoValues() .assertError(ex); @@ -1294,7 +1294,8 @@ public void mapFactoryExpiryCompletesGroupedFlowable() { Function, Map> evictingMapFactory = createEvictingMapFactorySynchronousOnly(1); PublishSubject subject = PublishSubject.create(); TestSubscriberEx ts = subject.toFlowable(BackpressureStrategy.BUFFER) - .groupBy(Functions.identity(), Functions.identity(), true, 16, evictingMapFactory) + .groupBy(Functions.identity(), Functions.identity(), evictingMapFactory, + new StandardBufferedConfig(true, 16)) .flatMap(addCompletedKey(completed)) .to(TestHelper.testConsumer()); subject.onNext(1); @@ -1315,7 +1316,8 @@ public void mapFactoryEvictionQueueClearedOnErrorCoverageOnly() { PublishSubject subject = PublishSubject.create(); TestSubscriber ts = subject .toFlowable(BackpressureStrategy.BUFFER) - .groupBy(Functions.identity(), Functions.identity(), true, 16, evictingMapFactory) + .groupBy(Functions.identity(), Functions.identity(), evictingMapFactory, + new StandardBufferedConfig(true, 16)) .flatMap((Function, Publisher>) g -> g) .test(); RuntimeException ex = new RuntimeException(); @@ -1337,7 +1339,7 @@ public void mapFactoryWithExpiringGuavaCacheDemonstrationCodeForUseInJavadoc() { int numValues = 1000; TestSubscriber ts = Flowable.range(1, numValues) - .groupBy(mod5, Functions.identity(), true, 16, evictingMapFactory) + .groupBy(mod5, Functions.identity(), evictingMapFactory, new StandardBufferedConfig(true, 16)) .flatMap(addCompletedKey(completed)) .test() .assertComplete() @@ -1367,8 +1369,8 @@ public void groupByEvictionCancellationOfSource5933() { final List list = new CopyOnWriteArrayList<>(); Flowable stream = source // .doOnCancel(() -> list.add("Source cancelled")) - .groupBy(Functions.identity(), Functions.identity(), false, - Flowable.bufferSize(), mapFactory) // + .groupBy(Functions.identity(), Functions.identity(), + mapFactory, new StandardBufferedConfig(false, Flowable.bufferSize())) // .flatMap(group -> group // .doOnComplete(() -> list.add("Group completed")).doOnCancel(() -> list.add("Group cancelled"))); TestSubscriber ts = stream // @@ -1556,7 +1558,7 @@ public void cancelOverFlatmapRace() { final PublishProcessor pp = PublishProcessor.create(); - pp.groupBy(v -> v % 10, Functions.identity(), false, 2048) + pp.groupBy(v -> v % 10, Functions.identity(), new StandardBufferedConfig(false, 2048)) .flatMap((Function, GroupedFlowable>) v -> v) .subscribe(ts); @@ -1717,7 +1719,7 @@ public void cancelledGroupResumesRequesting() { public void delayErrorCompleteMoreWorkInGroup() { PublishProcessor pp = PublishProcessor.create(); - TestSubscriber ts = pp.groupBy(_ -> 1, true) + TestSubscriber ts = pp.groupBy(_ -> 1, new StandardBufferedConfig(true)) .flatMap(g -> g.doOnNext(v -> { if (v == 1) { pp.onNext(2); @@ -1789,7 +1791,7 @@ static void issue6974Run(int groups, int iterations, int sizeCap, int flatMapCon TestSubscriber test = Flowable .range(1, groups) .repeat(iterations / groups) - .groupBy(i -> i, i -> i, false, 128, sizeCap(sizeCap, notifyOnExplicitRevoke)) + .groupBy(i -> i, i -> i, sizeCap(sizeCap, notifyOnExplicitRevoke), new StandardBufferedConfig(false, 128)) .flatMap(gf -> gf.compose(operation), new StandardConcurrentBufferedConfig(flatMapConcurrency)) .test(); test.awaitDone(5, TimeUnit.SECONDS); @@ -1818,9 +1820,11 @@ static void issue6974RunPart2(int groupByBufferSize, int flatMapMaxConcurrency, TestSubscriber ts = Flowable .range(1, 500_000) .map(i -> i % groups) - .groupBy(i -> i, i -> i, false, groupByBufferSize, + .groupBy(i -> i, i -> i, // set cap too high - sizeCap(groups * 100, notifyOnExplicitEviction)) + sizeCap(groups * 100, notifyOnExplicitEviction), + new StandardBufferedConfig(false, groupByBufferSize) + ) .flatMap(gf -> gf .take(10, TimeUnit.MILLISECONDS) , new StandardConcurrentBufferedConfig(flatMapMaxConcurrency)) @@ -1893,8 +1897,8 @@ public void issue6974Part2Case1ObserveOn() { .range(1, 500_000) .map(i -> i % groups) .doOnCancel(() -> System.out.println("Cancelling upstream")) - .groupBy(i -> i, i -> i, false, groupByBufferSize, - sizeCap(groups * 2, notifyOnExplicitEviction)) + .groupBy(i -> i, i -> i, sizeCap(groups * 2, notifyOnExplicitEviction), + new StandardBufferedConfig(false, groupByBufferSize)) .flatMap(gf -> gf .observeOn(Schedulers.computation()) // .take(10) @@ -1918,8 +1922,8 @@ public void issue6974Part2Case1ObserveOnHide() { .range(1, 500_000) .map(i -> i % groups) .doOnCancel(() -> System.out.println("Cancelling upstream")) - .groupBy(i -> i, i -> i, false, groupByBufferSize, - sizeCap(groups * 2, notifyOnExplicitEviction)) + .groupBy(i -> i, i -> i, sizeCap(groups * 2, notifyOnExplicitEviction), + new StandardBufferedConfig(false, groupByBufferSize)) .flatMap(gf -> gf .hide() .observeOn(Schedulers.computation()) @@ -1991,8 +1995,8 @@ public void issue6974Part2Case1ObserveOnConditional() { .range(1, 500_000) .map(i -> i % groups) .doOnCancel(() -> System.out.println("Cancelling upstream")) - .groupBy(i -> i, i -> i, false, groupByBufferSize, - sizeCap(groups * 2, notifyOnExplicitEviction)) + .groupBy(i -> i, i -> i, sizeCap(groups * 2, notifyOnExplicitEviction), + new StandardBufferedConfig(false, groupByBufferSize)) .flatMap(gf -> gf .observeOn(Schedulers.computation()) .filter(_ -> true) @@ -2017,8 +2021,8 @@ public void issue6974Part2Case1ObserveOnConditionalHide() { .range(1, 500_000) .map(i -> i % groups) .doOnCancel(() -> System.out.println("Cancelling upstream")) - .groupBy(i -> i, i -> i, false, groupByBufferSize, - sizeCap(groups * 2, notifyOnExplicitEviction)) + .groupBy(i -> i, i -> i, sizeCap(groups * 2, notifyOnExplicitEviction), + new StandardBufferedConfig(false, groupByBufferSize)) .flatMap(gf -> gf .hide() .observeOn(Schedulers.computation()) @@ -2060,7 +2064,7 @@ public void issue6982Case1() { Flowable .range(1, 500_000) .map(i -> i % groups) - .groupBy(i -> i, i -> i, false, groupByBufferSize, ttlCapGuava(Duration.ofMillis(10))) + .groupBy(i -> i, i -> i, ttlCapGuava(Duration.ofMillis(10)), new StandardBufferedConfig(false, groupByBufferSize)) .flatMap(gf -> gf.observeOn(Schedulers.computation()), new StandardConcurrentBufferedConfig(flatMapMaxConcurrency)) .test() .awaitDone(5, TimeUnit.SECONDS) @@ -2079,7 +2083,8 @@ public void issue6982Case2() { Flowable .range(1, 500_000) .map(i -> i % groups) - .groupBy(i -> i, i -> i, false, groupByBufferSize, ttlCapGuava(Duration.ofMillis(10))) + .groupBy(i -> i, i -> i, ttlCapGuava(Duration.ofMillis(10)), + new StandardBufferedConfig(false, groupByBufferSize)) .flatMap(gf -> gf.observeOn(Schedulers.computation()), new StandardConcurrentBufferedConfig(flatMapMaxConcurrency)) .test() .awaitDone(5, TimeUnit.SECONDS) diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableMergeDelayErrorTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableMergeDelayErrorTest.java index 32839114d66..a1f5576d341 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableMergeDelayErrorTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableMergeDelayErrorTest.java @@ -14,16 +14,18 @@ package io.reactivex.rxjava4.internal.operators.flowable; import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; import java.util.*; import java.util.concurrent.*; +import java.util.concurrent.Flow.*; import org.junit.*; -import static java.util.concurrent.Flow.*; import io.reactivex.rxjava4.core.*; +import io.reactivex.rxjava4.core.config.StandardConcurrentBufferedConfig; import io.reactivex.rxjava4.exceptions.*; import io.reactivex.rxjava4.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava4.processors.PublishProcessor; @@ -45,7 +47,7 @@ public void errorDelayed1() { final Flowable f1 = Flowable.unsafeCreate(new TestErrorFlowable("four", null, "six")); final Flowable f2 = Flowable.unsafeCreate(new TestErrorFlowable("one", "two", "three")); - Flowable m = Flowable.mergeDelayError(f1, f2); + Flowable m = Flowable.mergeArray(StandardConcurrentBufferedConfig.DELAY_ERRORS, f1, f2); m.subscribe(stringSubscriber); verify(stringSubscriber, times(1)).onError(any(NullPointerException.class)); @@ -69,7 +71,7 @@ public void errorDelayed2() { final Flowable f3 = Flowable.unsafeCreate(new TestErrorFlowable("seven", "eight", null)); final Flowable f4 = Flowable.unsafeCreate(new TestErrorFlowable("nine")); - Flowable m = Flowable.mergeDelayError(f1, f2, f3, f4); + Flowable m = Flowable.mergeArray(StandardConcurrentBufferedConfig.DELAY_ERRORS, f1, f2, f3, f4); m.subscribe(stringSubscriber); verify(stringSubscriber, times(1)).onError(any(CompositeException.class)); @@ -94,7 +96,7 @@ public void errorDelayed3() { final Flowable f3 = Flowable.unsafeCreate(new TestErrorFlowable("seven", "eight", null)); final Flowable f4 = Flowable.unsafeCreate(new TestErrorFlowable("nine")); - Flowable m = Flowable.mergeDelayError(f1, f2, f3, f4); + Flowable m = Flowable.mergeArray(StandardConcurrentBufferedConfig.DELAY_ERRORS, f1, f2, f3, f4); m.subscribe(stringSubscriber); verify(stringSubscriber, times(1)).onError(any(NullPointerException.class)); @@ -117,7 +119,7 @@ public void errorDelayed4() { final Flowable f3 = Flowable.unsafeCreate(new TestErrorFlowable("seven", "eight")); final Flowable f4 = Flowable.unsafeCreate(new TestErrorFlowable("nine", null)); - Flowable m = Flowable.mergeDelayError(f1, f2, f3, f4); + Flowable m = Flowable.mergeArray(StandardConcurrentBufferedConfig.DELAY_ERRORS, f1, f2, f3, f4); m.subscribe(stringSubscriber); verify(stringSubscriber, times(1)).onError(any(NullPointerException.class)); @@ -141,7 +143,10 @@ public void errorDelayed4WithThreading() { // throw the error at the very end so no onComplete will be called after it final TestAsyncErrorFlowable f4 = new TestAsyncErrorFlowable("nine", null); - Flowable m = Flowable.mergeDelayError(Flowable.unsafeCreate(f1), Flowable.unsafeCreate(f2), Flowable.unsafeCreate(f3), Flowable.unsafeCreate(f4)); + Flowable m = Flowable.mergeArray( + StandardConcurrentBufferedConfig.DELAY_ERRORS, + Flowable.unsafeCreate(f1), Flowable.unsafeCreate(f2), + Flowable.unsafeCreate(f3), Flowable.unsafeCreate(f4)); m.subscribe(stringSubscriber); try { @@ -172,7 +177,7 @@ public void compositeErrorDelayed1() { final Flowable f1 = Flowable.unsafeCreate(new TestErrorFlowable("four", null, "six")); final Flowable f2 = Flowable.unsafeCreate(new TestErrorFlowable("one", "two", null)); - Flowable m = Flowable.mergeDelayError(f1, f2); + Flowable m = Flowable.mergeArray(StandardConcurrentBufferedConfig.DELAY_ERRORS, f1, f2); m.subscribe(stringSubscriber); verify(stringSubscriber, times(1)).onError(any(Throwable.class)); @@ -193,7 +198,7 @@ public void compositeErrorDelayed2() { final Flowable f1 = Flowable.unsafeCreate(new TestErrorFlowable("four", null, "six")); final Flowable f2 = Flowable.unsafeCreate(new TestErrorFlowable("one", "two", null)); - Flowable m = Flowable.mergeDelayError(f1, f2); + Flowable m = Flowable.mergeArray(StandardConcurrentBufferedConfig.DELAY_ERRORS, f1, f2); CaptureObserver w = new CaptureObserver(); m.subscribe(w); @@ -230,7 +235,7 @@ public void mergeFlowableOfFlowables() { subscriber.onNext(f2); subscriber.onComplete(); }); - Flowable m = Flowable.mergeDelayError(flowableOfFlowables); + Flowable m = Flowable.merge(flowableOfFlowables, StandardConcurrentBufferedConfig.DELAY_ERRORS); m.subscribe(stringSubscriber); verify(stringSubscriber, never()).onError(any(Throwable.class)); @@ -243,7 +248,7 @@ public void mergeArray() { final Flowable f1 = Flowable.unsafeCreate(new TestSynchronousFlowable()); final Flowable f2 = Flowable.unsafeCreate(new TestSynchronousFlowable()); - Flowable m = Flowable.mergeDelayError(f1, f2); + Flowable m = Flowable.mergeArray(StandardConcurrentBufferedConfig.DELAY_ERRORS, f1, f2); m.subscribe(stringSubscriber); verify(stringSubscriber, never()).onError(any(Throwable.class)); @@ -259,7 +264,7 @@ public void mergeList() { listOfFlowables.add(f1); listOfFlowables.add(f2); - Flowable m = Flowable.mergeDelayError(Flowable.fromIterable(listOfFlowables)); + Flowable m = Flowable.merge(Flowable.fromIterable(listOfFlowables), StandardConcurrentBufferedConfig.DELAY_ERRORS); m.subscribe(stringSubscriber); verify(stringSubscriber, never()).onError(any(Throwable.class)); @@ -272,7 +277,8 @@ public void mergeArrayWithThreading() { final TestASynchronousFlowable f1 = new TestASynchronousFlowable(); final TestASynchronousFlowable f2 = new TestASynchronousFlowable(); - Flowable m = Flowable.mergeDelayError(Flowable.unsafeCreate(f1), Flowable.unsafeCreate(f2)); + Flowable m = Flowable.mergeArray(StandardConcurrentBufferedConfig.DELAY_ERRORS, + Flowable.unsafeCreate(f1), Flowable.unsafeCreate(f2)); m.subscribe(stringSubscriber); try { @@ -292,7 +298,8 @@ public void synchronousError() { final Flowable> f1 = Flowable.error(new RuntimeException("unit test")); final CountDownLatch latch = new CountDownLatch(1); - Flowable.mergeDelayError(f1).subscribe(new DefaultSubscriber<>() /* NFI */ { + Flowable.merge(f1, StandardConcurrentBufferedConfig.DELAY_ERRORS) + .subscribe(new DefaultSubscriber<>() /* NFI */ { @Override public void onComplete() { fail("Expected onError path"); @@ -427,9 +434,10 @@ public void onNext(String args) { @Test public void errorInParentFlowable() { TestSubscriberEx ts = new TestSubscriberEx<>(); - Flowable.mergeDelayError( + Flowable.merge( Flowable.just(Flowable.just(1), Flowable.just(2)) - .startWithItem(Flowable. error(new RuntimeException())) + .startWithItem(Flowable. error(new RuntimeException())), + StandardConcurrentBufferedConfig.DELAY_ERRORS ).subscribe(ts); ts.awaitDone(5, TimeUnit.SECONDS); ts.assertTerminated(); @@ -453,7 +461,7 @@ public void errorInParentFlowableDelayed() throws Exception { stringSubscriber = TestHelper.mockSubscriber(); TestSubscriberEx ts = new TestSubscriberEx<>(stringSubscriber); - Flowable m = Flowable.mergeDelayError(parentFlowable); + Flowable m = Flowable.merge(parentFlowable, StandardConcurrentBufferedConfig.DELAY_ERRORS); m.subscribe(ts); System.out.println("testErrorInParentFlowableDelayed | " + i); ts.awaitDone(2000, TimeUnit.MILLISECONDS); @@ -487,10 +495,10 @@ public void subscribe(final Subscriber subscriber) { @Test public void delayErrorMaxConcurrent() { final List requests = new ArrayList<>(); - Flowable source = Flowable.mergeDelayError(Flowable.just( + Flowable source = Flowable.merge(Flowable.just( Flowable.just(1).hide(), Flowable.error(new TestException())) - .doOnRequest(requests::add), 1); + .doOnRequest(requests::add), new StandardConcurrentBufferedConfig(ErrorMode.END, 1)); TestSubscriberEx ts = new TestSubscriberEx<>(); @@ -511,7 +519,7 @@ public void mergeIterable() { listOfFlowables.add(f1); listOfFlowables.add(f2); - Flowable m = Flowable.mergeDelayError(listOfFlowables); + Flowable m = Flowable.merge(listOfFlowables, StandardConcurrentBufferedConfig.DELAY_ERRORS); m.subscribe(stringSubscriber); verify(stringSubscriber, never()).onError(any(Throwable.class)); @@ -526,7 +534,7 @@ public void iterableMaxConcurrent() { PublishProcessor pp1 = PublishProcessor.create(); PublishProcessor pp2 = PublishProcessor.create(); - Flowable.mergeDelayError(Arrays.asList(pp1, pp2), 1).subscribe(ts); + Flowable.merge(Arrays.asList(pp1, pp2), new StandardConcurrentBufferedConfig(ErrorMode.END, 1)).subscribe(ts); assertTrue("ps1 has no subscribers?!", pp1.hasSubscribers()); assertFalse("ps2 has subscribers?!", pp2.hasSubscribers()); @@ -552,7 +560,8 @@ public void iterableMaxConcurrentError() { PublishProcessor pp1 = PublishProcessor.create(); PublishProcessor pp2 = PublishProcessor.create(); - Flowable.mergeDelayError(Arrays.asList(pp1, pp2), 1).subscribe(ts); + Flowable.merge(Arrays.asList(pp1, pp2), new StandardConcurrentBufferedConfig(ErrorMode.END, 1)) + .subscribe(ts); assertTrue("ps1 has no subscribers?!", pp1.hasSubscribers()); assertFalse("ps2 has subscribers?!", pp2.hasSubscribers()); @@ -591,7 +600,7 @@ public void array() { expected[j] = 1; } - Flowable.mergeArrayDelayError(sources) + Flowable.mergeArray(StandardConcurrentBufferedConfig.DELAY_ERRORS, sources) .test() .assertResult(expected); } @@ -599,77 +608,82 @@ public void array() { @Test public void mergeArrayDelayError() { - Flowable.mergeArrayDelayError(Flowable.just(1), Flowable.just(2)) + Flowable.mergeArray(StandardConcurrentBufferedConfig.DELAY_ERRORS, Flowable.just(1), Flowable.just(2)) .test() .assertResult(1, 2); } @Test public void mergeIterableDelayErrorWithError() { - Flowable.mergeDelayError( + Flowable.merge( Arrays.asList(Flowable.just(1).concatWith(Flowable.error(new TestException())), - Flowable.just(2))) + Flowable.just(2)), StandardConcurrentBufferedConfig.DELAY_ERRORS) .test() .assertFailure(TestException.class, 1, 2); } @Test public void mergeDelayError() { - Flowable.mergeDelayError( + Flowable.merge( Flowable.just(Flowable.just(1), - Flowable.just(2))) + Flowable.just(2)), + StandardConcurrentBufferedConfig.DELAY_ERRORS + ) .test() .assertResult(1, 2); } @Test public void mergeDelayErrorWithError() { - Flowable.mergeDelayError( + Flowable.merge( Flowable.just(Flowable.just(1).concatWith(Flowable.error(new TestException())), - Flowable.just(2))) + Flowable.just(2)), + StandardConcurrentBufferedConfig.DELAY_ERRORS + ) .test() .assertFailure(TestException.class, 1, 2); } @Test public void mergeDelayErrorMaxConcurrency() { - Flowable.mergeDelayError( + Flowable.merge( Flowable.just(Flowable.just(1), - Flowable.just(2)), 1) + Flowable.just(2)), new StandardConcurrentBufferedConfig(ErrorMode.END, 1)) .test() .assertResult(1, 2); } @Test public void mergeDelayErrorWithErrorMaxConcurrency() { - Flowable.mergeDelayError( + Flowable.merge( Flowable.just(Flowable.just(1).concatWith(Flowable.error(new TestException())), - Flowable.just(2)), 1) + Flowable.just(2)), new StandardConcurrentBufferedConfig(ErrorMode.END, 1)) .test() .assertFailure(TestException.class, 1, 2); } @Test public void mergeIterableDelayErrorMaxConcurrency() { - Flowable.mergeDelayError( + Flowable.merge( Arrays.asList(Flowable.just(1), - Flowable.just(2)), 1) + Flowable.just(2)), new StandardConcurrentBufferedConfig(ErrorMode.END, 1)) .test() .assertResult(1, 2); } @Test public void mergeIterableDelayErrorWithErrorMaxConcurrency() { - Flowable.mergeDelayError( + Flowable.merge( Arrays.asList(Flowable.just(1).concatWith(Flowable.error(new TestException())), - Flowable.just(2)), 1) + Flowable.just(2)), new StandardConcurrentBufferedConfig(ErrorMode.END, 1)) .test() .assertFailure(TestException.class, 1, 2); } @Test public void mergeDelayError3() { - Flowable.mergeDelayError( + Flowable.mergeArray( + StandardConcurrentBufferedConfig.DELAY_ERRORS, Flowable.just(1), Flowable.just(2), Flowable.just(3) @@ -680,7 +694,8 @@ public void mergeDelayError3() { @Test public void mergeDelayError3WithError() { - Flowable.mergeDelayError( + Flowable.mergeArray( + StandardConcurrentBufferedConfig.DELAY_ERRORS, Flowable.just(1), Flowable.just(2).concatWith(Flowable.error(new TestException())), Flowable.just(3) @@ -691,7 +706,8 @@ public void mergeDelayError3WithError() { @Test public void mergeIterableDelayError() { - Flowable.mergeDelayError(Arrays.asList(Flowable.just(1), Flowable.just(2))) + Flowable.merge(Arrays.asList(Flowable.just(1), Flowable.just(2)), + StandardConcurrentBufferedConfig.DELAY_ERRORS) .test() .assertResult(1, 2); } diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableMergeMaxConcurrentTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableMergeMaxConcurrentTest.java index 7a611e60a6d..353097c2288 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableMergeMaxConcurrentTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableMergeMaxConcurrentTest.java @@ -23,6 +23,7 @@ import org.junit.Test; import io.reactivex.rxjava4.core.*; +import io.reactivex.rxjava4.core.config.StandardConcurrentBufferedConfig; import io.reactivex.rxjava4.internal.schedulers.CachedScheduler; import io.reactivex.rxjava4.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava4.schedulers.Schedulers; @@ -40,7 +41,8 @@ public void whenMaxConcurrentIsOne() { os.add(Flowable.just("one", "two", "three", "four", "five").subscribeOn(Schedulers.newThread())); List expected = Arrays.asList("one", "two", "three", "four", "five", "one", "two", "three", "four", "five", "one", "two", "three", "four", "five"); - Iterator iter = Flowable.merge(os, 1).blockingIterable().iterator(); + Iterator iter = Flowable.merge(os, new StandardConcurrentBufferedConfig(1)) + .blockingIterable().iterator(); List actual = new ArrayList<>(); while (iter.hasNext()) { actual.add(iter.next()); @@ -65,7 +67,8 @@ public void maxConcurrent() { os.add(Flowable.unsafeCreate(sco)); } - Iterator iter = Flowable.merge(os, maxConcurrent).blockingIterable().iterator(); + Iterator iter = Flowable.merge(os, new StandardConcurrentBufferedConfig(maxConcurrent)) + .blockingIterable().iterator(); List actual = new ArrayList<>(); while (iter.hasNext()) { actual.add(iter.next()); @@ -117,7 +120,8 @@ public void mergeALotOfSourcesOneByOneSynchronously() { for (int i = 0; i < n; i++) { sourceList.add(Flowable.just(i)); } - Iterator it = Flowable.merge(Flowable.fromIterable(sourceList), 1).blockingIterable().iterator(); + Iterator it = Flowable.merge(Flowable.fromIterable(sourceList), new StandardConcurrentBufferedConfig(1)) + .blockingIterable().iterator(); int j = 0; while (it.hasNext()) { assertEquals((Integer)j, it.next()); @@ -133,7 +137,8 @@ public void mergeALotOfSourcesOneByOneSynchronouslyTakeHalf() { for (int i = 0; i < n; i++) { sourceList.add(Flowable.just(i)); } - Iterator it = Flowable.merge(Flowable.fromIterable(sourceList), 1).take(n / 2).blockingIterable().iterator(); + Iterator it = Flowable.merge(Flowable.fromIterable(sourceList), new StandardConcurrentBufferedConfig(1)) + .take(n / 2).blockingIterable().iterator(); int j = 0; while (it.hasNext()) { assertEquals((Integer)j, it.next()); @@ -153,7 +158,8 @@ public void simple() { result.add(j); } - Flowable.merge(sourceList, i).subscribe(ts); + Flowable.merge(sourceList, new StandardConcurrentBufferedConfig(i)) + .subscribe(ts); ts.assertNoErrors(); ts.assertTerminated(); @@ -172,7 +178,8 @@ public void simpleOneLess() { result.add(j); } - Flowable.merge(sourceList, i - 1).subscribe(ts); + Flowable.merge(sourceList, new StandardConcurrentBufferedConfig(i - 1)) + .subscribe(ts); ts.assertNoErrors(); ts.assertTerminated(); @@ -204,7 +211,8 @@ public void simpleAsync() { expected.add(j); } - Flowable.merge(sourceList, i).subscribe(ts); + Flowable.merge(sourceList, new StandardConcurrentBufferedConfig(i)) + .subscribe(ts); ts.awaitDone(1, TimeUnit.SECONDS); ts.assertNoErrors(); @@ -236,7 +244,8 @@ public void simpleOneLessAsync() { expected.add(j); } - Flowable.merge(sourceList, i - 1).subscribe(ts); + Flowable.merge(sourceList, new StandardConcurrentBufferedConfig(i - 1)) + .subscribe(ts); ts.awaitDone(1, TimeUnit.SECONDS); ts.assertNoErrors(); @@ -264,7 +273,8 @@ public void onNext(Integer t) { } }; - Flowable.merge(sourceList, 2).subscribe(ts); + Flowable.merge(sourceList, new StandardConcurrentBufferedConfig(2)) + .subscribe(ts); ts.request(5); @@ -287,7 +297,9 @@ public void take() throws Exception { TestSubscriber ts = new TestSubscriber<>(); - Flowable.merge(sourceList, 2).take(5).subscribe(ts); + Flowable.merge(sourceList, new StandardConcurrentBufferedConfig(2)) + .take(5) + .subscribe(ts); ts.awaitDone(5, TimeUnit.SECONDS); ts.assertNoErrors(); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableMergeTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableMergeTest.java index 0c8e8821dd7..b6d7e6fded8 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableMergeTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableMergeTest.java @@ -100,7 +100,7 @@ public void mergeArray() { final Flowable f1 = Flowable.unsafeCreate(new TestSynchronousFlowable()); final Flowable f2 = Flowable.unsafeCreate(new TestSynchronousFlowable()); - Flowable m = Flowable.merge(f1, f2); + Flowable m = Flowable.mergeArray(f1, f2); m.subscribe(stringSubscriber); verify(stringSubscriber, never()).onError(any(Throwable.class)); @@ -184,7 +184,7 @@ public void mergeArrayWithThreading() { final TestASynchronousFlowable f1 = new TestASynchronousFlowable(); final TestASynchronousFlowable f2 = new TestASynchronousFlowable(); - Flowable m = Flowable.merge(Flowable.unsafeCreate(f1), Flowable.unsafeCreate(f2)); + Flowable m = Flowable.mergeArray(Flowable.unsafeCreate(f1), Flowable.unsafeCreate(f2)); TestSubscriber ts = new TestSubscriber<>(stringSubscriber); m.subscribe(ts); @@ -219,7 +219,7 @@ public void synchronizationOfMultipleSequences() throws Throwable { final AtomicReference error = new AtomicReference<>(); - Flowable m = Flowable.merge(Flowable.unsafeCreate(f1), Flowable.unsafeCreate(f2)); + Flowable m = Flowable.mergeArray(Flowable.unsafeCreate(f1), Flowable.unsafeCreate(f2)); m.subscribe(new DefaultSubscriber<>() /* NFI */ { @Override @@ -300,7 +300,7 @@ public void error1() { final Flowable f1 = Flowable.unsafeCreate(new TestErrorFlowable("four", null, "six")); // we expect to lose "six" final Flowable f2 = Flowable.unsafeCreate(new TestErrorFlowable("one", "two", "three")); // we expect to lose all of these since o1 is done first and fails - Flowable m = Flowable.merge(f1, f2); + Flowable m = Flowable.mergeArray(f1, f2); m.subscribe(stringSubscriber); verify(stringSubscriber, times(1)).onError(any(NullPointerException.class)); @@ -324,7 +324,7 @@ public void error2() { final Flowable f3 = Flowable.unsafeCreate(new TestErrorFlowable("seven", "eight", null)); // we expect to lose all of these since o2 is done first and fails final Flowable f4 = Flowable.unsafeCreate(new TestErrorFlowable("nine")); // we expect to lose all of these since o2 is done first and fails - Flowable m = Flowable.merge(f1, f2, f3, f4); + Flowable m = Flowable.mergeArray(f1, f2, f3, f4); m.subscribe(stringSubscriber); verify(stringSubscriber, times(1)).onError(any(NullPointerException.class)); @@ -406,7 +406,7 @@ public void unsubscribeAsFlowablesComplete() { Flowable f2 = createFlowableOf5IntervalsOf1SecondIncrementsWithSubscriptionHook(scheduler2, os2); TestSubscriberEx ts = new TestSubscriberEx<>(); - Flowable.merge(f1, f2).subscribe(ts); + Flowable.mergeArray(f1, f2).subscribe(ts); // we haven't incremented time so nothing should be received yet ts.assertNoValues(); @@ -448,7 +448,7 @@ public void earlyUnsubscribe() { Flowable f2 = createFlowableOf5IntervalsOf1SecondIncrementsWithSubscriptionHook(scheduler2, os2); TestSubscriber ts = new TestSubscriber<>(); - Flowable.merge(f1, f2).subscribe(ts); + Flowable.mergeArray(f1, f2).subscribe(ts); // we haven't incremented time so nothing should be received yet ts.assertNoValues(); @@ -516,7 +516,8 @@ public void concurrency() { Flowable f = Flowable.range(1, 10000).subscribeOn(Schedulers.newThread()); for (int i = 0; i < 10; i++) { - Flowable merge = Flowable.merge(f.onBackpressureBuffer(), f.onBackpressureBuffer(), f.onBackpressureBuffer()); + Flowable merge = Flowable.mergeArray( + f.onBackpressureBuffer(), f.onBackpressureBuffer(), f.onBackpressureBuffer()); TestSubscriberEx ts = new TestSubscriberEx<>(); merge.subscribe(ts); @@ -560,7 +561,7 @@ public void concurrencyWithSleeping() { }); for (int i = 0; i < 10; i++) { - Flowable merge = Flowable.merge(f, f, f); + Flowable merge = Flowable.mergeArray(f, f, f); TestSubscriber ts = new TestSubscriber<>(); merge.subscribe(ts); @@ -598,7 +599,7 @@ public void concurrencyWithBrokenOnCompleteContract() { }); for (int i = 0; i < 10; i++) { - Flowable merge = Flowable.merge(f.onBackpressureBuffer(), f.onBackpressureBuffer(), f.onBackpressureBuffer()); + Flowable merge = Flowable.mergeArray(f.onBackpressureBuffer(), f.onBackpressureBuffer(), f.onBackpressureBuffer()); TestSubscriber ts = new TestSubscriber<>(); merge.subscribe(ts); @@ -626,7 +627,8 @@ public void onNext(Integer t) { } }; - Flowable.merge(f1.take(Flowable.bufferSize() * 2), f2.take(Flowable.bufferSize() * 2)).subscribe(testSubscriber); + Flowable.mergeArray(f1.take(Flowable.bufferSize() * 2), f2.take(Flowable.bufferSize() * 2)) + .subscribe(testSubscriber); testSubscriber.awaitDone(5, TimeUnit.SECONDS); if (!testSubscriber.errors().isEmpty()) { testSubscriber.errors().getFirst().printStackTrace(); @@ -662,7 +664,8 @@ public void onNext(Integer t) { } }; - Flowable.merge(f1.take(Flowable.bufferSize() * 2), Flowable.just(-99)).subscribe(testSubscriber); + Flowable.mergeArray(f1.take(Flowable.bufferSize() * 2), Flowable.just(-99)) + .subscribe(testSubscriber); testSubscriber.awaitDone(10, TimeUnit.SECONDS); List onNextEvents = testSubscriber.values(); @@ -708,7 +711,9 @@ public void onNext(Integer t) { } }; - Flowable.merge(f1.take(Flowable.bufferSize() * 2), f2.take(Flowable.bufferSize() * 2)).observeOn(Schedulers.computation()).subscribe(testSubscriber); + Flowable.mergeArray(f1.take(Flowable.bufferSize() * 2), f2.take(Flowable.bufferSize() * 2)) + .observeOn(Schedulers.computation()) + .subscribe(testSubscriber); testSubscriber.awaitDone(10, TimeUnit.SECONDS); if (!testSubscriber.errors().isEmpty()) { testSubscriber.errors().getFirst().printStackTrace(); @@ -962,7 +967,7 @@ public void mergeManyAsyncSingle() { @Test public void shouldCompleteAfterApplyingBackpressure_NormalPath() { - Flowable source = Flowable.mergeDelayError(Flowable.just(Flowable.range(1, 2))); + Flowable source = Flowable.merge(Flowable.just(Flowable.range(1, 2)), StandardConcurrentBufferedConfig.DELAY_ERRORS); TestSubscriberEx subscriber = new TestSubscriberEx<>(0L); source.subscribe(subscriber); subscriber.request(3); // 1, 2, - with request(2) we get the 1 and 2 but not the @@ -972,7 +977,7 @@ public void shouldCompleteAfterApplyingBackpressure_NormalPath() { @Test public void shouldCompleteAfterApplyingBackpressure_FastPath() { - Flowable source = Flowable.mergeDelayError(Flowable.just(Flowable.just(1))); + Flowable source = Flowable.merge(Flowable.just(Flowable.just(1)), StandardConcurrentBufferedConfig.DELAY_ERRORS); TestSubscriberEx subscriber = new TestSubscriberEx<>(0L); source.subscribe(subscriber); subscriber.request(2); // 1, - should work as per .._NormalPath above @@ -983,7 +988,9 @@ public void shouldCompleteAfterApplyingBackpressure_FastPath() { @Test public void shouldNotCompleteIfThereArePendingScalarSynchronousEmissionsWhenTheLastInnerSubscriberCompletes() { TestScheduler scheduler = new TestScheduler(); - Flowable source = Flowable.mergeDelayError(Flowable.just(1L), Flowable.timer(1, TimeUnit.SECONDS, scheduler).skip(1)); + Flowable source = Flowable.mergeArray( + StandardConcurrentBufferedConfig.DELAY_ERRORS, + Flowable.just(1L), Flowable.timer(1, TimeUnit.SECONDS, scheduler).skip(1)); TestSubscriberEx subscriber = new TestSubscriberEx<>(0L); source.subscribe(subscriber); scheduler.advanceTimeBy(1, TimeUnit.SECONDS); @@ -1000,7 +1007,8 @@ public void shouldNotCompleteIfThereArePendingScalarSynchronousEmissionsWhenTheL @Test public void delayedErrorsShouldBeEmittedWhenCompleteAfterApplyingBackpressure_NormalPath() { Throwable exception = new Throwable(); - Flowable source = Flowable.mergeDelayError(Flowable.range(1, 2), Flowable.error(exception)); + Flowable source = Flowable.mergeArray(StandardConcurrentBufferedConfig.DELAY_ERRORS, + Flowable.range(1, 2), Flowable.error(exception)); TestSubscriberEx subscriber = new TestSubscriberEx<>(0L); source.subscribe(subscriber); subscriber.request(3); // 1, 2, @@ -1012,7 +1020,8 @@ public void delayedErrorsShouldBeEmittedWhenCompleteAfterApplyingBackpressure_No @Test public void delayedErrorsShouldBeEmittedWhenCompleteAfterApplyingBackpressure_FastPath() { Throwable exception = new Throwable(); - Flowable source = Flowable.mergeDelayError(Flowable.just(1), Flowable.error(exception)); + Flowable source = Flowable.mergeArray(StandardConcurrentBufferedConfig.DELAY_ERRORS, + Flowable.just(1), Flowable.error(exception)); TestSubscriberEx subscriber = new TestSubscriberEx<>(0L); source.subscribe(subscriber); subscriber.request(2); // 1, @@ -1023,7 +1032,7 @@ public void delayedErrorsShouldBeEmittedWhenCompleteAfterApplyingBackpressure_Fa @Test public void shouldNotCompleteWhileThereAreStillScalarSynchronousEmissionsInTheQueue() { - Flowable source = Flowable.merge(Flowable.just(1), Flowable.just(2)); + Flowable source = Flowable.mergeArray(Flowable.just(1), Flowable.just(2)); TestSubscriber subscriber = new TestSubscriber<>(1L); source.subscribe(subscriber); subscriber.assertValue(1); @@ -1034,7 +1043,9 @@ public void shouldNotCompleteWhileThereAreStillScalarSynchronousEmissionsInTheQu @Test public void shouldNotReceivedDelayedErrorWhileThereAreStillScalarSynchronousEmissionsInTheQueue() { Throwable exception = new Throwable(); - Flowable source = Flowable.mergeDelayError(Flowable.just(1), Flowable.just(2), Flowable.error(exception)); + Flowable source = Flowable.mergeArray( + StandardConcurrentBufferedConfig.DELAY_ERRORS, + Flowable.just(1), Flowable.just(2), Flowable.error(exception)); TestSubscriberEx subscriber = new TestSubscriberEx<>(0L); subscriber.request(1); source.subscribe(subscriber); @@ -1048,7 +1059,9 @@ public void shouldNotReceivedDelayedErrorWhileThereAreStillScalarSynchronousEmis @Test public void shouldNotReceivedDelayedErrorWhileThereAreStillNormalEmissionsInTheQueue() { Throwable exception = new Throwable(); - Flowable source = Flowable.mergeDelayError(Flowable.range(1, 2), Flowable.range(3, 2), Flowable.error(exception)); + Flowable source = Flowable.mergeArray( + StandardConcurrentBufferedConfig.DELAY_ERRORS, + Flowable.range(1, 2), Flowable.range(3, 2), Flowable.error(exception)); TestSubscriberEx subscriber = new TestSubscriberEx<>(0L); subscriber.request(3); source.subscribe(subscriber); @@ -1220,7 +1233,7 @@ public void onNext(Integer t) { @Test public void negativeMaxConcurrent() { try { - Flowable.merge(Arrays.asList(Flowable.just(1), Flowable.just(2)), -1); + Flowable.merge(Arrays.asList(Flowable.just(1), Flowable.just(2)), new StandardConcurrentBufferedConfig(-1)); fail("Expected IllegalArgumentException"); } catch (IllegalArgumentException e) { assertEquals("maxConcurrency > 0 required but it was -1", e.getMessage()); @@ -1230,7 +1243,7 @@ public void negativeMaxConcurrent() { @Test public void zeroMaxConcurrent() { try { - Flowable.merge(Arrays.asList(Flowable.just(1), Flowable.just(2)), 0); + Flowable.merge(Arrays.asList(Flowable.just(1), Flowable.just(2)), new StandardConcurrentBufferedConfig(0)); fail("Expected IllegalArgumentException"); } catch (IllegalArgumentException e) { assertEquals("maxConcurrency > 0 required but it was 0", e.getMessage()); @@ -1241,7 +1254,8 @@ public void zeroMaxConcurrent() { public void mergeConcurrentJustJust() { TestSubscriber ts = TestSubscriber.create(); - Flowable.merge(Flowable.just(Flowable.just(1)), 5).subscribe(ts); + Flowable.merge(Flowable.just(Flowable.just(1)), new StandardConcurrentBufferedConfig(5)) + .subscribe(ts); ts.assertValue(1); ts.assertNoErrors(); @@ -1252,7 +1266,8 @@ public void mergeConcurrentJustJust() { public void mergeConcurrentJustRange() { TestSubscriber ts = TestSubscriber.create(); - Flowable.merge(Flowable.just(Flowable.range(1, 5)), 5).subscribe(ts); + Flowable.merge(Flowable.just(Flowable.range(1, 5)), new StandardConcurrentBufferedConfig(5)) + .subscribe(ts); ts.assertValues(1, 2, 3, 4, 5); ts.assertNoErrors(); @@ -1267,7 +1282,8 @@ public void mergeArrayMaxConcurrent() { PublishProcessor pp1 = PublishProcessor.create(); PublishProcessor pp2 = PublishProcessor.create(); - Flowable.mergeArray(1, 128, new Flowable[] { pp1, pp2 }).subscribe(ts); + Flowable.mergeArray(new StandardConcurrentBufferedConfig(ErrorMode.IMMEDIATE, 1, 128), new Flowable[] { pp1, pp2 }) + .subscribe(ts); assertTrue("ps1 has no subscribers?!", pp1.hasSubscribers()); assertFalse("ps2 has subscribers?!", pp2.hasSubscribers()); @@ -1406,7 +1422,7 @@ public void mergeErrors() { Flowable source1 = Flowable.error(new TestException("First")); Flowable source2 = Flowable.error(new TestException("Second")); - Flowable.merge(source1, source2) + Flowable.mergeArray(source1, source2) .to(TestHelper.testConsumer()) .assertFailureAndMessage(TestException.class, "First"); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableObserveOnTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableObserveOnTest.java index 50d5f9fb59a..8b261f2bf8d 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableObserveOnTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableObserveOnTest.java @@ -19,25 +19,24 @@ import java.util.*; import java.util.concurrent.*; +import java.util.concurrent.Flow.*; import java.util.concurrent.atomic.*; import org.junit.Test; import org.mockito.InOrder; -import static java.util.concurrent.Flow.*; import io.reactivex.rxjava4.annotations.Nullable; import io.reactivex.rxjava4.core.*; -import io.reactivex.rxjava4.disposables.*; +import io.reactivex.rxjava4.core.config.StandardBufferedConfig; +import io.reactivex.rxjava4.disposables.Disposable; import io.reactivex.rxjava4.exceptions.*; -import io.reactivex.rxjava4.functions.*; +import io.reactivex.rxjava4.functions.Function; import io.reactivex.rxjava4.internal.functions.Functions; import io.reactivex.rxjava4.internal.operators.flowable.FlowableObserveOn.BaseObserveOnSubscriber; import io.reactivex.rxjava4.internal.schedulers.ImmediateThinScheduler; import io.reactivex.rxjava4.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava4.observers.TestObserver; -import io.reactivex.rxjava4.operators.QueueFuseable; -import io.reactivex.rxjava4.operators.QueueSubscription; -import io.reactivex.rxjava4.operators.SimpleQueue; +import io.reactivex.rxjava4.operators.*; import io.reactivex.rxjava4.plugins.RxJavaPlugins; import io.reactivex.rxjava4.processors.*; import io.reactivex.rxjava4.schedulers.*; @@ -707,7 +706,7 @@ public void errorDelayed() { TestSubscriber ts = TestSubscriber.create(0); - source.observeOn(s, true).subscribe(ts); + source.observeOn(s, new StandardBufferedConfig(true)).subscribe(ts); ts.assertNoValues(); ts.assertNoErrors(); @@ -741,7 +740,8 @@ public void errorDelayedAsync() { TestSubscriber ts = TestSubscriber.create(); - source.observeOn(Schedulers.computation(), true).subscribe(ts); + source.observeOn(Schedulers.computation(), new StandardBufferedConfig(true)) + .subscribe(ts); ts.awaitDone(2, TimeUnit.SECONDS); ts.assertValues(1, 2, 3); @@ -782,7 +782,8 @@ public void fixedReplenishPattern() { Flowable.range(1, 100) .doOnRequest(requests::add) - .observeOn(test, false, 16).subscribe(ts); + .observeOn(test, new StandardBufferedConfig(false, 16)) + .subscribe(ts); test.advanceTimeBy(1, TimeUnit.SECONDS); ts.request(20); @@ -806,7 +807,7 @@ public void bufferSizesWork() { for (int i = 1; i <= 1024; i = i * 2) { TestSubscriber ts = TestSubscriber.create(); - Flowable.range(1, 1000 * 1000).observeOn(Schedulers.computation(), false, i) + Flowable.range(1, 1000 * 1000).observeOn(Schedulers.computation(), new StandardBufferedConfig(false, i)) .subscribe(ts); ts.awaitDone(5, TimeUnit.SECONDS); @@ -847,7 +848,7 @@ public void rebatchRequestsArgumentCheck() { @Test public void delayError() { Flowable.range(1, 5).concatWith(Flowable.error(new TestException())) - .observeOn(Schedulers.computation(), true) + .observeOn(Schedulers.computation(), new StandardBufferedConfig(true)) .doOnNext(v -> { if (v == 1) { Thread.sleep(100); @@ -1083,7 +1084,8 @@ public void inputAsyncFusedError() { public void inputAsyncFusedErrorDelayed() { UnicastProcessor up = UnicastProcessor.create(); - TestSubscriber ts = up.observeOn(Schedulers.single(), true).test(); + TestSubscriber ts = up.observeOn(Schedulers.single(), new StandardBufferedConfig(true)) + .test(); up.onError(new TestException()); @@ -1144,7 +1146,7 @@ public void inputOutputAsyncFusedErrorDelayed() { UnicastProcessor up = UnicastProcessor.create(); - up.observeOn(Schedulers.single(), true) + up.observeOn(Schedulers.single(), new StandardBufferedConfig(true)) .subscribe(ts); up.onError(new TestException()); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureBufferStrategyTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureBufferStrategyTest.java index 85d2d06bdae..ae9fe82d904 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureBufferStrategyTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureBufferStrategyTest.java @@ -14,7 +14,6 @@ package io.reactivex.rxjava4.internal.operators.flowable; import static io.reactivex.rxjava4.core.BackpressureOverflowStrategy.*; -import static io.reactivex.rxjava4.internal.functions.Functions.EMPTY_ACTION; import static org.junit.Assert.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; @@ -27,7 +26,6 @@ import io.reactivex.rxjava4.core.*; import io.reactivex.rxjava4.exceptions.*; import io.reactivex.rxjava4.functions.*; -import io.reactivex.rxjava4.internal.functions.Functions; import io.reactivex.rxjava4.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava4.processors.PublishProcessor; import io.reactivex.rxjava4.subscribers.*; @@ -39,9 +37,9 @@ public class FlowableOnBackpressureBufferStrategyTest extends RxJavaTest { public void backpressureWithBufferDropOldest() throws InterruptedException { int bufferSize = 3; final AtomicInteger droppedCount = new AtomicInteger(0); - Action incrementOnDrop = droppedCount::incrementAndGet; TestSubscriber ts = createTestSubscriber(); - Flowable.fromPublisher(send500ValuesAndComplete.onBackpressureBuffer(bufferSize, incrementOnDrop, DROP_OLDEST)) + Flowable.fromPublisher(send500ValuesAndComplete.onBackpressureBuffer(bufferSize, DROP_OLDEST, + _ -> droppedCount.getAndIncrement())) .subscribe(ts); // we request 10 but only 3 should come from the buffer ts.request(10); @@ -80,9 +78,9 @@ public void onNext(Long t) { public void backpressureWithBufferDropLatest() throws InterruptedException { int bufferSize = 3; final AtomicInteger droppedCount = new AtomicInteger(0); - Action incrementOnDrop = droppedCount::incrementAndGet; TestSubscriber ts = createTestSubscriber(); - Flowable.fromPublisher(send500ValuesAndComplete.onBackpressureBuffer(bufferSize, incrementOnDrop, DROP_LATEST)) + Flowable.fromPublisher(send500ValuesAndComplete.onBackpressureBuffer(bufferSize, DROP_LATEST, + _ -> droppedCount.getAndIncrement())) .subscribe(ts); // we request 10 but only 3 should come from the buffer ts.request(10); @@ -109,25 +107,25 @@ public void backpressureWithBufferDropLatest() throws InterruptedException { @Test(expected = IllegalArgumentException.class) public void backpressureBufferNegativeCapacity() throws InterruptedException { - Flowable.empty().onBackpressureBuffer(-1, EMPTY_ACTION , DROP_OLDEST); + Flowable.empty().onBackpressureBuffer(-1, DROP_OLDEST); } @Test(expected = IllegalArgumentException.class) public void backpressureBufferZeroCapacity() throws InterruptedException { - Flowable.empty().onBackpressureBuffer(0, EMPTY_ACTION , DROP_OLDEST); + Flowable.empty().onBackpressureBuffer(0, DROP_OLDEST); } @Test public void dispose() { TestHelper.checkDisposed(Flowable.just(1) - .onBackpressureBuffer(16, Functions.EMPTY_ACTION, BackpressureOverflowStrategy.ERROR)); + .onBackpressureBuffer(16, BackpressureOverflowStrategy.ERROR)); } @Test public void error() { Flowable .error(new TestException()) - .onBackpressureBuffer(16, Functions.EMPTY_ACTION, BackpressureOverflowStrategy.ERROR) + .onBackpressureBuffer(16, BackpressureOverflowStrategy.ERROR) .test() .assertFailure(TestException.class); } @@ -135,41 +133,31 @@ public void error() { @Test public void overflowError() { Flowable.range(1, 20) - .onBackpressureBuffer(8, Functions.EMPTY_ACTION, BackpressureOverflowStrategy.ERROR) + .onBackpressureBuffer(8, BackpressureOverflowStrategy.ERROR) .test(0L) .assertFailure(MissingBackpressureException.class); } @Test public void badSource() { - TestHelper.checkBadSourceFlowable(f -> f.onBackpressureBuffer(8, Functions.EMPTY_ACTION, BackpressureOverflowStrategy.ERROR), false, 1, 1, 1); + TestHelper.checkBadSourceFlowable(f -> f.onBackpressureBuffer(8, BackpressureOverflowStrategy.ERROR), false, 1, 1, 1); } @Test public void doubleOnSubscribe() { - TestHelper.checkDoubleOnSubscribeFlowable(f -> f.onBackpressureBuffer(8, Functions.EMPTY_ACTION, BackpressureOverflowStrategy.ERROR)); - } - - @Test - public void overflowCrashes() { - Flowable.range(1, 20) - .onBackpressureBuffer(8, () -> { - throw new TestException(); - }, BackpressureOverflowStrategy.DROP_OLDEST) - .test(0L) - .assertFailure(TestException.class); + TestHelper.checkDoubleOnSubscribeFlowable(f -> f.onBackpressureBuffer(8, BackpressureOverflowStrategy.ERROR)); } @Test public void badRequest() { TestHelper.assertBadRequestReported(Flowable.just(1) - .onBackpressureBuffer(16, Functions.EMPTY_ACTION, BackpressureOverflowStrategy.ERROR)); + .onBackpressureBuffer(16, BackpressureOverflowStrategy.ERROR)); } @Test public void empty() { Flowable.empty() - .onBackpressureBuffer(16, Functions.EMPTY_ACTION, BackpressureOverflowStrategy.ERROR) + .onBackpressureBuffer(16, BackpressureOverflowStrategy.ERROR) .test(0L) .assertResult(); } @@ -177,24 +165,16 @@ public void empty() { @Test public void justTake() { Flowable.just(1) - .onBackpressureBuffer(16, Functions.EMPTY_ACTION, BackpressureOverflowStrategy.ERROR) + .onBackpressureBuffer(16, BackpressureOverflowStrategy.ERROR) .take(1) .test() .assertResult(1); } - @Test - public void overflowNullAction() { - Flowable.range(1, 5) - .onBackpressureBuffer(1, null, BackpressureOverflowStrategy.DROP_OLDEST) - .test(0L) - .assertEmpty(); - } - @Test public void cancelOnDrain() { Flowable.range(1, 5) - .onBackpressureBuffer(10, null, BackpressureOverflowStrategy.DROP_OLDEST) + .onBackpressureBuffer(10, BackpressureOverflowStrategy.DROP_OLDEST) .takeUntil(_ -> true) .test(0L) .assertEmpty() @@ -209,7 +189,7 @@ public void onDroppedNormalDropOldest() throws Throwable { @SuppressWarnings("unchecked") Consumer onDropped = mock(Consumer.class); - TestSubscriber ts = pp.onBackpressureBuffer(1, null, BackpressureOverflowStrategy.DROP_OLDEST, onDropped) + TestSubscriber ts = pp.onBackpressureBuffer(1, BackpressureOverflowStrategy.DROP_OLDEST, onDropped) .test(0L); ts.assertEmpty(); @@ -233,7 +213,7 @@ public void onDroppedNormalDropLatest() throws Throwable { @SuppressWarnings("unchecked") Consumer onDropped = mock(Consumer.class); - TestSubscriber ts = pp.onBackpressureBuffer(2, null, BackpressureOverflowStrategy.DROP_LATEST, onDropped) + TestSubscriber ts = pp.onBackpressureBuffer(2, BackpressureOverflowStrategy.DROP_LATEST, onDropped) .test(0L); ts.assertEmpty(); @@ -259,7 +239,7 @@ public void onDroppedNormalError() throws Throwable { @SuppressWarnings("unchecked") Consumer onDropped = mock(Consumer.class); - TestSubscriber ts = pp.onBackpressureBuffer(1, null, BackpressureOverflowStrategy.ERROR, onDropped) + TestSubscriber ts = pp.onBackpressureBuffer(1, BackpressureOverflowStrategy.ERROR, onDropped) .test(0L); ts.assertEmpty(); @@ -282,7 +262,7 @@ public void onDroppedCrash() throws Throwable { Consumer onDropped = _ -> { throw new TestException(); }; - TestSubscriberEx ts = pp.onBackpressureBuffer(1, null, BackpressureOverflowStrategy.DROP_OLDEST, onDropped) + TestSubscriberEx ts = pp.onBackpressureBuffer(1, BackpressureOverflowStrategy.DROP_OLDEST, onDropped) .subscribeWith(new TestSubscriberEx<>(0L)); ts.assertEmpty(); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureBufferTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureBufferTest.java index d20feb2cb38..3d4c6941df0 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureBufferTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableOnBackpressureBufferTest.java @@ -24,6 +24,7 @@ import org.junit.Test; import io.reactivex.rxjava4.core.*; +import io.reactivex.rxjava4.core.config.OnBackpressureBufferConfig; import io.reactivex.rxjava4.exceptions.*; import io.reactivex.rxjava4.functions.*; import io.reactivex.rxjava4.internal.functions.Functions; @@ -99,12 +100,12 @@ public void onNext(Long t) { @Test(expected = IllegalArgumentException.class) public void fixBackpressureBufferNegativeCapacity() throws InterruptedException { - Flowable.empty().onBackpressureBuffer(-1); + Flowable.empty().onBackpressureBuffer(new OnBackpressureBufferConfig<>(-1)); } @Test(expected = IllegalArgumentException.class) public void fixBackpressureBufferZeroCapacity() throws InterruptedException { - Flowable.empty().onBackpressureBuffer(0); + Flowable.empty().onBackpressureBuffer(new OnBackpressureBufferConfig<>(0)); } @Test @@ -134,7 +135,7 @@ public void onNext(Long t) { ts.request(100); infinite.subscribeOn(Schedulers.computation()) - .onBackpressureBuffer(500, backpressureCallback::countDown) + .onBackpressureBuffer(new OnBackpressureBufferConfig<>(500, _ -> backpressureCallback.countDown())) /*.take(1000)*/ .subscribe(ts); l1.await(); @@ -159,7 +160,7 @@ public void onNext(Long t) { } }); - private static final Action THROWS_NON_FATAL = () -> { + private static final Consumer THROWS_NON_FATAL = _ -> { throw new RuntimeException(); }; @@ -170,7 +171,7 @@ public void nonFatalExceptionThrownByOnOverflowIsNotReportedByUpstream() { infinite .subscribeOn(Schedulers.computation()) .doOnError(_ -> errorOccurred.set(true)) - .onBackpressureBuffer(1, THROWS_NON_FATAL) + .onBackpressureBuffer(new OnBackpressureBufferConfig<>(1, THROWS_NON_FATAL)) .subscribe(ts); ts.awaitDone(5, TimeUnit.SECONDS); assertFalse(errorOccurred.get()); @@ -180,7 +181,7 @@ public void nonFatalExceptionThrownByOnOverflowIsNotReportedByUpstream() { public void maxSize() { TestSubscriber ts = TestSubscriber.create(0); - Flowable.range(1, 10).onBackpressureBuffer(1).subscribe(ts); + Flowable.range(1, 10).onBackpressureBuffer(new OnBackpressureBufferConfig<>(1)).subscribe(ts); ts.assertNoValues(); ts.assertError(MissingBackpressureException.class); @@ -189,19 +190,19 @@ public void maxSize() { @Test(expected = IllegalArgumentException.class) public void fixBackpressureBufferNegativeCapacity2() throws InterruptedException { - Flowable.empty().onBackpressureBuffer(-1); + Flowable.empty().onBackpressureBuffer(new OnBackpressureBufferConfig<>(-1)); } @Test(expected = IllegalArgumentException.class) public void fixBackpressureBufferZeroCapacity2() throws InterruptedException { - Flowable.empty().onBackpressureBuffer(0); + Flowable.empty().onBackpressureBuffer(new OnBackpressureBufferConfig<>(0)); } @Test public void noDelayError() { Flowable.just(1).concatWith(Flowable.error(new TestException())) - .onBackpressureBuffer(false) + .onBackpressureBuffer(new OnBackpressureBufferConfig<>(false)) .test(0L) .assertFailure(TestException.class); } @@ -209,7 +210,7 @@ public void noDelayError() { @Test public void delayError() { TestSubscriber ts = Flowable.just(1).concatWith(Flowable.error(new TestException())) - .onBackpressureBuffer(true) + .onBackpressureBuffer(new OnBackpressureBufferConfig<>(true)) .test(0L) .assertEmpty(); @@ -221,7 +222,7 @@ public void delayError() { @Test public void delayErrorBuffer() { TestSubscriber ts = Flowable.just(1).concatWith(Flowable.error(new TestException())) - .onBackpressureBuffer(16, true) + .onBackpressureBuffer(new OnBackpressureBufferConfig<>(16, true)) .test(0L) .assertEmpty(); @@ -275,7 +276,7 @@ public void fusedPreconsume() throws Exception { @Test public void emptyDelayError() { Flowable.empty() - .onBackpressureBuffer(true) + .onBackpressureBuffer(new OnBackpressureBufferConfig<>(true)) .test() .assertResult(); } @@ -297,7 +298,7 @@ public void fusedNoConcurrentCleanDueToCancel() { try { final PublishProcessor pp = PublishProcessor.create(); - TestObserver to = pp.onBackpressureBuffer(4, false, true) + TestObserver to = pp.onBackpressureBuffer(new OnBackpressureBufferConfig<>(4, false, true)) .observeOn(Schedulers.cached()) .map(Functions.identity()) .observeOn(Schedulers.single()) @@ -340,7 +341,8 @@ public void onDroppedNormal() throws Throwable { @SuppressWarnings("unchecked") Consumer onDropped = mock(Consumer.class); - TestSubscriber ts = pp.onBackpressureBuffer(1, false, false, () -> { }, onDropped) + TestSubscriber ts = pp.onBackpressureBuffer( + new OnBackpressureBufferConfig<>(1, false, false, onDropped)) .test(0L); ts.assertEmpty(); @@ -363,7 +365,7 @@ public void onDroppedCrash() throws Throwable { Consumer onDropped = _ -> { throw new TestException(); }; - TestSubscriberEx ts = pp.onBackpressureBuffer(1, false, false, () -> { }, onDropped) + TestSubscriberEx ts = pp.onBackpressureBuffer(new OnBackpressureBufferConfig<>(1, false, false, onDropped)) .subscribeWith(new TestSubscriberEx<>(0L)); ts.assertEmpty(); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowablePublishTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowablePublishTest.java index cc9f3faa5e9..a4e05a87ff6 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowablePublishTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowablePublishTest.java @@ -102,7 +102,7 @@ public Integer apply(Integer i) { }).doOnComplete(() -> System.out.println("^^^^^^^^^^^^^ completed SLOW")); TestSubscriber ts = new TestSubscriber<>(); - Flowable.merge(fast, slow).subscribe(ts); + Flowable.mergeArray(fast, slow).subscribe(ts); is.connect(); ts.awaitDone(5, TimeUnit.SECONDS); ts.assertNoErrors(); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableReplayEagerTruncateTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableReplayEagerTruncateTest.java index 9ba9e1a0680..0a32f95f833 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableReplayEagerTruncateTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableReplayEagerTruncateTest.java @@ -30,6 +30,7 @@ import io.reactivex.rxjava4.annotations.NonNull; import io.reactivex.rxjava4.core.*; import io.reactivex.rxjava4.core.Scheduler.Worker; +import io.reactivex.rxjava4.core.config.StandardBufferedConfig; import io.reactivex.rxjava4.disposables.Disposable; import io.reactivex.rxjava4.exceptions.TestException; import io.reactivex.rxjava4.flowables.ConnectableFlowable; @@ -918,7 +919,7 @@ public void asyncComeAndGo() { .subscribeOn(Schedulers.cached()); Flowable cached = source.replay().autoConnect(); - Flowable output = cached.observeOn(Schedulers.computation(), false, 1024); + Flowable output = cached.observeOn(Schedulers.computation(), new StandardBufferedConfig(false, 1024)); List> list = new ArrayList<>(100); for (int i = 0; i < 100; i++) { diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableReplayTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableReplayTest.java index 9e8dd850b41..76470bd2034 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableReplayTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableReplayTest.java @@ -30,6 +30,7 @@ import io.reactivex.rxjava4.annotations.NonNull; import io.reactivex.rxjava4.core.*; import io.reactivex.rxjava4.core.Scheduler.Worker; +import io.reactivex.rxjava4.core.config.StandardBufferedConfig; import io.reactivex.rxjava4.disposables.Disposable; import io.reactivex.rxjava4.exceptions.TestException; import io.reactivex.rxjava4.flowables.ConnectableFlowable; @@ -937,7 +938,7 @@ public void asyncComeAndGo() { .subscribeOn(Schedulers.cached()); Flowable cached = source.replay().autoConnect(); - Flowable output = cached.observeOn(Schedulers.computation(), false, 1024); + Flowable output = cached.observeOn(Schedulers.computation(), new StandardBufferedConfig(false, 1024)); List> list = new ArrayList<>(100); for (int i = 0; i < 100; i++) { diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableSampleTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableSampleTest.java index 0c7e708f870..76d3c3a2ff0 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableSampleTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableSampleTest.java @@ -24,6 +24,7 @@ import static java.util.concurrent.Flow.*; import io.reactivex.rxjava4.core.*; +import io.reactivex.rxjava4.core.config.SampleConfig; import io.reactivex.rxjava4.exceptions.*; import io.reactivex.rxjava4.functions.Function; import io.reactivex.rxjava4.internal.subscriptions.BooleanSubscription; @@ -304,7 +305,7 @@ public void backpressureOverflowWithOtherPublisher() { @Test public void emitLastTimed() { Flowable.just(1) - .sample(1, TimeUnit.DAYS, true) + .sample(1, TimeUnit.DAYS, Schedulers.computation(), SampleConfig.EMIT_LAST) .test() .assertResult(1); } @@ -312,7 +313,7 @@ public void emitLastTimed() { @Test public void emitLastTimedEmpty() { Flowable.empty() - .sample(1, TimeUnit.DAYS, true) + .sample(1, TimeUnit.DAYS, Schedulers.computation(), SampleConfig.EMIT_LAST) .test() .assertResult(); } @@ -320,7 +321,7 @@ public void emitLastTimedEmpty() { @Test public void emitLastTimedCustomScheduler() { Flowable.just(1) - .sample(1, TimeUnit.DAYS, Schedulers.single(), true) + .sample(1, TimeUnit.DAYS, Schedulers.single(), SampleConfig.EMIT_LAST) .test() .assertResult(1); } @@ -332,7 +333,7 @@ public void emitLastTimedRunCompleteRace() { final PublishProcessor pp = PublishProcessor.create(); - TestSubscriber ts = pp.sample(1, TimeUnit.SECONDS, scheduler, true) + TestSubscriber ts = pp.sample(1, TimeUnit.SECONDS, scheduler, SampleConfig.EMIT_LAST) .test(); pp.onNext(1); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableSequenceEqualTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableSequenceEqualTest.java index 4e4404f511f..b5be0ab9834 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableSequenceEqualTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableSequenceEqualTest.java @@ -17,13 +17,14 @@ import static org.mockito.Mockito.*; import java.util.List; +import java.util.concurrent.Flow.Subscriber; import java.util.concurrent.TimeUnit; import org.junit.Test; import org.mockito.InOrder; -import static java.util.concurrent.Flow.*; import io.reactivex.rxjava4.core.*; +import io.reactivex.rxjava4.core.config.SequenceEqualConfig; import io.reactivex.rxjava4.exceptions.*; import io.reactivex.rxjava4.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava4.observers.TestObserver; @@ -114,9 +115,9 @@ public void withEmpty3Flowable() { public void withEqualityErrorFlowable() { Flowable flowable = Flowable.sequenceEqual( Flowable.just("one"), Flowable.just("one"), - (_, _) -> { + new SequenceEqualConfig<>((_, _) -> { throw new TestException(); - }).toFlowable(); + })).toFlowable(); verifyError(flowable); } @@ -199,9 +200,9 @@ public void withEmpty3() { public void withEqualityError() { Single single = Flowable.sequenceEqual( Flowable.just("one"), Flowable.just("one"), - (_, _) -> { + new SequenceEqualConfig<>((_, _) -> { throw new TestException(); - }); + })); verifyError(single); } @@ -247,7 +248,7 @@ private void verifyError(Single single) { @Test public void prefetch() { - Flowable.sequenceEqual(Flowable.range(1, 20), Flowable.range(1, 20), 2) + Flowable.sequenceEqual(Flowable.range(1, 20), Flowable.range(1, 20), new SequenceEqualConfig<>(2)) .test() .assertResult(true); } @@ -313,7 +314,7 @@ public void disposedFlowable() { @Test public void prefetchFlowable() { - Flowable.sequenceEqual(Flowable.range(1, 20), Flowable.range(1, 20), 2) + Flowable.sequenceEqual(Flowable.range(1, 20), Flowable.range(1, 20), new SequenceEqualConfig<>(2)) .toFlowable() .test() .assertResult(true); @@ -384,7 +385,7 @@ protected void subscribeActual(Subscriber s) { s.onNext(i); } } - }, 8) + }, new SequenceEqualConfig<>(8)) .toFlowable() .test() .assertFailure(MissingBackpressureException.class); @@ -401,7 +402,7 @@ protected void subscribeActual(Subscriber s) { s.onError(new TestException("First")); s.onError(new TestException("Second")); } - }, 8) + }, new SequenceEqualConfig<>(8)) .toFlowable() .to(TestHelper.testConsumer()) .assertFailureAndMessage(TestException.class, "First"); @@ -473,7 +474,7 @@ protected void subscribeActual(Subscriber s) { s.onNext(i); } } - }, 8) + }, new SequenceEqualConfig<>(8)) .test() .assertFailure(MissingBackpressureException.class); } @@ -489,7 +490,7 @@ protected void subscribeActual(Subscriber s) { s.onError(new TestException("First")); s.onError(new TestException("Second")); } - }, 8) + }, new SequenceEqualConfig<>(8)) .to(TestHelper.testConsumer()) .assertFailureAndMessage(TestException.class, "First"); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableSkipLastTimedTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableSkipLastTimedTest.java index 906e1fc9706..0ad8aabeb41 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableSkipLastTimedTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableSkipLastTimedTest.java @@ -16,13 +16,14 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; +import java.util.concurrent.Flow.Subscriber; import java.util.concurrent.TimeUnit; import org.junit.Test; import org.mockito.InOrder; -import static java.util.concurrent.Flow.*; import io.reactivex.rxjava4.core.*; +import io.reactivex.rxjava4.core.config.StandardBufferedConfig; import io.reactivex.rxjava4.exceptions.TestException; import io.reactivex.rxjava4.functions.Function; import io.reactivex.rxjava4.processors.PublishProcessor; @@ -164,7 +165,7 @@ public void skipLastTimedDefaultScheduler() { @Test public void skipLastTimedDefaultSchedulerDelayError() { Flowable.just(1).concatWith(Flowable.just(2).delay(500, TimeUnit.MILLISECONDS)) - .skipLast(300, TimeUnit.MILLISECONDS, true) + .skipLast(300, TimeUnit.MILLISECONDS, Schedulers.computation(), StandardBufferedConfig.DELAY_ERRORS) .test() .awaitDone(5, TimeUnit.SECONDS) .assertResult(1); @@ -173,7 +174,7 @@ public void skipLastTimedDefaultSchedulerDelayError() { @Test public void skipLastTimedCustomSchedulerDelayError() { Flowable.just(1).concatWith(Flowable.just(2).delay(500, TimeUnit.MILLISECONDS)) - .skipLast(300, TimeUnit.MILLISECONDS, Schedulers.cached(), true) + .skipLast(300, TimeUnit.MILLISECONDS, Schedulers.cached(), StandardBufferedConfig.DELAY_ERRORS) .test() .awaitDone(5, TimeUnit.SECONDS) .assertResult(1); @@ -208,7 +209,7 @@ public void onNextDisposeRace() { @Test public void errorDelayed() { Flowable.error(new TestException()) - .skipLast(1, TimeUnit.DAYS, new TestScheduler(), true) + .skipLast(1, TimeUnit.DAYS, new TestScheduler(), StandardBufferedConfig.DELAY_ERRORS) .test() .assertFailure(TestException.class); } @@ -227,7 +228,7 @@ public void take() { public void observeOn() { Flowable.range(1, 1000) .skipLast(0, TimeUnit.SECONDS) - .observeOn(Schedulers.single(), false, 16) + .observeOn(Schedulers.single(), new StandardBufferedConfig(false, 16)) .to(TestHelper.testConsumer()) .awaitDone(5, TimeUnit.SECONDS) .assertSubscribed() @@ -245,7 +246,7 @@ public void badRequest() { public void delayErrorMoreWork() { PublishProcessor pp = PublishProcessor.create(); - TestSubscriber ts = pp.skipLast(0, TimeUnit.MILLISECONDS, true) + TestSubscriber ts = pp.skipLast(0, TimeUnit.MILLISECONDS, Schedulers.computation(), StandardBufferedConfig.DELAY_ERRORS) .doOnNext(v -> { if (v == 1) { pp.onNext(1); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableSwitchTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableSwitchTest.java index 16f7962a0f4..23e66613516 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableSwitchTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableSwitchTest.java @@ -18,16 +18,17 @@ import static org.mockito.Mockito.*; import java.util.*; +import java.util.concurrent.Flow.*; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.*; import org.junit.*; import org.mockito.InOrder; -import static java.util.concurrent.Flow.*; import io.reactivex.rxjava4.core.*; +import io.reactivex.rxjava4.core.config.StandardBufferedConfig; import io.reactivex.rxjava4.exceptions.*; -import io.reactivex.rxjava4.functions.*; +import io.reactivex.rxjava4.functions.Function; import io.reactivex.rxjava4.internal.functions.Functions; import io.reactivex.rxjava4.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava4.internal.util.ExceptionHelper; @@ -498,7 +499,7 @@ public void secondaryRequestsDontOverflow() throws InterruptedException { public void delayErrors() { PublishProcessor> source = PublishProcessor.create(); - TestSubscriberEx ts = source.switchMapDelayError(Functions.>identity()) + TestSubscriberEx ts = source.switchMap(Functions.>identity(), StandardBufferedConfig.DELAY_ERRORS) .to(TestHelper.testConsumer()); ts.assertNoValues() @@ -534,7 +535,7 @@ public void switchOnNextPrefetch() { Flowable source = Flowable.range(1, 10).hide().doOnNext(list::add); - Flowable.switchOnNext(Flowable.just(source).hide(), 2) + Flowable.switchOnNext(Flowable.just(source).hide(), new StandardBufferedConfig(2)) .test(1); assertEquals(Arrays.asList(1, 2, 3), list); @@ -546,7 +547,7 @@ public void switchOnNextDelayError() { Flowable source = Flowable.range(1, 10).hide().doOnNext(list::add); - Flowable.switchOnNextDelayError(Flowable.just(source).hide()) + Flowable.switchOnNext(Flowable.just(source).hide(), StandardBufferedConfig.DELAY_ERRORS) .test(1); assertEquals(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), list); @@ -558,7 +559,7 @@ public void switchOnNextDelayErrorPrefetch() { Flowable source = Flowable.range(1, 10).hide().doOnNext(list::add); - Flowable.switchOnNextDelayError(Flowable.just(source).hide(), 2) + Flowable.switchOnNext(Flowable.just(source).hide(), new StandardBufferedConfig(2)) .test(1); assertEquals(Arrays.asList(1, 2, 3), list); @@ -568,7 +569,7 @@ public void switchOnNextDelayErrorPrefetch() { public void switchOnNextDelayErrorWithError() { PublishProcessor> pp = PublishProcessor.create(); - TestSubscriber ts = Flowable.switchOnNextDelayError(pp).test(); + TestSubscriber ts = Flowable.switchOnNext(pp, StandardBufferedConfig.DELAY_ERRORS).test(); pp.onNext(Flowable.just(1)); pp.onNext(Flowable.error(new TestException())); @@ -582,7 +583,7 @@ public void switchOnNextDelayErrorWithError() { public void switchOnNextDelayErrorBufferSize() { PublishProcessor> pp = PublishProcessor.create(); - TestSubscriber ts = Flowable.switchOnNextDelayError(pp, 2).test(); + TestSubscriber ts = Flowable.switchOnNext(pp, new StandardBufferedConfig(2)).test(); pp.onNext(Flowable.just(1)); pp.onNext(Flowable.range(2, 4)); @@ -594,13 +595,13 @@ public void switchOnNextDelayErrorBufferSize() { @Test public void switchMapDelayErrorEmptySource() { assertSame(Flowable.empty(), Flowable.empty() - .switchMapDelayError((Function>) _ -> Flowable.just(1), 16)); + .switchMap((Function>) _ -> Flowable.just(1), new StandardBufferedConfig(true, 16))); } @Test public void switchMapDelayErrorJustSource() { Flowable.just(0) - .switchMapDelayError((Function>) _ -> Flowable.just(1), 16) + .switchMap((Function>) _ -> Flowable.just(1), new StandardBufferedConfig(true, 16)) .test() .assertResult(1); @@ -609,13 +610,13 @@ public void switchMapDelayErrorJustSource() { @Test public void switchMapErrorEmptySource() { assertSame(Flowable.empty(), Flowable.empty() - .switchMap((Function>) _ -> Flowable.just(1), 16)); + .switchMap((Function>) _ -> Flowable.just(1), new StandardBufferedConfig(16))); } @Test public void switchMapJustSource() { Flowable.just(0) - .switchMap((Function>) _ -> Flowable.just(1), 16) + .switchMap((Function>) _ -> Flowable.just(1), new StandardBufferedConfig(16)) .test() .assertResult(1); @@ -852,7 +853,7 @@ public void scalarMap() { @Test public void scalarMapDelayError() { - Flowable.switchOnNextDelayError(Flowable.just(Flowable.just(1))) + Flowable.switchOnNext(Flowable.just(Flowable.just(1)), StandardBufferedConfig.DELAY_ERRORS) .test() .assertResult(1); } @@ -881,7 +882,7 @@ protected void subscribeActual(Subscriber s) { s.onNext(i); } } - }), 8) + }), new StandardBufferedConfig(8)) .test(1L) .assertFailure(QueueOverflowException.class, 0); } @@ -1077,7 +1078,7 @@ public void innerCompletedBackpressureBoundary() { @Test public void innerCompletedDelayError() { BehaviorProcessor.createDefault(Flowable.empty().hide()) - .switchMapDelayError(v -> v) + .switchMap(v -> v, StandardBufferedConfig.DELAY_ERRORS) .test() .assertEmpty() ; @@ -1089,7 +1090,7 @@ public void innerCompletedBackpressureBoundaryDelayError() { TestSubscriber ts = BehaviorProcessor.createDefault(pp) .onBackpressureBuffer() - .switchMapDelayError(v -> v) + .switchMap(v -> v, StandardBufferedConfig.DELAY_ERRORS) .test(1L) ; diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableTakeLastTimedTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableTakeLastTimedTest.java index f57ab202122..344cd7d36ff 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableTakeLastTimedTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableTakeLastTimedTest.java @@ -259,7 +259,7 @@ public void takeLastTime() { @Test public void takeLastTimeDelayError() { Flowable.just(1, 2).concatWith(Flowable.error(new TestException())) - .takeLast(1, TimeUnit.MINUTES, true) + .takeLast(1, TimeUnit.MINUTES, Schedulers.computation(), StandardBufferedConfig.DELAY_ERRORS) .test() .assertFailure(TestException.class, 1, 2); } @@ -267,7 +267,7 @@ public void takeLastTimeDelayError() { @Test public void takeLastTimeDelayErrorCustomScheduler() { Flowable.just(1, 2).concatWith(Flowable.error(new TestException())) - .takeLast(1, TimeUnit.MINUTES, Schedulers.cached(), true) + .takeLast(1, TimeUnit.MINUTES, Schedulers.cached(), StandardBufferedConfig.DELAY_ERRORS) .test() .assertFailure(TestException.class, 1, 2); } @@ -309,7 +309,7 @@ public void cancelCompleteRace() { @Test public void emptyDelayError() { Flowable.empty() - .takeLast(1, TimeUnit.DAYS, true) + .takeLast(1, TimeUnit.DAYS, Schedulers.computation(), StandardBufferedConfig.DELAY_ERRORS) .test() .assertResult(); } diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableThrottleLatestTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableThrottleLatestTest.java index bf684eca3c8..20be724c778 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableThrottleLatestTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableThrottleLatestTest.java @@ -18,12 +18,14 @@ import java.util.concurrent.TimeUnit; import org.junit.Test; + import io.reactivex.rxjava4.core.*; +import io.reactivex.rxjava4.core.config.SampleConfig; import io.reactivex.rxjava4.exceptions.*; -import io.reactivex.rxjava4.functions.*; +import io.reactivex.rxjava4.functions.Action; import io.reactivex.rxjava4.internal.subscriptions.EmptySubscription; import io.reactivex.rxjava4.processors.PublishProcessor; -import io.reactivex.rxjava4.schedulers.TestScheduler; +import io.reactivex.rxjava4.schedulers.*; import io.reactivex.rxjava4.subscribers.TestSubscriber; import io.reactivex.rxjava4.testsupport.*; @@ -48,7 +50,7 @@ public void range() { @Test public void rangeEmitLatest() { Flowable.range(1, 5) - .throttleLatest(1, TimeUnit.MINUTES, true) + .throttleLatest(1, TimeUnit.MINUTES, Schedulers.computation(), new SampleConfig<>(true)) .test() .assertResult(1, 5); } @@ -130,7 +132,8 @@ public void normalEmitLast() { TestScheduler sch = new TestScheduler(); PublishProcessor pp = PublishProcessor.create(); - TestSubscriber ts = pp.throttleLatest(1, TimeUnit.SECONDS, sch, true).test(); + TestSubscriber ts = pp.throttleLatest(1, TimeUnit.SECONDS, sch, new SampleConfig<>(true)) + .test(); pp.onNext(1); @@ -198,7 +201,7 @@ public void missingBackpressureExceptionLatest() throws Throwable { TestSubscriber ts = Flowable.just(1, 2) .concatWith(Flowable.never()) .doOnCancel(onCancel) - .throttleLatest(1, TimeUnit.SECONDS, sch, true) + .throttleLatest(1, TimeUnit.SECONDS, sch, new SampleConfig<>(true)) .test(1); sch.advanceTimeBy(1, TimeUnit.SECONDS); @@ -217,7 +220,7 @@ public void missingBackpressureExceptionLatestComplete() throws Throwable { TestSubscriber ts = pp .doOnCancel(onCancel) - .throttleLatest(1, TimeUnit.SECONDS, sch, true) + .throttleLatest(1, TimeUnit.SECONDS, sch, new SampleConfig<>(true)) .test(1); pp.onNext(1); @@ -283,7 +286,7 @@ public void onDroppedBasicNoEmitLast() { TestSubscriber drops = new TestSubscriber<>(); drops.onSubscribe(EmptySubscription.INSTANCE); - TestSubscriber ts = pp.throttleLatest(1, TimeUnit.SECONDS, sch, false, drops::onNext) + TestSubscriber ts = pp.throttleLatest(1, TimeUnit.SECONDS, sch, new SampleConfig<>(false, drops::onNext)) .test(); ts.assertEmpty(); @@ -326,7 +329,7 @@ public void onDroppedBasicNoEmitLastDropLast() { TestSubscriber drops = new TestSubscriber<>(); drops.onSubscribe(EmptySubscription.INSTANCE); - TestSubscriber ts = pp.throttleLatest(1, TimeUnit.SECONDS, sch, false, drops::onNext) + TestSubscriber ts = pp.throttleLatest(1, TimeUnit.SECONDS, sch, new SampleConfig<>(false, drops::onNext)) .test(); ts.assertEmpty(); @@ -364,7 +367,7 @@ public void onDroppedBasicEmitLast() { TestSubscriber drops = new TestSubscriber<>(); drops.onSubscribe(EmptySubscription.INSTANCE); - TestSubscriber ts = pp.throttleLatest(1, TimeUnit.SECONDS, sch, true, drops::onNext) + TestSubscriber ts = pp.throttleLatest(1, TimeUnit.SECONDS, sch, new SampleConfig<>(true, drops::onNext)) .test(); ts.assertEmpty(); @@ -406,11 +409,11 @@ public void onDroppedBasicNoEmitLastFirstDropCrash() throws Throwable { TestSubscriber ts = pp .doOnCancel(whenDisposed) - .throttleLatest(1, TimeUnit.SECONDS, sch, false, d -> { + .throttleLatest(1, TimeUnit.SECONDS, sch, new SampleConfig<>(false, d -> { if (d == 2) { throw new TestException("forced"); } - }) + })) .test(); ts.assertEmpty(); @@ -445,7 +448,7 @@ public void onDroppedBasicNoEmitLastOnErrorDropCrash() throws Throwable { TestSubscriberEx ts = pp .doOnCancel(whenDisposed) - .throttleLatest(1, TimeUnit.SECONDS, sch, false, d -> { throw new TestException("forced " + d); }) + .throttleLatest(1, TimeUnit.SECONDS, sch, new SampleConfig<>(false, d -> { throw new TestException("forced " + d); })) .subscribeWith(new TestSubscriberEx<>()); ts.assertEmpty(); @@ -482,7 +485,7 @@ public void onDroppedBasicEmitLastOnErrorDropCrash() throws Throwable { TestSubscriberEx ts = pp .doOnCancel(whenDisposed) - .throttleLatest(1, TimeUnit.SECONDS, sch, true, d -> { throw new TestException("forced " + d); }) + .throttleLatest(1, TimeUnit.SECONDS, sch, new SampleConfig<>(true, d -> { throw new TestException("forced " + d); })) .subscribeWith(new TestSubscriberEx<>()); ts.assertEmpty(); @@ -514,7 +517,7 @@ public void onDroppedBasicNoEmitLastNoLastToDrop() { TestSubscriber drops = new TestSubscriber<>(); drops.onSubscribe(EmptySubscription.INSTANCE); - TestSubscriber ts = pp.throttleLatest(1, TimeUnit.SECONDS, sch, false, drops::onNext) + TestSubscriber ts = pp.throttleLatest(1, TimeUnit.SECONDS, sch, new SampleConfig<>(false, drops::onNext)) .test(); ts.assertEmpty(); @@ -541,7 +544,7 @@ public void onDroppedErrorNoEmitLastNoLastToDrop() { TestSubscriber drops = new TestSubscriber<>(); drops.onSubscribe(EmptySubscription.INSTANCE); - TestSubscriber ts = pp.throttleLatest(1, TimeUnit.SECONDS, sch, false, drops::onNext) + TestSubscriber ts = pp.throttleLatest(1, TimeUnit.SECONDS, sch, new SampleConfig<>(false, drops::onNext)) .test(); ts.assertEmpty(); @@ -572,7 +575,7 @@ public void onDroppedHasLastNoEmitLastDropCrash() throws Throwable { TestSubscriberEx ts = pp .doOnCancel(whenDisposed) - .throttleLatest(1, TimeUnit.SECONDS, sch, false, d -> { throw new TestException("forced " + d); }) + .throttleLatest(1, TimeUnit.SECONDS, sch, new SampleConfig<>(false, d -> { throw new TestException("forced " + d); })) .subscribeWith(new TestSubscriberEx<>()); ts.assertEmpty(); @@ -609,7 +612,7 @@ public void onDroppedDisposeDrops() throws Throwable { TestSubscriberEx ts = pp .doOnCancel(whenDisposed) - .throttleLatest(1, TimeUnit.SECONDS, sch, false, drops::onNext) + .throttleLatest(1, TimeUnit.SECONDS, sch, new SampleConfig<>(false, drops::onNext)) .subscribeWith(new TestSubscriberEx<>()); ts.assertEmpty(); @@ -647,7 +650,7 @@ public void onDroppedDisposeNoDrops() throws Throwable { TestSubscriberEx ts = pp .doOnCancel(whenDisposed) - .throttleLatest(1, TimeUnit.SECONDS, sch, false, drops::onNext) + .throttleLatest(1, TimeUnit.SECONDS, sch, new SampleConfig<>(false, drops::onNext)) .subscribeWith(new TestSubscriberEx<>()); ts.assertEmpty(); @@ -679,7 +682,7 @@ public void onDroppedDisposeCrashesDrop() throws Throwable { TestSubscriberEx ts = pp .doOnCancel(whenDisposed) - .throttleLatest(1, TimeUnit.SECONDS, sch, false, d -> { throw new TestException("forced " + d); }) + .throttleLatest(1, TimeUnit.SECONDS, sch, new SampleConfig<>(false, d -> { throw new TestException("forced " + d); })) .subscribeWith(new TestSubscriberEx<>()); ts.assertEmpty(); @@ -719,7 +722,7 @@ public void onDroppedBackpressured() throws Throwable { TestSubscriber ts = pp .doOnCancel(whenDisposed) - .throttleLatest(1, TimeUnit.SECONDS, sch, false, drops::onNext) + .throttleLatest(1, TimeUnit.SECONDS, sch, new SampleConfig<>(false, drops::onNext)) .test(0L); ts.assertEmpty(); @@ -748,7 +751,7 @@ public void onDroppedBackpressuredDropCrash() throws Throwable { TestSubscriberEx ts = pp .doOnCancel(whenDisposed) - .throttleLatest(1, TimeUnit.SECONDS, sch, false, d -> { throw new TestException("forced " + d); }) + .throttleLatest(1, TimeUnit.SECONDS, sch, new SampleConfig<>(false, d -> { throw new TestException("forced " + d); })) .subscribeWith(new TestSubscriberEx<>(0L)); ts.assertEmpty(); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableWindowWithSizeTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableWindowWithSizeTest.java index 7dfb8f664db..6f451d830df 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableWindowWithSizeTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableWindowWithSizeTest.java @@ -26,6 +26,7 @@ import io.reactivex.rxjava4.core.*; import io.reactivex.rxjava4.core.Flowable; +import io.reactivex.rxjava4.core.config.StandardConcurrentBufferedConfig; import io.reactivex.rxjava4.exceptions.TestException; import io.reactivex.rxjava4.functions.*; import io.reactivex.rxjava4.internal.subscriptions.BooleanSubscription; @@ -145,7 +146,7 @@ public void windowUnsubscribeOverlappingAsyncSource() { .doOnNext(_ -> count.incrementAndGet()) .observeOn(Schedulers.computation()) .window(5, 4) - .take(2), 128) + .take(2), new StandardConcurrentBufferedConfig(128)) .subscribe(ts); ts.awaitDone(500, TimeUnit.MILLISECONDS); ts.assertTerminated(); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableZipTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableZipTest.java index 5b9c3fc33e3..5ad1dc347e1 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableZipTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableZipTest.java @@ -20,13 +20,14 @@ import java.lang.reflect.*; import java.util.*; import java.util.concurrent.*; +import java.util.concurrent.Flow.*; import java.util.concurrent.atomic.AtomicInteger; import org.junit.*; import org.mockito.InOrder; -import static java.util.concurrent.Flow.*; import io.reactivex.rxjava4.core.*; +import io.reactivex.rxjava4.core.config.StandardBufferedConfig; import io.reactivex.rxjava4.exceptions.*; import io.reactivex.rxjava4.functions.*; import io.reactivex.rxjava4.internal.functions.Functions; @@ -1180,7 +1181,8 @@ public void zip2DelayError() { Flowable error2 = Flowable.error(new TestException("Two")); Flowable source2 = Flowable.range(1, 2).concatWith(error2); - TestSubscriberEx ts = Flowable.zip(source1, source2, (BiFunction) (a, b) -> "" + a + b, true) + TestSubscriberEx ts = Flowable.zip(source1, source2, + (BiFunction) (a, b) -> "" + a + b, new StandardBufferedConfig(true)) .to(TestHelper.testConsumer()) .assertFailure(CompositeException.class, "11", "22"); @@ -1198,7 +1200,8 @@ public void zip2DelayErrorPrefetch() { Flowable error2 = Flowable.error(new TestException("Two")); Flowable source2 = Flowable.range(1, 2).concatWith(error2); - TestSubscriberEx ts = Flowable.zip(source1, source2, (BiFunction) (a, b) -> "" + a + b, true, 1) + TestSubscriberEx ts = Flowable.zip(source1, source2, + (BiFunction) (a, b) -> "" + a + b, new StandardBufferedConfig(true, 1)) .to(TestHelper.testConsumer()) .assertFailure(CompositeException.class, "11", "22"); @@ -1212,7 +1215,7 @@ public void zip2DelayErrorPrefetch() { public void zip2Prefetch() { Flowable.zip(Flowable.range(1, 9), Flowable.range(21, 9), - (BiFunction) (a, b) -> "" + a + b, false, 2 + (BiFunction) (a, b) -> "" + a + b, new StandardBufferedConfig(false, 2) ) .takeLast(1) .test() @@ -1221,7 +1224,9 @@ public void zip2Prefetch() { @Test public void zipArrayEmpty() { - assertSame(Flowable.empty(), Flowable.zipArray(Functions.identity(), false, 16)); + assertSame(Flowable.empty(), Flowable.zipArray( + new Publisher[0], + Functions.identity(), new StandardBufferedConfig(false, 16))); } @Test @@ -1374,7 +1379,7 @@ public void singleErrorDelayed() { PublishProcessor pp1 = PublishProcessor.create(); PublishProcessor pp2 = PublishProcessor.create(); - TestSubscriberEx ts = Flowable.zip(pp1, pp2, (a, _) -> a, true) + TestSubscriberEx ts = Flowable.zip(pp1, pp2, (a, _) -> a, new StandardBufferedConfig(true)) .to(TestHelper.testConsumer()); pp1.onError(new TestException("First")); @@ -1412,7 +1417,7 @@ public void fusedInputThrows() { public void fusedInputThrowsDelayError() { Flowable.zip(Flowable.just(1).map(_ -> { throw new TestException(); - }), Flowable.just(2), Integer::sum, true) + }), Flowable.just(2), Integer::sum, new StandardBufferedConfig(true)) .test() .assertFailure(TestException.class); } @@ -1430,7 +1435,7 @@ public void fusedInputThrowsBackpressured() { public void fusedInputThrowsDelayErrorBackpressured() { Flowable.zip(Flowable.just(1).map(_ -> { throw new TestException(); - }), Flowable.just(2), Integer::sum, true) + }), Flowable.just(2), Integer::sum, new StandardBufferedConfig(true)) .test(0L) .assertFailure(TestException.class); } @@ -1563,7 +1568,7 @@ public void fusedInnerPollCrashDelayError() { Flowable.just(1) .map(_ -> { throw new TestException(); }) .compose(TestHelper.flowableStripBoundary()), - Integer::sum, true + Integer::sum, new StandardBufferedConfig(true) ) .test() .assertFailure(TestException.class); @@ -1576,7 +1581,7 @@ public void fusedInnerPollCrashRequestBoundaryDelayError() { Flowable.just(1) .map(_ -> { throw new TestException(); }) .compose(TestHelper.flowableStripBoundary()), - Integer::sum, true + Integer::sum, new StandardBufferedConfig(true) ) .test(0L) .assertFailure(TestException.class); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/mixed/FlowableConcatMapCompletableTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/mixed/FlowableConcatMapCompletableTest.java index c1a8319d0a2..f55e3c7d286 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/mixed/FlowableConcatMapCompletableTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/mixed/FlowableConcatMapCompletableTest.java @@ -16,14 +16,15 @@ import static org.junit.Assert.*; import java.util.List; +import java.util.concurrent.Flow.Subscriber; import java.util.concurrent.atomic.AtomicInteger; import org.junit.Test; -import static java.util.concurrent.Flow.*; import io.reactivex.rxjava4.core.*; +import io.reactivex.rxjava4.core.config.StandardBufferedConfig; import io.reactivex.rxjava4.exceptions.*; -import io.reactivex.rxjava4.functions.*; +import io.reactivex.rxjava4.functions.Function; import io.reactivex.rxjava4.internal.functions.Functions; import io.reactivex.rxjava4.internal.subscriptions.BooleanSubscription; import io.reactivex.rxjava4.observers.TestObserver; @@ -56,7 +57,7 @@ public void simple2() { @Test public void simpleLongPrefetch() { Flowable.range(1, 1024) - .concatMapCompletable(Functions.justFunction(Completable.complete()), 32) + .concatMapCompletable(Functions.justFunction(Completable.complete()), new StandardBufferedConfig(32)) .test() .assertResult(); } @@ -64,7 +65,7 @@ public void simpleLongPrefetch() { @Test public void simpleLongPrefetchHidden() { Flowable.range(1, 1024).hide() - .concatMapCompletable(Functions.justFunction(Completable.complete()), 32) + .concatMapCompletable(Functions.justFunction(Completable.complete()), new StandardBufferedConfig(32)) .test() .assertResult(); } @@ -88,8 +89,9 @@ public void innerError() { @Test public void innerErrorDelayed() { TestObserverEx to = Flowable.range(1, 5) - .concatMapCompletableDelayError( - _ -> Completable.error(new TestException()) + .concatMapCompletable( + _ -> Completable.error(new TestException()), + StandardBufferedConfig.DELAY_ERRORS ) .to(TestHelper.testConsumer()) .assertFailure(CompositeException.class) @@ -161,8 +163,9 @@ public void boundaryError() { PublishProcessor pp = PublishProcessor.create(); CompletableSubject cs = CompletableSubject.create(); - TestObserver to = pp.concatMapCompletableDelayError( - Functions.justFunction(cs), false).test(); + TestObserver to = pp.concatMapCompletable( + Functions.justFunction(cs), StandardBufferedConfig.DELAY_ERRORS_BOUNDARY) + .test(); to.assertEmpty(); @@ -190,13 +193,13 @@ public void endError() { final CompletableSubject cs = CompletableSubject.create(); final CompletableSubject cs2 = CompletableSubject.create(); - TestObserver to = pp.concatMapCompletableDelayError( + TestObserver to = pp.concatMapCompletable( v -> { if (v == 1) { return cs; } return cs2; - }, true, 32 + }, new StandardBufferedConfig(ErrorMode.END, 32) ) .test(); @@ -260,7 +263,7 @@ protected void subscribeActual(Subscriber s) { } } .concatMapCompletable( - Functions.justFunction(Completable.never()), 1 + Functions.justFunction(Completable.never()), new StandardBufferedConfig(1) ) .test() .assertFailure(QueueOverflowException.class); @@ -359,13 +362,15 @@ public void undeliverableUponCancel() { @Test public void undeliverableUponCancelDelayError() { TestHelper.checkUndeliverableUponCancel((FlowableConverter) upstream -> - upstream.concatMapCompletableDelayError((Function) _ -> Completable.complete().hide(), false, 2)); + upstream.concatMapCompletable((Function) _ -> Completable.complete().hide(), + new StandardBufferedConfig(ErrorMode.BOUNDARY, 2))); } @Test public void undeliverableUponCancelDelayErrorTillEnd() { TestHelper.checkUndeliverableUponCancel((FlowableConverter) upstream -> - upstream.concatMapCompletableDelayError((Function) _ -> Completable.complete().hide(), true, 2)); + upstream.concatMapCompletable((Function) _ -> Completable.complete().hide(), + new StandardBufferedConfig(ErrorMode.END, 2))); } @Test diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableDelayTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableDelayTest.java index 782150e1e7f..ebd773088c8 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableDelayTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableDelayTest.java @@ -749,7 +749,7 @@ public void delaySupplierErrors() { @Test public void delayWithTimeDelayError() throws Exception { Observable.just(1).concatWith(Observable.error(new TestException())) - .delay(100, TimeUnit.MILLISECONDS, true) + .delay(100, TimeUnit.MILLISECONDS, Schedulers.computation(), true) .test() .awaitDone(5, TimeUnit.SECONDS) .assertFailure(TestException.class, 1); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableSampleTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableSampleTest.java index 34eac338432..52253e34525 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableSampleTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableSampleTest.java @@ -22,7 +22,8 @@ import org.mockito.InOrder; import io.reactivex.rxjava4.core.*; -import io.reactivex.rxjava4.disposables.*; +import io.reactivex.rxjava4.core.config.SampleConfig; +import io.reactivex.rxjava4.disposables.Disposable; import io.reactivex.rxjava4.exceptions.TestException; import io.reactivex.rxjava4.functions.Function; import io.reactivex.rxjava4.observers.TestObserver; @@ -275,7 +276,7 @@ public void error() { @Test public void emitLastTimed() { Observable.just(1) - .sample(1, TimeUnit.DAYS, true) + .sample(1, TimeUnit.DAYS, Schedulers.computation(), SampleConfig.EMIT_LAST) .test() .assertResult(1); } @@ -283,7 +284,7 @@ public void emitLastTimed() { @Test public void emitLastTimedEmpty() { Observable.empty() - .sample(1, TimeUnit.DAYS, true) + .sample(1, TimeUnit.DAYS, Schedulers.computation(), SampleConfig.EMIT_LAST) .test() .assertResult(); } @@ -291,7 +292,7 @@ public void emitLastTimedEmpty() { @Test public void emitLastTimedCustomScheduler() { Observable.just(1) - .sample(1, TimeUnit.DAYS, Schedulers.single(), true) + .sample(1, TimeUnit.DAYS, Schedulers.single(), SampleConfig.EMIT_LAST) .test() .assertResult(1); } @@ -303,7 +304,7 @@ public void emitLastTimedRunCompleteRace() { final PublishSubject ps = PublishSubject.create(); - TestObserver to = ps.sample(1, TimeUnit.SECONDS, scheduler, true) + TestObserver to = ps.sample(1, TimeUnit.SECONDS, scheduler, SampleConfig.EMIT_LAST) .test(); ps.onNext(1); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableSequenceEqualTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableSequenceEqualTest.java index 20fdd3fe53e..ce69963959c 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableSequenceEqualTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableSequenceEqualTest.java @@ -20,7 +20,7 @@ import org.mockito.InOrder; import io.reactivex.rxjava4.core.*; -import io.reactivex.rxjava4.core.config.ObservableSequenceEqualConfig; +import io.reactivex.rxjava4.core.config.SequenceEqualConfig; import io.reactivex.rxjava4.exceptions.TestException; import io.reactivex.rxjava4.observers.TestObserver; import io.reactivex.rxjava4.subjects.PublishSubject; @@ -107,7 +107,7 @@ public void withEmpty3Observable() { public void withEqualityErrorObservable() { Observable o = Observable.sequenceEqual( Observable.just("one"), Observable.just("one"), - new ObservableSequenceEqualConfig<>((_, _) -> { + new SequenceEqualConfig<>((_, _) -> { throw new TestException(); })).toObservable(); verifyError(o); @@ -143,7 +143,7 @@ private void verifyError(Single single) { @Test public void prefetchObservable() { - Observable.sequenceEqual(Observable.range(1, 20), Observable.range(1, 20), new ObservableSequenceEqualConfig<>(2)) + Observable.sequenceEqual(Observable.range(1, 20), Observable.range(1, 20), new SequenceEqualConfig<>(2)) .toObservable() .test() .assertResult(true); @@ -233,7 +233,7 @@ public void withEmpty3() { public void withEqualityError() { Single o = Observable.sequenceEqual( Observable.just("one"), Observable.just("one"), - new ObservableSequenceEqualConfig<>((_, _) -> { + new SequenceEqualConfig<>((_, _) -> { throw new TestException(); })); verifyError(o); @@ -252,7 +252,7 @@ private void verifyResult(Observable o, boolean result) { @Test public void prefetch() { - Observable.sequenceEqual(Observable.range(1, 20), Observable.range(1, 20), new ObservableSequenceEqualConfig<>(2)) + Observable.sequenceEqual(Observable.range(1, 20), Observable.range(1, 20), new SequenceEqualConfig<>(2)) .test() .assertResult(true); } @@ -344,7 +344,7 @@ public void bothCompleteWhileComparing() { PublishSubject ps1 = PublishSubject.create(); PublishSubject ps2 = PublishSubject.create(); - TestObserver to = Observable.sequenceEqual(ps1, ps2, new ObservableSequenceEqualConfig<>((a, b) -> { + TestObserver to = Observable.sequenceEqual(ps1, ps2, new SequenceEqualConfig<>((a, b) -> { ps1.onNext(1); ps1.onComplete(); @@ -366,7 +366,7 @@ public void bothCompleteWhileComparingAsObservable() { PublishSubject ps1 = PublishSubject.create(); PublishSubject ps2 = PublishSubject.create(); - TestObserver to = Observable.sequenceEqual(ps1, ps2, new ObservableSequenceEqualConfig<>((a, b) -> { + TestObserver to = Observable.sequenceEqual(ps1, ps2, new SequenceEqualConfig<>((a, b) -> { ps1.onNext(1); ps1.onComplete(); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableSkipLastTimedTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableSkipLastTimedTest.java index 3874551b314..e416ea58cff 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableSkipLastTimedTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableSkipLastTimedTest.java @@ -22,6 +22,7 @@ import org.mockito.InOrder; import io.reactivex.rxjava4.core.*; +import io.reactivex.rxjava4.core.config.StandardBufferedConfig; import io.reactivex.rxjava4.exceptions.TestException; import io.reactivex.rxjava4.observers.TestObserver; import io.reactivex.rxjava4.schedulers.*; @@ -162,7 +163,7 @@ public void skipLastTimedDefaultScheduler() { @Test public void skipLastTimedDefaultSchedulerDelayError() { Observable.just(1).concatWith(Observable.just(2).delay(500, TimeUnit.MILLISECONDS)) - .skipLast(300, TimeUnit.MILLISECONDS, true) + .skipLast(300, TimeUnit.MILLISECONDS, Schedulers.computation(), StandardBufferedConfig.DELAY_ERRORS) .test() .awaitDone(5, TimeUnit.SECONDS) .assertResult(1); @@ -171,7 +172,7 @@ public void skipLastTimedDefaultSchedulerDelayError() { @Test public void skipLastTimedCustomSchedulerDelayError() { Observable.just(1).concatWith(Observable.just(2).delay(500, TimeUnit.MILLISECONDS)) - .skipLast(300, TimeUnit.MILLISECONDS, Schedulers.cached(), true) + .skipLast(300, TimeUnit.MILLISECONDS, Schedulers.cached(), StandardBufferedConfig.DELAY_ERRORS) .test() .awaitDone(5, TimeUnit.SECONDS) .assertResult(1); @@ -209,7 +210,8 @@ public void onCompleteDisposeDelayErrorRace() { for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { final PublishSubject ps = PublishSubject.create(); - final TestObserver to = ps.skipLast(1, TimeUnit.DAYS, scheduler, true).test(); + final TestObserver to = ps.skipLast(1, TimeUnit.DAYS, scheduler, StandardBufferedConfig.DELAY_ERRORS) + .test(); Runnable r1 = ps::onComplete; @@ -222,7 +224,7 @@ public void onCompleteDisposeDelayErrorRace() { @Test public void errorDelayed() { Observable.error(new TestException()) - .skipLast(1, TimeUnit.DAYS, new TestScheduler(), true) + .skipLast(1, TimeUnit.DAYS, new TestScheduler(), StandardBufferedConfig.DELAY_ERRORS) .test() .assertFailure(TestException.class); } @@ -259,7 +261,8 @@ public void onNextOnCompleteDisposeDelayErrorRace() { for (int i = 0; i < TestHelper.RACE_DEFAULT_LOOPS; i++) { final PublishSubject ps = PublishSubject.create(); - final TestObserver to = ps.skipLast(1, TimeUnit.DAYS, scheduler, true).test(); + final TestObserver to = ps.skipLast(1, TimeUnit.DAYS, scheduler, StandardBufferedConfig.DELAY_ERRORS) + .test(); Runnable r1 = () -> { ps.onNext(1); @@ -279,7 +282,7 @@ public void skipLastTimedDelayError() { PublishSubject source = PublishSubject.create(); // FIXME the timeunit now matters due to rounding - Observable result = source.skipLast(1000, TimeUnit.MILLISECONDS, scheduler, true); + Observable result = source.skipLast(1000, TimeUnit.MILLISECONDS, scheduler, StandardBufferedConfig.DELAY_ERRORS); Observer o = TestHelper.mockObserver(); @@ -317,7 +320,7 @@ public void skipLastTimedErrorBeforeTimeDelayError() { PublishSubject source = PublishSubject.create(); - Observable result = source.skipLast(1, TimeUnit.SECONDS, scheduler, true); + Observable result = source.skipLast(1, TimeUnit.SECONDS, scheduler, StandardBufferedConfig.DELAY_ERRORS); Observer o = TestHelper.mockObserver(); @@ -342,7 +345,7 @@ public void skipLastTimedCompleteBeforeTimeDelayError() { PublishSubject source = PublishSubject.create(); - Observable result = source.skipLast(1, TimeUnit.SECONDS, scheduler, true); + Observable result = source.skipLast(1, TimeUnit.SECONDS, scheduler, StandardBufferedConfig.DELAY_ERRORS); Observer o = TestHelper.mockObserver(); @@ -370,7 +373,7 @@ public void skipLastTimedWhenAllElementsAreValidDelayError() { PublishSubject source = PublishSubject.create(); - Observable result = source.skipLast(1, TimeUnit.MILLISECONDS, scheduler, true); + Observable result = source.skipLast(1, TimeUnit.MILLISECONDS, scheduler, StandardBufferedConfig.DELAY_ERRORS); Observer o = TestHelper.mockObserver(); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableTakeLastTimedTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableTakeLastTimedTest.java index f7817409009..4dcdc9b3d49 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableTakeLastTimedTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableTakeLastTimedTest.java @@ -222,7 +222,7 @@ public void takeLastTime() { @Test public void takeLastTimeDelayError() { Observable.just(1, 2).concatWith(Observable.error(new TestException())) - .takeLast(1, TimeUnit.MINUTES, true) + .takeLast(1, TimeUnit.MINUTES, Schedulers.computation(), StandardBufferedConfig.DELAY_ERRORS) .test() .assertFailure(TestException.class, 1, 2); } @@ -230,7 +230,7 @@ public void takeLastTimeDelayError() { @Test public void takeLastTimeDelayErrorCustomScheduler() { Observable.just(1, 2).concatWith(Observable.error(new TestException())) - .takeLast(1, TimeUnit.MINUTES, Schedulers.cached(), true) + .takeLast(1, TimeUnit.MINUTES, Schedulers.cached(), StandardBufferedConfig.DELAY_ERRORS) .test() .assertFailure(TestException.class, 1, 2); } diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableThrottleLatestTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableThrottleLatestTest.java index 548881d27d7..b4151a3bc6d 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableThrottleLatestTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableThrottleLatestTest.java @@ -20,11 +20,12 @@ import org.junit.Test; import io.reactivex.rxjava4.core.*; +import io.reactivex.rxjava4.core.config.SampleConfig; import io.reactivex.rxjava4.disposables.Disposable; import io.reactivex.rxjava4.exceptions.*; import io.reactivex.rxjava4.functions.*; import io.reactivex.rxjava4.observers.TestObserver; -import io.reactivex.rxjava4.schedulers.TestScheduler; +import io.reactivex.rxjava4.schedulers.*; import io.reactivex.rxjava4.subjects.PublishSubject; import io.reactivex.rxjava4.testsupport.*; @@ -49,7 +50,7 @@ public void range() { @Test public void rangeEmitLatest() { Observable.range(1, 5) - .throttleLatest(1, TimeUnit.MINUTES, true) + .throttleLatest(1, TimeUnit.MINUTES, Schedulers.computation(), new SampleConfig<>(true)) .test() .assertResult(1, 5); } @@ -131,7 +132,7 @@ public void normalEmitLast() { TestScheduler sch = new TestScheduler(); PublishSubject ps = PublishSubject.create(); - TestObserver to = ps.throttleLatest(1, TimeUnit.SECONDS, sch, true).test(); + TestObserver to = ps.throttleLatest(1, TimeUnit.SECONDS, sch, new SampleConfig<>(true)).test(); ps.onNext(1); @@ -228,7 +229,7 @@ public void onDroppedBasicNoEmitLast() { TestObserver drops = new TestObserver<>(); drops.onSubscribe(Disposable.empty()); - TestObserver to = ps.throttleLatest(1, TimeUnit.SECONDS, sch, false, drops::onNext) + TestObserver to = ps.throttleLatest(1, TimeUnit.SECONDS, sch, new SampleConfig<>(false, drops::onNext)) .test(); to.assertEmpty(); @@ -271,7 +272,7 @@ public void onDroppedBasicNoEmitLastDropLast() { TestObserver drops = new TestObserver<>(); drops.onSubscribe(Disposable.empty()); - TestObserver to = ps.throttleLatest(1, TimeUnit.SECONDS, sch, false, drops::onNext) + TestObserver to = ps.throttleLatest(1, TimeUnit.SECONDS, sch, new SampleConfig<>(false, drops::onNext)) .test(); to.assertEmpty(); @@ -309,7 +310,7 @@ public void onDroppedBasicEmitLast() { TestObserver drops = new TestObserver<>(); drops.onSubscribe(Disposable.empty()); - TestObserver to = ps.throttleLatest(1, TimeUnit.SECONDS, sch, true, drops::onNext) + TestObserver to = ps.throttleLatest(1, TimeUnit.SECONDS, sch, new SampleConfig<>(true, drops::onNext)) .test(); to.assertEmpty(); @@ -351,11 +352,11 @@ public void onDroppedBasicNoEmitLastFirstDropCrash() throws Throwable { TestObserver to = ps .doOnDispose(whenDisposed) - .throttleLatest(1, TimeUnit.SECONDS, sch, false, d -> { + .throttleLatest(1, TimeUnit.SECONDS, sch, new SampleConfig<>(false, d -> { if (d == 2) { throw new TestException("forced"); } - }) + })) .test(); to.assertEmpty(); @@ -390,7 +391,7 @@ public void onDroppedBasicNoEmitLastOnErrorDropCrash() throws Throwable { TestObserverEx to = ps .doOnDispose(whenDisposed) - .throttleLatest(1, TimeUnit.SECONDS, sch, false, d -> { throw new TestException("forced " + d); }) + .throttleLatest(1, TimeUnit.SECONDS, sch, new SampleConfig<>(false, d -> { throw new TestException("forced " + d); })) .subscribeWith(new TestObserverEx<>()); to.assertEmpty(); @@ -427,7 +428,7 @@ public void onDroppedBasicEmitLastOnErrorDropCrash() throws Throwable { TestObserverEx to = ps .doOnDispose(whenDisposed) - .throttleLatest(1, TimeUnit.SECONDS, sch, true, d -> { throw new TestException("forced " + d); }) + .throttleLatest(1, TimeUnit.SECONDS, sch, new SampleConfig<>(true, d -> { throw new TestException("forced " + d); })) .subscribeWith(new TestObserverEx<>()); to.assertEmpty(); @@ -459,7 +460,7 @@ public void onDroppedBasicNoEmitLastNoLastToDrop() { TestObserver drops = new TestObserver<>(); drops.onSubscribe(Disposable.empty()); - TestObserver to = ps.throttleLatest(1, TimeUnit.SECONDS, sch, false, drops::onNext) + TestObserver to = ps.throttleLatest(1, TimeUnit.SECONDS, sch, new SampleConfig<>(false, drops::onNext)) .test(); to.assertEmpty(); @@ -486,7 +487,7 @@ public void onDroppedErrorNoEmitLastNoLastToDrop() { TestObserver drops = new TestObserver<>(); drops.onSubscribe(Disposable.empty()); - TestObserver to = ps.throttleLatest(1, TimeUnit.SECONDS, sch, false, drops::onNext) + TestObserver to = ps.throttleLatest(1, TimeUnit.SECONDS, sch, new SampleConfig<>(false, drops::onNext)) .test(); to.assertEmpty(); @@ -517,7 +518,7 @@ public void onDroppedHasLastNoEmitLastDropCrash() throws Throwable { TestObserverEx to = ps .doOnDispose(whenDisposed) - .throttleLatest(1, TimeUnit.SECONDS, sch, false, d -> { throw new TestException("forced " + d); }) + .throttleLatest(1, TimeUnit.SECONDS, sch, new SampleConfig<>(false, d -> { throw new TestException("forced " + d); })) .subscribeWith(new TestObserverEx<>()); to.assertEmpty(); @@ -554,7 +555,7 @@ public void onDroppedDisposeDrops() throws Throwable { TestObserverEx to = ps .doOnDispose(whenDisposed) - .throttleLatest(1, TimeUnit.SECONDS, sch, false, drops::onNext) + .throttleLatest(1, TimeUnit.SECONDS, sch, new SampleConfig<>(false, drops::onNext)) .subscribeWith(new TestObserverEx<>()); to.assertEmpty(); @@ -592,7 +593,7 @@ public void onDroppedDisposeNoDrops() throws Throwable { TestObserverEx to = ps .doOnDispose(whenDisposed) - .throttleLatest(1, TimeUnit.SECONDS, sch, false, drops::onNext) + .throttleLatest(1, TimeUnit.SECONDS, sch, new SampleConfig<>(false, drops::onNext)) .subscribeWith(new TestObserverEx<>()); to.assertEmpty(); @@ -624,7 +625,7 @@ public void onDroppedDisposeCrashesDrop() throws Throwable { TestObserverEx to = ps .doOnDispose(whenDisposed) - .throttleLatest(1, TimeUnit.SECONDS, sch, false, d -> { throw new TestException("forced " + d); }) + .throttleLatest(1, TimeUnit.SECONDS, sch, new SampleConfig<>(false, d -> { throw new TestException("forced " + d); })) .subscribeWith(new TestObserverEx<>()); to.assertEmpty(); diff --git a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableZipTest.java b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableZipTest.java index d1da0e8d688..9936cca1ad4 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableZipTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/operators/observable/ObservableZipTest.java @@ -1103,7 +1103,7 @@ public void zip2DelayErrorPrefetch() { @Test public void zipArrayEmpty() { assertSame(Observable.empty(), Observable.zipArray( - new Observable[0], new StandardBufferedConfig(false, 16), Functions.identity())); + new Observable[0], Functions.identity(), new StandardBufferedConfig(false, 16))); } @Test diff --git a/src/test/java/io/reactivex/rxjava4/internal/schedulers/ParallelSchedulerTest.java b/src/test/java/io/reactivex/rxjava4/internal/schedulers/ParallelSchedulerTest.java index 666ef2c3b7d..40e13e42993 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/schedulers/ParallelSchedulerTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/schedulers/ParallelSchedulerTest.java @@ -23,7 +23,7 @@ import io.reactivex.rxjava4.core.*; import io.reactivex.rxjava4.core.Scheduler.Worker; -import io.reactivex.rxjava4.core.config.ParallelSchedulerConfig; +import io.reactivex.rxjava4.core.config.*; import io.reactivex.rxjava4.disposables.*; import io.reactivex.rxjava4.internal.functions.Functions; import io.reactivex.rxjava4.internal.schedulers.ParallelScheduler.TrackingParallelWorker.TrackedAction; @@ -46,7 +46,7 @@ public void normalNonTracking() { try { for (int i = 0; i < 100; i++) { Flowable.range(1, 10).hide() - .observeOn(s, false, 4) + .observeOn(s, new StandardBufferedConfig(false, 4)) .test() .awaitDone(5, TimeUnit.SECONDS) .assertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); @@ -63,7 +63,7 @@ public void normalNonTrackingVia() { try { for (int i = 0; i < 100; i++) { Flowable.range(1, 10).hide() - .observeOn(s, false, 4) + .observeOn(s, new StandardBufferedConfig(false, 4)) .test() .awaitDone(5, TimeUnit.SECONDS) .assertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); @@ -97,7 +97,7 @@ public void normalTracking() { try { for (int i = 0; i < 100; i++) { Flowable.range(1, 10).hide() - .observeOn(s, false, 4) + .observeOn(s, new StandardBufferedConfig(false, 4)) .test() .awaitDone(5, TimeUnit.SECONDS) .assertResult(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); diff --git a/src/test/java/io/reactivex/rxjava4/internal/virtual/VirtualCreateTest.java b/src/test/java/io/reactivex/rxjava4/internal/virtual/VirtualCreateTest.java index 683af0cbf67..10b69301fd6 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/virtual/VirtualCreateTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/virtual/VirtualCreateTest.java @@ -39,6 +39,7 @@ import org.junit.Test; import io.reactivex.rxjava4.core.Flowable; +import io.reactivex.rxjava4.core.config.StandardBufferedConfig; import io.reactivex.rxjava4.schedulers.Schedulers; public class VirtualCreateTest { @@ -95,7 +96,7 @@ public void backpressure() throws Throwable { e.emit(i); } }, exec) - .observeOn(Schedulers.single(), false, 2) + .observeOn(Schedulers.single(), new StandardBufferedConfig(false, 2)) .test() .awaitDone(5, TimeUnit.SECONDS) .assertValueCount(10000)); @@ -106,7 +107,7 @@ public void error() throws Throwable { withVirtual(exec -> Flowable.virtualCreate(_ -> { throw new IOException(); }, exec) - .observeOn(Schedulers.single(), false, 2) + .observeOn(Schedulers.single(), new StandardBufferedConfig(false, 2)) .test() .awaitDone(5, TimeUnit.SECONDS) .assertError(IOException.class)); diff --git a/src/test/java/io/reactivex/rxjava4/internal/virtual/VirtualCreateVirtualTest.java b/src/test/java/io/reactivex/rxjava4/internal/virtual/VirtualCreateVirtualTest.java index fac9ef1d06e..ed08977c7cf 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/virtual/VirtualCreateVirtualTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/virtual/VirtualCreateVirtualTest.java @@ -38,6 +38,7 @@ import org.junit.Test; import io.reactivex.rxjava4.core.Flowable; +import io.reactivex.rxjava4.core.config.StandardBufferedConfig; import io.reactivex.rxjava4.schedulers.Schedulers; public class VirtualCreateVirtualTest { @@ -88,7 +89,7 @@ public void backpressure() throws Throwable { e.emit(i); } }) - .observeOn(Schedulers.single(), false, 2) + .observeOn(Schedulers.single(), new StandardBufferedConfig(false, 2)) .test() .awaitDone(5, TimeUnit.SECONDS) .assertValueCount(10000) @@ -100,7 +101,7 @@ public void error() throws Throwable { Flowable.virtualCreate(_ -> { throw new IOException(); }) - .observeOn(Schedulers.single(), false, 2) + .observeOn(Schedulers.single(), new StandardBufferedConfig(false, 2)) .test() .awaitDone(5, TimeUnit.SECONDS) .assertError(IOException.class) diff --git a/src/test/java/io/reactivex/rxjava4/internal/virtual/VirtualTransformTest.java b/src/test/java/io/reactivex/rxjava4/internal/virtual/VirtualTransformTest.java index 3e073e5882a..d51f3b365f2 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/virtual/VirtualTransformTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/virtual/VirtualTransformTest.java @@ -22,6 +22,7 @@ import org.junit.Test; import io.reactivex.rxjava4.core.Flowable; +import io.reactivex.rxjava4.core.config.StandardBufferedConfig; import io.reactivex.rxjava4.schedulers.Schedulers; import io.reactivex.rxjava4.testsupport.TestHelper; @@ -75,7 +76,7 @@ public void take() throws Throwable { public void observeOn() throws Throwable { TestHelper.withVirtual(exec -> Flowable.range(1, 10000) .virtualTransform((v, e, _) -> e.emit(v), exec) - .observeOn(Schedulers.single(), false, 2) + .observeOn(Schedulers.single(), new StandardBufferedConfig(false, 2)) .test() .awaitDone(5, TimeUnit.SECONDS) .assertNoErrors() diff --git a/src/test/java/io/reactivex/rxjava4/internal/virtual/VirtualTransformVirtualTest.java b/src/test/java/io/reactivex/rxjava4/internal/virtual/VirtualTransformVirtualTest.java index 9c4b1e7153d..40f245af9cb 100644 --- a/src/test/java/io/reactivex/rxjava4/internal/virtual/VirtualTransformVirtualTest.java +++ b/src/test/java/io/reactivex/rxjava4/internal/virtual/VirtualTransformVirtualTest.java @@ -22,6 +22,7 @@ import org.junit.Test; import io.reactivex.rxjava4.core.Flowable; +import io.reactivex.rxjava4.core.config.StandardBufferedConfig; import io.reactivex.rxjava4.schedulers.Schedulers; public class VirtualTransformVirtualTest { @@ -75,7 +76,7 @@ public void take() throws Throwable { public void observeOn() throws Throwable { Flowable.range(1, 10000) .virtualTransform((v, e, _) -> e.emit(v)) - .observeOn(Schedulers.single(), false, 2) + .observeOn(Schedulers.single(), new StandardBufferedConfig(false, 2)) .test() .awaitDone(5, TimeUnit.SECONDS) .assertNoErrors() diff --git a/src/test/java/io/reactivex/rxjava4/maybe/MaybeTest.java b/src/test/java/io/reactivex/rxjava4/maybe/MaybeTest.java index 62c76f908e6..ba77f7447ef 100644 --- a/src/test/java/io/reactivex/rxjava4/maybe/MaybeTest.java +++ b/src/test/java/io/reactivex/rxjava4/maybe/MaybeTest.java @@ -2177,7 +2177,8 @@ public void fromFuture() { .assertResult() ; - Maybe.fromFuture(Flowable.error(new TestException()).delay(200, TimeUnit.MILLISECONDS, true).toFuture()) + Maybe.fromFuture(Flowable.error(new TestException()) + .delay(200, TimeUnit.MILLISECONDS, Schedulers.computation(), true).toFuture()) .test() .awaitDone(5, TimeUnit.SECONDS) .assertFailure(TestException.class) diff --git a/src/test/java/io/reactivex/rxjava4/parallel/ParallelFromPublisherTest.java b/src/test/java/io/reactivex/rxjava4/parallel/ParallelFromPublisherTest.java index 233c7533ab9..7a67fd4ec86 100644 --- a/src/test/java/io/reactivex/rxjava4/parallel/ParallelFromPublisherTest.java +++ b/src/test/java/io/reactivex/rxjava4/parallel/ParallelFromPublisherTest.java @@ -17,19 +17,19 @@ import java.util.*; import java.util.concurrent.*; +import java.util.concurrent.Flow.*; import org.junit.Test; -import static java.util.concurrent.Flow.*; import io.reactivex.rxjava4.annotations.NonNull; import io.reactivex.rxjava4.core.*; +import io.reactivex.rxjava4.core.config.StandardBufferedConfig; import io.reactivex.rxjava4.exceptions.*; -import io.reactivex.rxjava4.functions.*; +import io.reactivex.rxjava4.functions.Function; import io.reactivex.rxjava4.internal.functions.Functions; import io.reactivex.rxjava4.internal.subscribers.BasicFuseableSubscriber; import io.reactivex.rxjava4.internal.subscriptions.BooleanSubscription; -import io.reactivex.rxjava4.operators.QueueFuseable; -import io.reactivex.rxjava4.operators.QueueSubscription; +import io.reactivex.rxjava4.operators.*; import io.reactivex.rxjava4.processors.*; import io.reactivex.rxjava4.schedulers.Schedulers; import io.reactivex.rxjava4.testsupport.*; @@ -148,7 +148,7 @@ public void boundaryConfinement() { final ConcurrentHashMap processing = new ConcurrentHashMap<>(); TestSubscriberEx ts = Flowable.range(1, 10) - .observeOn(Schedulers.single(), false, 1) + .observeOn(Schedulers.single(), new StandardBufferedConfig(false, 1)) .doOnNext(_ -> between.add(Thread.currentThread().getName())) .parallel(2, 1) .runOn(Schedulers.computation(), 1) diff --git a/src/test/java/io/reactivex/rxjava4/schedulers/CachedThreadSchedulerTest.java b/src/test/java/io/reactivex/rxjava4/schedulers/CachedThreadSchedulerTest.java index ffa03018b3f..8d894b4ec91 100644 --- a/src/test/java/io/reactivex/rxjava4/schedulers/CachedThreadSchedulerTest.java +++ b/src/test/java/io/reactivex/rxjava4/schedulers/CachedThreadSchedulerTest.java @@ -40,7 +40,7 @@ public final void cachedScheduler() { Flowable f1 = Flowable.just(1, 2, 3, 4, 5); Flowable f2 = Flowable.just(6, 7, 8, 9, 10); - Flowable f = Flowable.merge(f1, f2).map(t -> { + Flowable f = Flowable.mergeArray(f1, f2).map(t -> { assertTrue(Thread.currentThread().getName().startsWith("RxCachedThreadScheduler")); return "Value_" + t + "_Thread_" + Thread.currentThread().getName(); }); diff --git a/src/test/java/io/reactivex/rxjava4/schedulers/ComputationSchedulerTests.java b/src/test/java/io/reactivex/rxjava4/schedulers/ComputationSchedulerTests.java index 2fdfe4b6332..c2e438d1820 100644 --- a/src/test/java/io/reactivex/rxjava4/schedulers/ComputationSchedulerTests.java +++ b/src/test/java/io/reactivex/rxjava4/schedulers/ComputationSchedulerTests.java @@ -95,7 +95,8 @@ public void run() { public final void computationThreadPool1() { Flowable f1 = Flowable. just(1, 2, 3, 4, 5); Flowable f2 = Flowable. just(6, 7, 8, 9, 10); - Flowable f = Flowable. merge(f1, f2).map(t -> { + Flowable f = Flowable. mergeArray(f1, f2) + .map(t -> { assertTrue(Thread.currentThread().getName().startsWith("RxComputationThreadPool")); return "Value_" + t + "_Thread_" + Thread.currentThread().getName(); }); @@ -110,7 +111,9 @@ public final void mergeWithExecutorScheduler() { Flowable f1 = Flowable. just(1, 2, 3, 4, 5); Flowable f2 = Flowable. just(6, 7, 8, 9, 10); - Flowable f = Flowable. merge(f1, f2).subscribeOn(Schedulers.computation()).map(t -> { + Flowable f = Flowable. mergeArray(f1, f2) + .subscribeOn(Schedulers.computation()) + .map(t -> { assertNotEquals(Thread.currentThread().getName(), currentThreadName); assertTrue(Thread.currentThread().getName().startsWith("RxComputationThreadPool")); return "Value_" + t + "_Thread_" + Thread.currentThread().getName(); diff --git a/src/test/java/io/reactivex/rxjava4/schedulers/ExecutorSchedulerFairTest.java b/src/test/java/io/reactivex/rxjava4/schedulers/ExecutorSchedulerFairTest.java index adb8a707733..6e7ba3deb03 100644 --- a/src/test/java/io/reactivex/rxjava4/schedulers/ExecutorSchedulerFairTest.java +++ b/src/test/java/io/reactivex/rxjava4/schedulers/ExecutorSchedulerFairTest.java @@ -23,8 +23,9 @@ import io.reactivex.rxjava4.core.*; import io.reactivex.rxjava4.core.Scheduler.Worker; +import io.reactivex.rxjava4.core.config.StandardBufferedConfig; import io.reactivex.rxjava4.disposables.Disposable; -import io.reactivex.rxjava4.functions.*; +import io.reactivex.rxjava4.functions.Function; import io.reactivex.rxjava4.internal.disposables.EmptyDisposable; import io.reactivex.rxjava4.internal.functions.Functions; import io.reactivex.rxjava4.internal.schedulers.RxThreadFactory; @@ -375,9 +376,9 @@ public void fairInterleaving() { PublishProcessor pp = PublishProcessor.create(); TestSubscriber ts = pp - .publish((Function, Flowable>) v -> Flowable.merge( - v.filter(w -> w % 2 == 0).observeOn(sch, false, 1).hide(), - v.filter(w -> w % 2 != 0).observeOn(sch, false, 1).hide() + .publish((Function, Flowable>) v -> Flowable.mergeArray( + v.filter(w -> w % 2 == 0).observeOn(sch, new StandardBufferedConfig(false, 1)).hide(), + v.filter(w -> w % 2 != 0).observeOn(sch, new StandardBufferedConfig(false, 1)).hide() )) .test(); @@ -403,7 +404,7 @@ public void fairInterleavingWithDelay() { PublishProcessor pp = PublishProcessor.create(); TestSubscriber ts = pp - .publish((Function, Flowable>) v -> Flowable.merge( + .publish((Function, Flowable>) v -> Flowable.mergeArray( v.filter(w -> w % 2 == 0).delay(0, TimeUnit.SECONDS, sch).hide(), v.filter(w -> w % 2 != 0).delay(0, TimeUnit.SECONDS, sch).hide() )) diff --git a/src/test/java/io/reactivex/rxjava4/schedulers/TrampolineSchedulerTest.java b/src/test/java/io/reactivex/rxjava4/schedulers/TrampolineSchedulerTest.java index 52698e66baa..10f6807f2f6 100644 --- a/src/test/java/io/reactivex/rxjava4/schedulers/TrampolineSchedulerTest.java +++ b/src/test/java/io/reactivex/rxjava4/schedulers/TrampolineSchedulerTest.java @@ -43,7 +43,9 @@ public final void mergeWithCurrentThreadScheduler1() { Flowable f1 = Flowable. just(1, 2, 3, 4, 5); Flowable f2 = Flowable. just(6, 7, 8, 9, 10); - Flowable f = Flowable. merge(f1, f2).subscribeOn(Schedulers.trampoline()).map(t -> { + Flowable f = Flowable. mergeArray(f1, f2) + .subscribeOn(Schedulers.trampoline()) + .map(t -> { assertEquals(Thread.currentThread().getName(), currentThreadName); return "Value_" + t + "_Thread_" + Thread.currentThread().getName(); }); diff --git a/src/test/java/io/reactivex/rxjava4/schedulers/VirtualThreadSchedulerTest.java b/src/test/java/io/reactivex/rxjava4/schedulers/VirtualThreadSchedulerTest.java index d7ea00cf097..ce0a35cbd8c 100644 --- a/src/test/java/io/reactivex/rxjava4/schedulers/VirtualThreadSchedulerTest.java +++ b/src/test/java/io/reactivex/rxjava4/schedulers/VirtualThreadSchedulerTest.java @@ -40,7 +40,8 @@ public final void virtualScheduler() { Flowable f1 = Flowable.just(1, 2, 3, 4, 5); Flowable f2 = Flowable.just(6, 7, 8, 9, 10); - Flowable f = Flowable.merge(f1, f2).map(t -> { + Flowable f = Flowable.mergeArray(f1, f2) + .map(t -> { assertTrue(Thread.currentThread().isVirtual()); return "Value_" + t + "_Thread_" + Thread.currentThread().getName(); }); diff --git a/src/test/java/io/reactivex/rxjava4/tck/MergeTckTest.java b/src/test/java/io/reactivex/rxjava4/tck/MergeTckTest.java index f60c5188527..c1e2486513b 100644 --- a/src/test/java/io/reactivex/rxjava4/tck/MergeTckTest.java +++ b/src/test/java/io/reactivex/rxjava4/tck/MergeTckTest.java @@ -24,7 +24,7 @@ public class MergeTckTest extends BaseTck { @Override public Publisher createFlowPublisher(long elements) { return - Flowable.merge( + Flowable.mergeArray( Flowable.fromIterable(iterate(elements / 2)), Flowable.fromIterable(iterate(elements - elements / 2)) ) diff --git a/src/test/java/io/reactivex/rxjava4/tck/SwitchMapDelayErrorTckTest.java b/src/test/java/io/reactivex/rxjava4/tck/SwitchMapDelayErrorTckTest.java index c7509157c67..3779f0afbec 100644 --- a/src/test/java/io/reactivex/rxjava4/tck/SwitchMapDelayErrorTckTest.java +++ b/src/test/java/io/reactivex/rxjava4/tck/SwitchMapDelayErrorTckTest.java @@ -13,10 +13,12 @@ package io.reactivex.rxjava4.tck; -import static java.util.concurrent.Flow.*; +import java.util.concurrent.Flow.Publisher; + import org.testng.annotations.Test; import io.reactivex.rxjava4.core.Flowable; +import io.reactivex.rxjava4.core.config.StandardBufferedConfig; import io.reactivex.rxjava4.internal.functions.Functions; @Test @@ -25,8 +27,8 @@ public class SwitchMapDelayErrorTckTest extends BaseTck { @Override public Publisher createFlowPublisher(long elements) { return - Flowable.just(1).switchMapDelayError(Functions.justFunction( - Flowable.fromIterable(iterate(elements))) + Flowable.just(1).switchMap(Functions.justFunction( + Flowable.fromIterable(iterate(elements))), StandardBufferedConfig.DELAY_ERRORS ) ; } diff --git a/src/test/java/io/reactivex/rxjava4/validators/CheckJavadocConfigAndArgumentTest.java b/src/test/java/io/reactivex/rxjava4/validators/CheckJavadocConfigAndArgumentTest.java new file mode 100644 index 00000000000..ab752bc4755 --- /dev/null +++ b/src/test/java/io/reactivex/rxjava4/validators/CheckJavadocConfigAndArgumentTest.java @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2016-present, RxJava Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See + * the License for the specific language governing permissions and limitations under the License. + */ + +package io.reactivex.rxjava4.validators; + +import java.io.File; +import java.nio.file.Files; +import java.util.*; + +import io.reactivex.rxjava4.core.RxJavaTest; +import org.junit.Test; + +import io.reactivex.rxjava4.testsupport.TestHelper; + +/** + * Scan the Javadocs of a source and check if mentions of other classes, + * interfaces and enums are using at-link and at-code wrapping for style. + *

+ * The check ignores HTML tag content on a line, @see and @throws entries + * and <code></code> lines. + */ +public class CheckJavadocConfigAndArgumentTest extends RxJavaTest { + + @Test + public void checkFlowable() throws Exception { + checkSource("Flowable", "io.reactivex.rxjava4.core"); + } + + @Test + public void checkCompletable() throws Exception { + checkSource("Completable", "io.reactivex.rxjava4.core"); + } + + @Test + public void checkSingle() throws Exception { + checkSource("Single", "io.reactivex.rxjava4.core"); + } + + @Test + public void checkMaybe() throws Exception { + checkSource("Maybe", "io.reactivex.rxjava4.core"); + } + + @Test + public void checkObservable() throws Exception { + checkSource("Observable", "io.reactivex.rxjava4.core"); + } + + @Test + public void checkParallelFlowable() throws Exception { + checkSource("ParallelFlowable", "io.reactivex.rxjava4.parallel"); + } + + @Test + public void checkCompositeDisposable() throws Exception { + checkSource("CompositeDisposable", "io.reactivex.rxjava4.disposables"); + } + + @Test + public void checkConnectableFlowable() throws Exception { + checkSource("ConnectableFlowable", "io.reactivex.rxjava4.flowables"); + } + + @Test + public void checkConnectableObservable() throws Exception { + checkSource("ConnectableObservable", "io.reactivex.rxjava4.observables"); + } + + @Test + public void checkSchedulers() throws Exception { + checkSource("Schedulers", "io.reactivex.rxjava4.schedulers"); + } + + static void checkSource(String baseClassName, String packageName) throws Exception { + File f = TestHelper.findSource(baseClassName, packageName); + if (f == null) { + return; + } + + StringBuilder errors = new StringBuilder(2048); + int errorCount = 0; + + List lines = Files.readAllLines(f.toPath()); + + // i = 1 skip the header Javadoc + for (int i = 1; i < lines.size(); i++) { + + if (lines.get(i).trim().equals("/**")) { + + for (int j = i + 1; j < lines.size(); j++) { + if (lines.get(j).trim().equals("*/")) { + + List subList = lines.subList(i + 1, j); + + if (subList.stream().anyMatch(s -> s.contains("@param config"))) { + + if (!subList.stream().anyMatch(s -> s.contains("@since 4."))) { + + errorCount++; + errors.append("Since 4.0.0 missing:\r\n at ") + .append(packageName) + .append(".") + .append(baseClassName) + .append(".method(") + .append(baseClassName) + .append(".java:") + .append(j) + .append(")\r\n"); + } + + if (subList.stream().anyMatch(s -> s.contains("@throws IllegalArgumentException"))) { + + for (int m = j + 1; m < lines.size(); m++) { + if (lines.get(m).isEmpty()) { + List subSubList = lines.subList(j + 1, m); + + if (!subSubList.stream().anyMatch(s -> s.contains("new IllegalArgumentException")) + && !subSubList.stream().anyMatch(s -> s.contains("verifyPositive"))) { + errorCount++; + errors.append("Unnecessary IllegalArgumentException:\r\n at ") + .append(packageName) + .append(".") + .append(baseClassName) + .append(".method(") + .append(baseClassName) + .append(".java:") + .append(j) + .append(")\r\n"); + } + + break; + } + } + } +} + i = j; + break; + } + } + } + } + + if (errorCount != 0) { + errors.insert(0, "Found " + (errorCount > ERROR_LIMIT ? ERROR_LIMIT + "+" : errorCount + "") + " cases\r\n"); + throw new AssertionError(errors.toString()); + } + } + + static String removeCurlies(String input) { + StringBuilder result = new StringBuilder(input.length()); + + boolean skip = false; + for (int i = 0; i < input.length(); i++) { + char c = input.charAt(i); + if (c == '{') { + skip = true; + } + if (!skip) { + result.append(c); + } + if (c == '}') { + skip = false; + } + } + + return result.toString(); + } + + static String stripTags(String input) { + StringBuilder result = new StringBuilder(input.length()); + result.append(input, input.length() > 1 ? 2 : 1, input.length()); + + clearTag(result, ""); + clearTag(result, "", ""); + clearTag(result, "", ""); + clearTag(result, "", ""); + clearTag(result, ""); + + return result.toString(); + } + + static void clearTag(StringBuilder builder, String startTag, String endTag) { + int k = 0; + for (;;) { + int j = builder.indexOf(startTag, k); + if (j < 0) { + break; + } + + int e = builder.indexOf(endTag, j); + if (e < 0) { + e = builder.length(); + } + + blankRange(builder, j, e); + + k = e + endTag.length(); + } + } + + static void blankRange(StringBuilder builder, int start, int end) { + for (int i = start; i < end; i++) { + int c = builder.charAt(i); + if (c != '\r' && c != '\n') { + builder.setCharAt(i, ' '); + } + } + } + + static final List NAMES = Arrays.asList( + "Flowable", "Observable", "Maybe", "Single", "Completable", "ParallelFlowable", + + "Publisher", "ObservableSource", "MaybeSource", "SingleSource", "CompletableSource", + + "FlowableSubscriber", "Subscriber", "Observer", "MaybeObserver", "SingleObserver", "CompletableObserver", + + "FlowableOperator", "ObservableOperator", "MaybeOperator", "SingleOperator", "CompletableOperator", + + "FlowableOnSubscribe", "ObservableOnSubscribe", "MaybeOnSubscribe", "SingleOnSubscribe", "CompletableOnSubscribe", + + "FlowableTransformer", "ObservableTransformer", "MaybeTransformer", "SingleTransformer", "CompletableTransformer", "ParallelTransformer", + + "FlowableConverter", "ObservableConverter", "MaybeConverter", "SingleConverter", "CompletableConverter", + + "FlowableEmitter", "ObservableEmitter", "MaybeEmitter", "SingleEmitter", "CompletableEmitter", + + "Iterable", "Stream", + + "Function", "BiFunction", "Function3", "Function4", "Function5", "Function6", "Function7", "Function8", "Function9", + + "Action", "Runnable", "Disposable", "Subscription", "Consumer", "BiConsumer", "Future", + + "Supplier", "Callable", "TimeUnit", + + "BackpressureOverflowStrategy", "ParallelFailureHandling", + + "Exception", "Throwable", "NullPointerException", "IllegalStateException", "IllegalArgumentException", "MissingBackpressureException", "UndeliverableException", + "OutOfMemoryError", "StackOverflowError", "NoSuchElementException", "ClassCastException", "CompositeException", + "RuntimeException", "Error", "TimeoutException", "OnErrorNotImplementedException", + + "false", "true", "onNext", "onError", "onComplete", "onSuccess", "onSubscribe", "null", + + "ConnectableFlowable", "ConnectableObservable", "Subject", "FlowableProcessor", "Processor", "Scheduler", + + "Optional", "CompletionStage", "Collector", "Collectors", "Schedulers", "RxJavaPlugins", "CompletableFuture", + + "Object", "Integer", "Long", "Boolean", "LongConsumer", "BooleanSupplier", + + "GroupedFlowable", "GroupedObservable", "UnicastSubject", "UnicastProcessor", + + "Notification", "Comparable", "Comparator", "Collection", + + "SafeSubscriber", "SafeObserver", + + "List", "ArrayList", "HashMap", "HashSet", "CharSequence", + + "TestSubscriber", "TestObserver", "Class", + + "ThreadFactory", "Runnable", "Executor", "ExecutorService", "Executors", "RejectedExecutionException" + ); + + static final Set ALWAYS_CODE = new HashSet<>(Arrays.asList( + "false", "true", "null", "onSuccess", "onNext", "onError", "onComplete", "onSubscribe" + )); + + static final int ERROR_LIMIT = 5000; +} diff --git a/src/test/java/io/reactivex/rxjava4/validators/CheckParamValidationTest.java b/src/test/java/io/reactivex/rxjava4/validators/CheckParamValidationTest.java index aaaf30b7b81..5b81f7a2489 100644 --- a/src/test/java/io/reactivex/rxjava4/validators/CheckParamValidationTest.java +++ b/src/test/java/io/reactivex/rxjava4/validators/CheckParamValidationTest.java @@ -139,7 +139,6 @@ public void checkParallelFlowable() { // negative time is considered as zero time addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "delay", Long.TYPE, TimeUnit.class)); - addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "delay", Long.TYPE, TimeUnit.class, Boolean.TYPE)); addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "delay", Long.TYPE, TimeUnit.class, Scheduler.class)); addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "delay", Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE)); @@ -152,10 +151,6 @@ public void checkParallelFlowable() { addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "debounce", Long.TYPE, TimeUnit.class, Scheduler.class)); addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "debounce", Long.TYPE, TimeUnit.class, Scheduler.class, Consumer.class)); - // null Action allowed - addOverride(new ParamOverride(Flowable.class, 1, ParamMode.ANY, "onBackpressureBuffer", Long.TYPE, Action.class, BackpressureOverflowStrategy.class)); - addOverride(new ParamOverride(Flowable.class, 1, ParamMode.ANY, "onBackpressureBuffer", Long.TYPE, Action.class, BackpressureOverflowStrategy.class, Consumer.class)); - // zero repeat is allowed addOverride(new ParamOverride(Flowable.class, 0, ParamMode.NON_NEGATIVE, "repeat", Long.TYPE)); @@ -191,24 +186,20 @@ public void checkParallelFlowable() { // negative time is considered as zero time addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "sample", Long.TYPE, TimeUnit.class)); - addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "sample", Long.TYPE, TimeUnit.class, Boolean.TYPE)); addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "sample", Long.TYPE, TimeUnit.class, Scheduler.class)); - addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "sample", Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE)); - addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "sample", Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE, Consumer.class)); + addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "sample", Long.TYPE, TimeUnit.class, Scheduler.class, SampleConfig.class)); // negative time is considered as zero time addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "takeLast", Long.TYPE, TimeUnit.class)); - addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "takeLast", Long.TYPE, TimeUnit.class, Boolean.TYPE)); addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "takeLast", Long.TYPE, TimeUnit.class, Scheduler.class)); - addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "takeLast", Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE)); - addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "takeLast", Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE, Integer.TYPE)); + addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "takeLast", Long.TYPE, TimeUnit.class, Scheduler.class, StandardBufferedConfig.class)); addOverride(new ParamOverride(Flowable.class, 0, ParamMode.NON_NEGATIVE, "takeLast", Long.TYPE, Long.TYPE, TimeUnit.class)); addOverride(new ParamOverride(Flowable.class, 0, ParamMode.NON_NEGATIVE, "takeLast", Long.TYPE, Long.TYPE, TimeUnit.class, Scheduler.class)); addOverride(new ParamOverride(Flowable.class, 0, ParamMode.NON_NEGATIVE, "takeLast", - Long.TYPE, Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE, Integer.TYPE)); + Long.TYPE, Long.TYPE, TimeUnit.class, Scheduler.class, StandardBufferedConfig.class)); addOverride(new ParamOverride(Flowable.class, 1, ParamMode.ANY, "takeLast", Long.TYPE, Long.TYPE, TimeUnit.class)); addOverride(new ParamOverride(Flowable.class, 1, ParamMode.ANY, "takeLast", Long.TYPE, Long.TYPE, TimeUnit.class, Scheduler.class)); - addOverride(new ParamOverride(Flowable.class, 1, ParamMode.ANY, "takeLast", Long.TYPE, Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE, Integer.TYPE)); + addOverride(new ParamOverride(Flowable.class, 1, ParamMode.ANY, "takeLast", Long.TYPE, Long.TYPE, TimeUnit.class, Scheduler.class, StandardBufferedConfig.class)); // take last 0 is allowed addOverride(new ParamOverride(Flowable.class, 0, ParamMode.NON_NEGATIVE, "takeLast", Integer.TYPE)); @@ -218,10 +209,8 @@ public void checkParallelFlowable() { // negative time is considered as zero time addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "skipLast", Long.TYPE, TimeUnit.class)); - addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "skipLast", Long.TYPE, TimeUnit.class, Boolean.TYPE)); addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "skipLast", Long.TYPE, TimeUnit.class, Scheduler.class)); - addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "skipLast", Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE)); - addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "skipLast", Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE, Integer.TYPE)); + addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "skipLast", Long.TYPE, TimeUnit.class, Scheduler.class, StandardBufferedConfig.class)); // negative time is considered as zero time addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "throttleFirst", Long.TYPE, TimeUnit.class)); @@ -236,9 +225,7 @@ public void checkParallelFlowable() { // negative time is considered as zero time addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "throttleLatest", Long.TYPE, TimeUnit.class)); addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "throttleLatest", Long.TYPE, TimeUnit.class, Scheduler.class)); - addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "throttleLatest", Long.TYPE, TimeUnit.class, Boolean.TYPE)); - addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "throttleLatest", Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE)); - addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "throttleLatest", Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE, Consumer.class)); + addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "throttleLatest", Long.TYPE, TimeUnit.class, Scheduler.class, SampleConfig.class)); // negative buffer time is considered as zero buffer time addOverride(new ParamOverride(Flowable.class, 0, ParamMode.ANY, "window", Long.TYPE, TimeUnit.class)); @@ -298,7 +285,6 @@ public void checkParallelFlowable() { // negative time is considered as zero time addOverride(new ParamOverride(Maybe.class, 0, ParamMode.ANY, "delay", Long.TYPE, TimeUnit.class)); addOverride(new ParamOverride(Maybe.class, 0, ParamMode.ANY, "delay", Long.TYPE, TimeUnit.class, Scheduler.class)); - addOverride(new ParamOverride(Maybe.class, 0, ParamMode.ANY, "delay", Long.TYPE, TimeUnit.class, Boolean.TYPE)); addOverride(new ParamOverride(Maybe.class, 0, ParamMode.ANY, "delay", Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE)); // zero repeat is allowed @@ -329,7 +315,6 @@ public void checkParallelFlowable() { // negative time is considered as zero time addOverride(new ParamOverride(Single.class, 0, ParamMode.ANY, "delay", Long.TYPE, TimeUnit.class)); - addOverride(new ParamOverride(Single.class, 0, ParamMode.ANY, "delay", Long.TYPE, TimeUnit.class, Boolean.TYPE)); addOverride(new ParamOverride(Single.class, 0, ParamMode.ANY, "delay", Long.TYPE, TimeUnit.class, Scheduler.class)); addOverride(new ParamOverride(Single.class, 0, ParamMode.ANY, "delay", Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE)); @@ -394,7 +379,6 @@ public void checkParallelFlowable() { // negative time is considered as zero time addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "delay", Long.TYPE, TimeUnit.class)); - addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "delay", Long.TYPE, TimeUnit.class, Boolean.TYPE)); addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "delay", Long.TYPE, TimeUnit.class, Scheduler.class)); addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "delay", Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE)); @@ -442,24 +426,20 @@ public void checkParallelFlowable() { // negative time is considered as zero time addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "sample", Long.TYPE, TimeUnit.class)); - addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "sample", Long.TYPE, TimeUnit.class, Boolean.TYPE)); addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "sample", Long.TYPE, TimeUnit.class, Scheduler.class)); - addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "sample", Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE)); - addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "sample", Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE, Consumer.class)); + addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "sample", Long.TYPE, TimeUnit.class, Scheduler.class, SampleConfig.class)); // negative time is considered as zero time addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "takeLast", Long.TYPE, TimeUnit.class)); - addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "takeLast", Long.TYPE, TimeUnit.class, Boolean.TYPE)); addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "takeLast", Long.TYPE, TimeUnit.class, Scheduler.class)); - addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "takeLast", Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE)); - addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "takeLast", Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE, Integer.TYPE)); + addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "takeLast", Long.TYPE, TimeUnit.class, Scheduler.class, StandardBufferedConfig.class)); addOverride(new ParamOverride(Observable.class, 0, ParamMode.NON_NEGATIVE, "takeLast", Long.TYPE, Long.TYPE, TimeUnit.class)); addOverride(new ParamOverride(Observable.class, 0, ParamMode.NON_NEGATIVE, "takeLast", Long.TYPE, Long.TYPE, TimeUnit.class, Scheduler.class)); addOverride(new ParamOverride(Observable.class, 0, ParamMode.NON_NEGATIVE, "takeLast", - Long.TYPE, Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE, Integer.TYPE)); + Long.TYPE, Long.TYPE, TimeUnit.class, Scheduler.class, StandardBufferedConfig.class)); addOverride(new ParamOverride(Observable.class, 1, ParamMode.ANY, "takeLast", Long.TYPE, Long.TYPE, TimeUnit.class)); addOverride(new ParamOverride(Observable.class, 1, ParamMode.ANY, "takeLast", Long.TYPE, Long.TYPE, TimeUnit.class, Scheduler.class)); - addOverride(new ParamOverride(Observable.class, 1, ParamMode.ANY, "takeLast", Long.TYPE, Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE, Integer.TYPE)); + addOverride(new ParamOverride(Observable.class, 1, ParamMode.ANY, "takeLast", Long.TYPE, Long.TYPE, TimeUnit.class, Scheduler.class, StandardBufferedConfig.class)); // take last 0 is allowed addOverride(new ParamOverride(Observable.class, 0, ParamMode.NON_NEGATIVE, "takeLast", Integer.TYPE)); @@ -469,10 +449,8 @@ public void checkParallelFlowable() { // negative time is considered as zero time addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "skipLast", Long.TYPE, TimeUnit.class)); - addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "skipLast", Long.TYPE, TimeUnit.class, Boolean.TYPE)); addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "skipLast", Long.TYPE, TimeUnit.class, Scheduler.class)); - addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "skipLast", Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE)); - addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "skipLast", Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE, Integer.TYPE)); + addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "skipLast", Long.TYPE, TimeUnit.class, Scheduler.class, StandardBufferedConfig.class)); // negative time is considered as zero time addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "throttleFirst", Long.TYPE, TimeUnit.class)); @@ -487,9 +465,7 @@ public void checkParallelFlowable() { // negative time is considered as zero time addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "throttleLatest", Long.TYPE, TimeUnit.class)); addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "throttleLatest", Long.TYPE, TimeUnit.class, Scheduler.class)); - addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "throttleLatest", Long.TYPE, TimeUnit.class, Boolean.TYPE)); - addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "throttleLatest", Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE)); - addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "throttleLatest", Long.TYPE, TimeUnit.class, Scheduler.class, Boolean.TYPE, Consumer.class)); + addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "throttleLatest", Long.TYPE, TimeUnit.class, Scheduler.class, SampleConfig.class)); // negative buffer time is considered as zero buffer time addOverride(new ParamOverride(Observable.class, 0, ParamMode.ANY, "window", Long.TYPE, TimeUnit.class)); @@ -618,7 +594,9 @@ public void checkParallelFlowable() { defaultValues.put(StandardBufferedConfig.class, StandardBufferedConfig.DEFAULT); defaultValues.put(StandardConcurrentConfig.class, StandardConcurrentConfig.DEFAULT); defaultValues.put(StandardConcurrentBufferedConfig.class, StandardConcurrentBufferedConfig.DEFAULT); - defaultValues.put(ObservableSequenceEqualConfig.class, ObservableSequenceEqualConfig.DEFAULT); + defaultValues.put(SequenceEqualConfig.class, SequenceEqualConfig.DEFAULT); + defaultValues.put(SampleConfig.class, SampleConfig.DEFAULT); + defaultValues.put(OnBackpressureBufferConfig.class, OnBackpressureBufferConfig.DEFAULT); // TODO insert new config record types here @@ -1170,7 +1148,9 @@ record ParamOverride(Class clazz, int index, ParamMode mode, String name, Cla try { clazz.getMethod(name, arguments); } catch (Exception ex) { - throw new AssertionError(ex); + throw new AssertionError( + clazz + "." + name + "(" + Arrays.toString(arguments) + ")", + ex); } }