1313
1414package io .reactivex .rxjava4 .core ;
1515
16- import java .lang .reflect .InvocationTargetException ;
1716import java .util .*;
1817import java .util .concurrent .*;
18+ import java .util .concurrent .atomic .AtomicLong ;
1919
2020import io .reactivex .rxjava4 .annotations .*;
2121import io .reactivex .rxjava4 .disposables .*;
2222import io .reactivex .rxjava4 .exceptions .Exceptions ;
2323import io .reactivex .rxjava4 .functions .*;
24+ import io .reactivex .rxjava4 .internal .functions .ObjectHelper ;
2425import io .reactivex .rxjava4 .internal .operators .streamable .*;
25- import io .reactivex .rxjava4 .internal .util .AwaitCoordinatorStatic ;
26+ import io .reactivex .rxjava4 .internal .util .*;
27+ import io .reactivex .rxjava4 .plugins .RxJavaPlugins ;
2628import io .reactivex .rxjava4 .schedulers .Schedulers ;
2729import io .reactivex .rxjava4 .subscribers .TestSubscriber ;
2830
@@ -75,7 +77,7 @@ default Streamer<T> stream() {
7577 @ CheckReturnValue
7678 @ NonNull
7779 static <@ NonNull T > Streamable <T > empty () {
78- return new StreamableEmpty <>();
80+ return RxJavaPlugins . onAssembly ( new StreamableEmpty <>() );
7981 }
8082
8183 /**
@@ -88,7 +90,21 @@ default Streamer<T> stream() {
8890 @ NonNull
8991 static <@ NonNull T > Streamable <T > just (@ NonNull T item ) {
9092 Objects .requireNonNull (item , "item is null" );
91- return new StreamableJust <>(item );
93+ return RxJavaPlugins .onAssembly (new StreamableJust <>(item ));
94+ }
95+
96+ /**
97+ * Streams all elements of the given items array.
98+ * @param <T> the element type of the items
99+ * @param items the array of items to stream
100+ * @return the new {@code Streamable} instance
101+ * @throws NullPointerException if {@code items} is {@code null}
102+ */
103+ @ SafeVarargs
104+ @ NonNull
105+ static <@ NonNull T > Streamable <T > fromArray (T ... items ) {
106+ Objects .requireNonNull (items , "items is null" );
107+ return RxJavaPlugins .onAssembly (new StreamableFromArray <>(items ));
92108 }
93109
94110 /**
@@ -115,7 +131,7 @@ static <T> Streamable<T> fromPublisher(@NonNull Flow.Publisher<T> source) {
115131 @ NonNull
116132 static <T > Streamable <T > fromPublisher (@ NonNull Flow .Publisher <T > source , @ NonNull ExecutorService executor ) {
117133 Objects .requireNonNull (source , "source is null" );
118- return new StreamableFromPublisher <>(source , executor );
134+ return RxJavaPlugins . onAssembly ( new StreamableFromPublisher <>(source , executor ) );
119135 }
120136
121137 /**
@@ -193,6 +209,32 @@ static <T> Streamable<T> fromPublisher(@NonNull Flow.Publisher<T> source, @NonNu
193209 }, executor );
194210 }
195211
212+ /**
213+ * Defers the creation of the actual {@code Streamable}, allowing a per streamer
214+ * state to be created along with it.
215+ * @param <T> the element type of the {@code Streamable}
216+ * @param supplier the callback that returns the actual {@code Streamable} to be streamed
217+ * @return the new {@code Streamable} instance
218+ * @throws NullPointerException if {@code supplier} is {@code null}
219+ */
220+ static <@ NonNull T > Streamable <T > defer (Supplier <? extends Streamable <? extends T >> supplier ) {
221+ Objects .requireNonNull (supplier , "supplier is null" );
222+ return RxJavaPlugins .onAssembly (new StreamableDefer <>(supplier ));
223+ }
224+
225+ /**
226+ * Creates a {@code Streamable} that signals the given {@link Throwable} immediately when it begins streaming,
227+ * ending the sequence.
228+ * @param <T> the element type of the sequence
229+ * @param throwable the {@code Throwable} to signal immediately upon streaming
230+ * @return the new {@code Streamable} instance
231+ * @throws NullPointerException if {@code throwable} is {@code null}
232+ */
233+ static <@ NonNull T > Streamable <T > error (Throwable throwable ) {
234+ Objects .requireNonNull (throwable , "throwable is null" );
235+ return RxJavaPlugins .onAssembly (new StreamableError <>(throwable ));
236+ }
237+
196238 /**
197239 * Emits the elements of each inner sequence produced by the outher sequence.
198240 * @param <T> the common element type
@@ -212,6 +254,54 @@ static <T> Streamable<T> fromPublisher(@NonNull Flow.Publisher<T> source, @NonNu
212254 }, exec );
213255 }
214256
257+ /**
258+ * Emits elements from start up to start + count exclusive.
259+ * @param start the start element
260+ * @param count the number of elements to emit
261+ * @return the new {@code Streamable} instance
262+ */
263+ static Streamable <Integer > range (int start , int count ) {
264+ if (count < 0 ) {
265+ throw new IllegalArgumentException ("count >= 0 required but it was " + count );
266+ } else
267+ if (count == 0 ) {
268+ return empty ();
269+ } else
270+ if (count == 1 ) {
271+ return just (start );
272+ } else
273+ if ((long )start + (count - 1 ) > Integer .MAX_VALUE ) {
274+ throw new IllegalArgumentException ("Integer overflow" );
275+ }
276+ return RxJavaPlugins .onAssembly (new StreamableRange (start , count ));
277+ }
278+
279+ /**
280+ * Emits elements from start up to start + count exclusive.
281+ * @param start the start element
282+ * @param count the number of elements to emit
283+ * @return the new {@code Streamable} instance
284+ */
285+ static Streamable <Long > rangeLong (long start , long count ) {
286+ if (count < 0 ) {
287+ throw new IllegalArgumentException ("count >= 0 required but it was " + count );
288+ }
289+
290+ if (count == 0 ) {
291+ return empty ();
292+ }
293+
294+ if (count == 1 ) {
295+ return just (start );
296+ }
297+
298+ long end = start + (count - 1 );
299+ if (start > 0 && end < 0 ) {
300+ throw new IllegalArgumentException ("Overflow! start + count is bigger than Long.MAX_VALUE" );
301+ }
302+ return RxJavaPlugins .onAssembly (new StreamableRangeLong (start , count ));
303+ }
304+
215305 // oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
216306 // Operators
217307 // oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
@@ -274,6 +364,25 @@ default Flowable<T> toFlowable(@NonNull ExecutorService executor) {
274364 .await (emitter .canceller ()), executor );
275365 }
276366
367+ /**
368+ * Takes at most the given number of items from the upstream and relays it to the downstream,
369+ * then cancels the rest of the sequence.
370+ * @param n the maximum number of items to relay
371+ * @return the new {@code Streamable} instance
372+ */
373+ default Streamable <T > take (long n ) {
374+ ObjectHelper .verifyPositive (n , "n" );
375+ return defer (() -> {
376+ var countdown = new AtomicLong (n );
377+ return transform ((item , emitter , stopper ) -> {
378+ emitter .emit (item );
379+ if (countdown .decrementAndGet () <= 0 ) {
380+ stopper .dispose ();
381+ }
382+ });
383+ });
384+ }
385+
277386 // oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
278387 // Consumption methods and outgoing converters
279388 // oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
@@ -324,13 +433,12 @@ default CompletionStageDisposable<Void> forEach(@NonNull Consumer<? super T> con
324433 */
325434 @ CheckReturnValue
326435 @ NonNull
327- @ SuppressWarnings ("unchecked" )
328436 default CompletionStageDisposable <Void > forEach (@ NonNull Consumer <? super T > consumer , @ NonNull DisposableContainer canceller , @ NonNull ExecutorService executor ) {
329437 Objects .requireNonNull (consumer , "consumer is null" );
330438 Objects .requireNonNull (canceller , "canceller is null" );
331439 Objects .requireNonNull (executor , "executor is null" );
332440 final Streamable <T > me = this ;
333- var future = executor . submit (() -> {
441+ var future = CompletableFuture .< Void > supplyAsync (() -> {
334442 try (var str = me .stream (canceller )) {
335443 while (!canceller .isDisposed ()) {
336444 if (str .awaitNext (canceller )) {
@@ -344,20 +452,15 @@ default CompletionStageDisposable<Void> forEach(@NonNull Consumer<? super T> con
344452 // System.out.println("Canceller status after loop: " + canceller.isDisposed());
345453 } catch (final Throwable crash ) {
346454 Exceptions .throwIfFatal (crash );
347- // System.out.println("Canceller status in error: " + canceller.isDisposed());
348- crash .printStackTrace ();
349- if (crash instanceof RuntimeException ex ) {
350- throw ex ;
351- }
352- if (crash instanceof Exception ex ) {
353- throw ex ;
455+ if (crash instanceof CompletionException ce ) {
456+ throw ExceptionHelper .wrapOrThrow (ce .getCause ());
354457 }
355- throw new InvocationTargetException (crash );
458+ throw ExceptionHelper . wrapOrThrow (crash );
356459 }
357460 return null ;
358- });
461+ }, executor );
359462 canceller .add (Disposable .fromFuture (future ));
360- return new CompletionStageDisposable <>(StreamableHelper . toCompletionStage (( Future < Void >) ( Future <?>) future ) , canceller );
463+ return new CompletionStageDisposable <>(future , canceller );
361464 }
362465
363466 /**
@@ -369,7 +472,6 @@ default CompletionStageDisposable<Void> forEach(@NonNull Consumer<? super T> con
369472 */
370473 @ CheckReturnValue
371474 @ NonNull
372- @ SuppressWarnings ("unchecked" )
373475 default CompletionStageDisposable <Void > forEach (
374476 @ NonNull BiConsumer <? super T , ? super Disposable > consumer ,
375477 @ NonNull DisposableContainer canceller ,
@@ -378,7 +480,7 @@ default CompletionStageDisposable<Void> forEach(
378480 Objects .requireNonNull (canceller , "canceller is null" );
379481 Objects .requireNonNull (executor , "executor is null" );
380482 final Streamable <T > me = this ;
381- var future = executor . submit (() -> {
483+ var future = CompletableFuture .< Void > supplyAsync (() -> {
382484 try (var str = me .stream (canceller )) {
383485 var stopper = Disposable .empty ();
384486 while (!canceller .isDisposed () && !stopper .isDisposed ()) {
@@ -394,21 +496,15 @@ default CompletionStageDisposable<Void> forEach(
394496 // System.out.println("Canceller status after loop: " + canceller.isDisposed());
395497 } catch (final Throwable crash ) {
396498 Exceptions .throwIfFatal (crash );
397- // System.out.println("Canceller status in error: " + canceller.isDisposed());
398- // crash.printStackTrace();
399- if (crash instanceof RuntimeException ex ) {
400- throw ex ;
401- }
402- if (crash instanceof Exception ex ) {
403- throw ex ;
499+ if (crash instanceof CompletionException ce ) {
500+ throw ExceptionHelper .wrapOrThrow (ce .getCause ());
404501 }
405- throw new InvocationTargetException (crash );
502+ throw ExceptionHelper . wrapOrThrow (crash );
406503 }
407504 return null ;
408505 });
409506 canceller .add (Disposable .fromFuture (future ));
410- return new CompletionStageDisposable <>(
411- StreamableHelper .toCompletionStage ((Future <Void >) (Future <?>) future ), canceller );
507+ return new CompletionStageDisposable <>(future , canceller );
412508 }
413509
414510 /**
@@ -419,9 +515,8 @@ default CompletionStageDisposable<Void> forEach(
419515 default void subscribe (@ NonNull Flow .Subscriber <? super T > subscriber , @ NonNull ExecutorService executor ) {
420516 final Streamable <T > me = this ;
421517 Flowable .<T >virtualCreate (emitter -> {
422- // System.out.println("subscribe::virtualCreate");
423- // System.out.println("subscribe::virtualCreate::forEach::emit");
424- me .forEach (emitter ::emit ).await (emitter .canceller ());
518+ me .forEach (emitter ::emit , emitter .canceller ().derive (), executor )
519+ .await (emitter .canceller ());
425520 }, executor )
426521 .subscribe (subscriber );
427522 }
@@ -433,8 +528,7 @@ default void subscribe(@NonNull Flow.Subscriber<? super T> subscriber, @NonNull
433528 default void subscribe (@ NonNull Flow .Subscriber <? super T > subscriber ) {
434529 final Streamable <T > me = this ;
435530 Flowable .<T >virtualCreate (emitter -> {
436- // System.out.println("Emitting " + v);
437- me .forEach (emitter ::emit ).await (emitter .canceller ());
531+ me .forEach (emitter ::emit ).await (emitter .canceller ());
438532 })
439533 .subscribe (subscriber );
440534 }
0 commit comments