2222import io .reactivex .rxjava4 .exceptions .Exceptions ;
2323import io .reactivex .rxjava4 .functions .Consumer ;
2424import io .reactivex .rxjava4 .internal .operators .streamable .*;
25+ import io .reactivex .rxjava4 .schedulers .Schedulers ;
2526import io .reactivex .rxjava4 .subscribers .TestSubscriber ;
2627
2728/**
@@ -79,6 +80,7 @@ default Streamer<T> stream() {
7980 * @param item the constant item to produce
8081 * @return the {@code Streamable} instance
8182 */
83+ @ NonNull
8284 static <@ NonNull T > Streamable <T > just (@ NonNull T item ) {
8385 Objects .requireNonNull (item , "item is null" );
8486 return new StreamableJust <>(item );
@@ -90,10 +92,75 @@ default Streamer<T> stream() {
9092 * @param source Flow.Publisher to convert
9193 * @return the new Streamable instance
9294 */
93- static <T > Streamable <T > fromPublisher (Flow .Publisher <T > source ) {
95+ @ NonNull
96+ static <T > Streamable <T > fromPublisher (@ NonNull Flow .Publisher <T > source ) {
9497 Objects .requireNonNull (source , "source is null" );
95- return new StreamableFromPublisher <T >(source );
98+ return fromPublisher (source , Executors .newVirtualThreadPerTaskExecutor ());
99+ }
100+
101+ /**
102+ * Convert any Flow.Publisher into a Streamable sequence.
103+ * @param <T> the element type
104+ * @param source Flow.Publisher to convert
105+ * @param executor where the conversion will run
106+ * @return the new Streamable instance
107+ */
108+ @ NonNull
109+ static <T > Streamable <T > fromPublisher (@ NonNull Flow .Publisher <T > source , @ NonNull ExecutorService executor ) {
110+ Objects .requireNonNull (source , "source is null" );
111+ return new StreamableFromPublisher <T >(source , executor );
112+ }
113+
114+ /**
115+ * Generate a sequence of values via a virtual generator callback (yielder)
116+ * which is free to block and is natively backpressured.
117+ * <p>
118+ * Runs on the {@link Schedulers#virtual()} scheduler.
119+ * @param <T> the element type
120+ * @param generator the generator to use
121+ * @return the streamable instance
122+ */
123+ @ NonNull
124+ static <@ NonNull T > Streamable <T > create (@ NonNull VirtualGenerator <T > generator ) {
125+ // FIXME native implementation
126+ return Flowable .virtualCreate (generator )
127+ .toStreamable ();
128+ }
129+
130+ /**
131+ * Generate a sequence of values via a virtual generator callback (yielder)
132+ * which is free to block and is natively backpressured.
133+ * <p>
134+ * Runs on the given scheduler.
135+ * @param <T> the element type
136+ * @param generator the generator to use
137+ * @param scheduler the scheduler to run the virtual generator on
138+ * @return the streamable instance
139+ */
140+ @ NonNull
141+ static <@ NonNull T > Streamable <T > create (@ NonNull VirtualGenerator <T > generator , @ NonNull Scheduler scheduler ) {
142+ // FIXME native implementation
143+ return Flowable .virtualCreate (generator , scheduler )
144+ .toStreamable ();
145+ }
146+
147+ /**
148+ * Generate a sequence of values via a virtual generator callback (yielder)
149+ * which is free to block and is natively backpressured.
150+ * <p>
151+ * Runs on the given executor service.
152+ * @param <T> the element type
153+ * @param generator the generator to use
154+ * @param executor the executor to run the virtual generator on
155+ * @return the streamable instance
156+ */
157+ @ NonNull
158+ static <@ NonNull T > Streamable <T > create (@ NonNull VirtualGenerator <T > generator , @ NonNull ExecutorService executor ) {
159+ // FIXME native implementation
160+ return Flowable .virtualCreate (generator , executor )
161+ .toStreamable ();
96162 }
163+
97164 // oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
98165 // Operators
99166 // oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
@@ -103,6 +170,7 @@ static <T> Streamable<T> fromPublisher(Flow.Publisher<T> source) {
103170 * on the default Executors.newVirtualThreadPerTaskExecutor() virtual thread.
104171 * @return the new Flowable instance
105172 */
173+ @ NonNull
106174 default Flowable <T > toFlowable () {
107175 return toFlowable (Executors .newVirtualThreadPerTaskExecutor ());
108176 }
@@ -113,10 +181,44 @@ default Flowable<T> toFlowable() {
113181 * @param executor the executor to use
114182 * @return the new Flowable instance
115183 */
116- default Flowable <T > toFlowable (ExecutorService executor ) {
184+ @ NonNull
185+ default Flowable <T > toFlowable (@ NonNull ExecutorService executor ) {
186+ Objects .requireNonNull (executor , "executir is null" );
117187 var me = this ;
118188 return Flowable .virtualCreate (emitter -> {
119- me .forEach (emitter ::emit );
189+ me .forEach (emitter ::emit ).await (emitter .canceller ());
190+ }, executor );
191+ }
192+
193+ /**
194+ * Transforms the upstream sequence into zero or more elements for the downstream.
195+ * @param <R> the result element type
196+ * @param transformer the interface to implement the transforming logic
197+ * @return the new Streamable instance
198+ */
199+ @ NonNull
200+ default <@ NonNull R > Streamable <R > transform (@ NonNull VirtualTransformer <T , R > transformer ) {
201+ return transform (transformer , Executors .newVirtualThreadPerTaskExecutor ());
202+ }
203+
204+ /**
205+ * Transforms the upstream sequence into zero or more elements for the downstream.
206+ * @param <R> the result element type
207+ * @param transformer the interface to implement the transforming logic
208+ * @param executor where to run the transform and blocking operations
209+ * @return the new Streamable instance
210+ */
211+ @ NonNull
212+ default <@ NonNull R > Streamable <R > transform (@ NonNull VirtualTransformer <T , R > transformer ,
213+ @ NonNull ExecutorService executor ) {
214+ Objects .requireNonNull (transformer , "transformer is null" );
215+ Objects .requireNonNull (executor , "executor is null" );
216+ var me = this ;
217+ return create (emitter -> {
218+ me .forEach (item -> {
219+ System .out .println ("item " + item );
220+ transformer .transform (item , emitter );
221+ }, executor ).await (emitter .canceller ());
120222 }, executor );
121223 }
122224
@@ -174,6 +276,7 @@ default CompletionStageDisposable<Void> forEach(@NonNull Consumer<? super T> con
174276 try (var str = me .stream (canceller )) {
175277 while (!canceller .isDisposed ()) {
176278 if (str .awaitNext (canceller )) {
279+ System .out .println ("Received " + str .current ());
177280 consumer .accept (Objects .requireNonNull (str .current (), "The upstream Streamable " + me .getClass () + " produced a null element!" ));
178281 } else {
179282 break ;
@@ -203,9 +306,11 @@ default CompletionStageDisposable<Void> forEach(@NonNull Consumer<? super T> con
203306 default void subscribe (@ NonNull Flow .Subscriber <? super T > subscriber , @ NonNull ExecutorService executor ) {
204307 final Streamable <T > me = this ;
205308 Flowable .<T >virtualCreate (emitter -> {
309+ // System.out.println("subscribe::virtualCreate");
206310 me .forEach (v -> {
311+ // System.out.println("subscribe::virtualCreate::forEach::emit");
207312 emitter .emit (v );
208- });
313+ }). await () ;
209314 }, executor )
210315 .subscribe (subscriber );
211316 }
@@ -218,6 +323,7 @@ default void subscribe(@NonNull Flow.Subscriber<? super T> subscriber) {
218323 final Streamable <T > me = this ;
219324 Flowable .<T >virtualCreate (emitter -> {
220325 me .forEach (v -> {
326+ // System.out.println("Emitting " + v);
221327 emitter .emit (v );
222328 });
223329 })
@@ -233,4 +339,15 @@ default TestSubscriber<T> test() {
233339 subscribe (ts );
234340 return ts ;
235341 }
342+
343+ /**
344+ * Creates a new {@link TestSubscriber} and subscribes it to this {@code Streamable}.
345+ * @param executor the executor to use
346+ * @return the created test subscriber
347+ */
348+ default TestSubscriber <T > test (ExecutorService executor ) {
349+ var ts = new TestSubscriber <T >();
350+ subscribe (ts , executor );
351+ return ts ;
352+ }
236353}
0 commit comments