Add combinedMat method to Source (#23809)
* Add combinedMat method to Source * Fix formatting
This commit is contained in:
parent
0988933fac
commit
a50df1c575
4 changed files with 87 additions and 0 deletions
|
|
@ -11,6 +11,8 @@ import akka.japi.Pair;
|
||||||
import akka.japi.function.*;
|
import akka.japi.function.*;
|
||||||
import akka.japi.pf.PFBuilder;
|
import akka.japi.pf.PFBuilder;
|
||||||
import akka.stream.*;
|
import akka.stream.*;
|
||||||
|
import akka.stream.testkit.TestSubscriber;
|
||||||
|
import akka.stream.testkit.javadsl.TestSink;
|
||||||
import akka.util.ConstantFun;
|
import akka.util.ConstantFun;
|
||||||
import akka.stream.stage.*;
|
import akka.stream.stage.*;
|
||||||
import akka.testkit.AkkaSpec;
|
import akka.testkit.AkkaSpec;
|
||||||
|
|
@ -655,6 +657,28 @@ public class SourceTest extends StreamTest {
|
||||||
future.toCompletableFuture().get(3, TimeUnit.SECONDS);
|
future.toCompletableFuture().get(3, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void mustBeAbleToCombineMat() throws Exception {
|
||||||
|
final TestKit probe = new TestKit(system);
|
||||||
|
final Source<Integer, SourceQueueWithComplete<Integer>> source1 = Source.queue(1, OverflowStrategy.dropNew());
|
||||||
|
final Source<Integer, NotUsed> source2 = Source.from(Arrays.asList(2, 3));
|
||||||
|
|
||||||
|
// compiler to check the correct materialized value of type = SourceQueueWithComplete<Integer> available
|
||||||
|
final Source<Integer, SourceQueueWithComplete<Integer>> combined = Source.combineMat(
|
||||||
|
source1, source2, width -> Concat.<Integer> create(width), Keep.left()); //Keep.left() (i.e. preserve queueSource's materialized value)
|
||||||
|
|
||||||
|
SourceQueueWithComplete<Integer> queue = combined
|
||||||
|
.toMat(Sink.foreach(elem -> probe.getRef().tell(elem, ActorRef.noSender())), Keep.left())
|
||||||
|
.run(materializer);
|
||||||
|
|
||||||
|
queue.offer(0);
|
||||||
|
queue.offer(1);
|
||||||
|
queue.complete(); //complete queueSource so that combined with `Concat` pulls elements from queueSource
|
||||||
|
|
||||||
|
// elements from source1 (i.e. first of combined source) come first, then source2 elements, due to `Concat`
|
||||||
|
probe.expectMsgAllOf(0, 1, 2, 3);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void mustBeAbleToZipN() throws Exception {
|
public void mustBeAbleToZipN() throws Exception {
|
||||||
final TestKit probe = new TestKit(system);
|
final TestKit probe = new TestKit(system);
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ import scala.collection.immutable
|
||||||
import java.util
|
import java.util
|
||||||
import java.util.stream.BaseStream
|
import java.util.stream.BaseStream
|
||||||
|
|
||||||
|
import akka.stream.testkit.scaladsl.TestSink
|
||||||
|
|
||||||
class SourceSpec extends StreamSpec with DefaultTimeout {
|
class SourceSpec extends StreamSpec with DefaultTimeout {
|
||||||
|
|
||||||
implicit val materializer = ActorMaterializer()
|
implicit val materializer = ActorMaterializer()
|
||||||
|
|
@ -141,6 +143,45 @@ class SourceSpec extends StreamSpec with DefaultTimeout {
|
||||||
out.expectComplete()
|
out.expectComplete()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"combine from two inputs with combinedMat and take a materialized value" in {
|
||||||
|
val queueSource = Source.queue[Int](1, OverflowStrategy.dropBuffer)
|
||||||
|
val intSeqSource = Source(1 to 3)
|
||||||
|
|
||||||
|
// compiler to check the correct materialized value of type = SourceQueueWithComplete[Int] available
|
||||||
|
val combined1: Source[Int, SourceQueueWithComplete[Int]] =
|
||||||
|
Source.combineMat(queueSource, intSeqSource)(Concat(_))(Keep.left) //Keep.left (i.e. preserve queueSource's materialized value)
|
||||||
|
|
||||||
|
val (queue1, sinkProbe1) = combined1.toMat(TestSink.probe[Int])(Keep.both).run()
|
||||||
|
sinkProbe1.request(6)
|
||||||
|
queue1.offer(10)
|
||||||
|
queue1.offer(20)
|
||||||
|
queue1.offer(30)
|
||||||
|
queue1.complete() //complete queueSource so that combined1 with `Concat` then pulls elements from intSeqSource
|
||||||
|
sinkProbe1.expectNext(10)
|
||||||
|
sinkProbe1.expectNext(20)
|
||||||
|
sinkProbe1.expectNext(30)
|
||||||
|
sinkProbe1.expectNext(1)
|
||||||
|
sinkProbe1.expectNext(2)
|
||||||
|
sinkProbe1.expectNext(3)
|
||||||
|
|
||||||
|
// compiler to check the correct materialized value of type = SourceQueueWithComplete[Int] available
|
||||||
|
val combined2: Source[Int, SourceQueueWithComplete[Int]] =
|
||||||
|
//queueSource to be the second of combined source
|
||||||
|
Source.combineMat(intSeqSource, queueSource)(Concat(_))(Keep.right) //Keep.right (i.e. preserve queueSource's materialized value)
|
||||||
|
|
||||||
|
val (queue2, sinkProbe2) = combined2.toMat(TestSink.probe[Int])(Keep.both).run()
|
||||||
|
sinkProbe2.request(6)
|
||||||
|
queue2.offer(10)
|
||||||
|
queue2.offer(20)
|
||||||
|
queue2.offer(30)
|
||||||
|
queue2.complete() //complete queueSource so that combined1 with `Concat` then pulls elements from queueSource
|
||||||
|
sinkProbe2.expectNext(1) //as intSeqSource iss the first in combined source, elements from intSeqSource come first
|
||||||
|
sinkProbe2.expectNext(2)
|
||||||
|
sinkProbe2.expectNext(3)
|
||||||
|
sinkProbe2.expectNext(10) //after intSeqSource run out elements, queueSource elements come
|
||||||
|
sinkProbe2.expectNext(20)
|
||||||
|
sinkProbe2.expectNext(30)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"Repeat Source" must {
|
"Repeat Source" must {
|
||||||
|
|
|
||||||
|
|
@ -317,6 +317,15 @@ object Source {
|
||||||
new Source(scaladsl.Source.combine(first.asScala, second.asScala, seq: _*)(num ⇒ strategy.apply(num)))
|
new Source(scaladsl.Source.combine(first.asScala, second.asScala, seq: _*)(num ⇒ strategy.apply(num)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combines two sources with fan-in strategy like `Merge` or `Concat` and returns `Source` with a materialized value.
|
||||||
|
*/
|
||||||
|
def combineMat[T, U, M1, M2, M](first: Source[T, M1], second: Source[T, M2],
|
||||||
|
strategy: function.Function[java.lang.Integer, _ <: Graph[UniformFanInShape[T, U], NotUsed]],
|
||||||
|
combine: function.Function2[M1, M2, M]): Source[U, M] = {
|
||||||
|
new Source(scaladsl.Source.combineMat(first.asScala, second.asScala)(num ⇒ strategy.apply(num))(combinerToScala(combine)))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Combine the elements of multiple streams into a stream of lists.
|
* Combine the elements of multiple streams into a stream of lists.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -448,6 +448,19 @@ object Source {
|
||||||
combineRest(2, rest.iterator)
|
combineRest(2, rest.iterator)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combines two sources with fan-in strategy like `Merge` or `Concat` and returns `Source` with a materialized value.
|
||||||
|
*/
|
||||||
|
def combineMat[T, U, M1, M2, M](first: Source[T, M1], second: Source[T, M2])(strategy: Int ⇒ Graph[UniformFanInShape[T, U], NotUsed])(matF: (M1, M2) ⇒ M): Source[U, M] = {
|
||||||
|
val secondPartiallyCombined = GraphDSL.create(second) { implicit b ⇒ secondShape ⇒
|
||||||
|
import GraphDSL.Implicits._
|
||||||
|
val c = b.add(strategy(2))
|
||||||
|
secondShape ~> c.in(1)
|
||||||
|
FlowShape(c.in(0), c.out)
|
||||||
|
}
|
||||||
|
first.viaMat(secondPartiallyCombined)(matF)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Combine the elements of multiple streams into a stream of sequences.
|
* Combine the elements of multiple streams into a stream of sequences.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue