@@ -538,6 +538,52 @@ trait SourceOps[+T] { outer: Source[T] =>
538
538
}
539
539
c
540
540
541
+ /** Applies the given mapping function `f`, to each element received from this source, transforming it into an Iterable of results, then
542
+ * sends the results one by one to the returned channel. Can be used to unfold incoming sequences of elements into single elements.
543
+ *
544
+ * @param f
545
+ * A function that transforms the element from this source into a pair of the next state into an [[scala.collection.IterableOnce ]] of
546
+ * results which are sent one by one to the returned channel. If the result of `f` is empty, nothing is sent to the returned channel.
547
+ * @return
548
+ * A source to which the results of applying `f` to the elements from this source would be sent.
549
+ * @example
550
+ * {{{
551
+ * scala>
552
+ * import ox.*
553
+ * import ox.channels.Source
554
+ *
555
+ * supervised {
556
+ * val s = Source.fromValues(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9))
557
+ * s.mapConcat(identity)
558
+ * }
559
+ *
560
+ * scala> val res0: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
561
+ * }}}
562
+ */
563
+ def mapConcat [U ](f : T => IterableOnce [U ])(using Ox , StageCapacity ): Source [U ] =
564
+ val c = StageCapacity .newChannel[U ]
565
+ fork {
566
+ repeatWhile {
567
+ receiveSafe() match
568
+ case ChannelClosed .Done =>
569
+ c.doneSafe()
570
+ false
571
+ case ChannelClosed .Error (r) =>
572
+ c.errorSafe(r)
573
+ false
574
+ case t : T @ unchecked =>
575
+ try
576
+ val results : IterableOnce [U ] = f(t)
577
+ results.iterator.foreach(c.send)
578
+ true
579
+ catch
580
+ case t : Throwable =>
581
+ c.errorSafe(t)
582
+ false
583
+ }
584
+ }
585
+ c
586
+
541
587
/** Returns the first element from this source wrapped in [[Some ]] or [[None ]] when this source is empty. Note that `headOption` is not an
542
588
* idempotent operation on source as it receives elements from it.
543
589
*
@@ -565,7 +611,7 @@ trait SourceOps[+T] { outer: Source[T] =>
565
611
case e : ChannelClosed .Error => throw e.toThrowable
566
612
case t : T @ unchecked => Some (t)
567
613
}
568
-
614
+
569
615
/** Sends elements to the returned channel limiting the throughput to specific number of elements (evenly spaced) per time unit. Note that
570
616
* the element's `receive()` time is included in the resulting throughput. For instance having `throttle(1, 1.second)` and `receive()`
571
617
* taking `Xms` means that resulting channel will receive elements every `1s + Xms` time. Throttling is not applied to the empty source.
0 commit comments