115 lines
2.6 KiB
Scala
115 lines
2.6 KiB
Scala
package docs.stream.cookbook
|
|
|
|
import akka.stream.scaladsl.{ Sink, Source }
|
|
import akka.stream.testkit._
|
|
|
|
import scala.concurrent.duration._
|
|
|
|
object HoldOps {
|
|
//#hold-version-1
|
|
import akka.stream.stage._
|
|
class HoldWithInitial[T](initial: T) extends DetachedStage[T, T] {
|
|
private var currentValue: T = initial
|
|
|
|
override def onPush(elem: T, ctx: DetachedContext[T]): UpstreamDirective = {
|
|
currentValue = elem
|
|
ctx.pull()
|
|
}
|
|
|
|
override def onPull(ctx: DetachedContext[T]): DownstreamDirective = {
|
|
ctx.push(currentValue)
|
|
}
|
|
|
|
}
|
|
//#hold-version-1
|
|
|
|
//#hold-version-2
|
|
import akka.stream.stage._
|
|
class HoldWithWait[T] extends DetachedStage[T, T] {
|
|
private var currentValue: T = _
|
|
private var waitingFirstValue = true
|
|
|
|
override def onPush(elem: T, ctx: DetachedContext[T]): UpstreamDirective = {
|
|
currentValue = elem
|
|
waitingFirstValue = false
|
|
if (ctx.isHoldingDownstream) ctx.pushAndPull(currentValue)
|
|
else ctx.pull()
|
|
}
|
|
|
|
override def onPull(ctx: DetachedContext[T]): DownstreamDirective = {
|
|
if (waitingFirstValue) ctx.holdDownstream()
|
|
else ctx.push(currentValue)
|
|
}
|
|
|
|
}
|
|
//#hold-version-2
|
|
}
|
|
|
|
class RecipeHold extends RecipeSpec {
|
|
import HoldOps._
|
|
|
|
"Recipe for creating a holding element" must {
|
|
|
|
"work for version 1" in {
|
|
|
|
val pub = TestPublisher.probe[Int]()
|
|
val sub = TestSubscriber.manualProbe[Int]()
|
|
val source = Source.fromPublisher(pub)
|
|
val sink = Sink.fromSubscriber(sub)
|
|
|
|
source.transform(() => new HoldWithInitial(0)).to(sink).run()
|
|
|
|
val subscription = sub.expectSubscription()
|
|
sub.expectNoMsg(100.millis)
|
|
|
|
subscription.request(1)
|
|
sub.expectNext(0)
|
|
|
|
subscription.request(1)
|
|
sub.expectNext(0)
|
|
|
|
pub.sendNext(1)
|
|
pub.sendNext(2)
|
|
|
|
subscription.request(2)
|
|
sub.expectNext(2)
|
|
sub.expectNext(2)
|
|
|
|
pub.sendComplete()
|
|
subscription.request(1)
|
|
sub.expectComplete()
|
|
}
|
|
|
|
"work for version 2" in {
|
|
|
|
val pub = TestPublisher.probe[Int]()
|
|
val sub = TestSubscriber.manualProbe[Int]()
|
|
val source = Source.fromPublisher(pub)
|
|
val sink = Sink.fromSubscriber(sub)
|
|
|
|
source.transform(() => new HoldWithWait).to(sink).run()
|
|
|
|
val subscription = sub.expectSubscription()
|
|
sub.expectNoMsg(100.millis)
|
|
|
|
subscription.request(1)
|
|
sub.expectNoMsg(100.millis)
|
|
|
|
pub.sendNext(1)
|
|
sub.expectNext(1)
|
|
|
|
pub.sendNext(2)
|
|
pub.sendNext(3)
|
|
|
|
subscription.request(2)
|
|
sub.expectNext(3)
|
|
sub.expectNext(3)
|
|
|
|
pub.sendComplete()
|
|
subscription.request(1)
|
|
sub.expectComplete()
|
|
}
|
|
|
|
}
|
|
|
|
}
|