make all Take impls use the same implementation (Sink)
This commit is contained in:
parent
3a92104160
commit
a3f50420db
3 changed files with 20 additions and 54 deletions
|
|
@ -175,54 +175,14 @@ import scala.util.{ Failure, Success, Try }
|
||||||
new ActorRefSink[In](ref, onCompleteMessage, onFailureMessage, attr, amendShape(attr))
|
new ActorRefSink[In](ref, onCompleteMessage, onFailureMessage, attr, amendShape(attr))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* INTERNAL API
|
|
||||||
*/
|
|
||||||
@InternalApi private[akka] final class LastOptionStage[T] extends GraphStageWithMaterializedValue[SinkShape[T], Future[Option[T]]] {
|
|
||||||
|
|
||||||
val in: Inlet[T] = Inlet("lastOption.in")
|
|
||||||
|
|
||||||
override val shape: SinkShape[T] = SinkShape.of(in)
|
|
||||||
|
|
||||||
override def createLogicAndMaterializedValue(inheritedAttributes: Attributes) = {
|
|
||||||
val p: Promise[Option[T]] = Promise()
|
|
||||||
(new GraphStageLogic(shape) with InHandler {
|
|
||||||
private[this] var prev: T = null.asInstanceOf[T]
|
|
||||||
|
|
||||||
override def preStart(): Unit = pull(in)
|
|
||||||
|
|
||||||
def onPush(): Unit = {
|
|
||||||
prev = grab(in)
|
|
||||||
pull(in)
|
|
||||||
}
|
|
||||||
|
|
||||||
override def onUpstreamFinish(): Unit = {
|
|
||||||
val head = prev
|
|
||||||
prev = null.asInstanceOf[T]
|
|
||||||
p.trySuccess(Option(head))
|
|
||||||
completeStage()
|
|
||||||
}
|
|
||||||
|
|
||||||
override def onUpstreamFailure(ex: Throwable): Unit = {
|
|
||||||
prev = null.asInstanceOf[T]
|
|
||||||
p.tryFailure(ex)
|
|
||||||
failStage(ex)
|
|
||||||
}
|
|
||||||
|
|
||||||
setHandler(in, this)
|
|
||||||
}, p.future)
|
|
||||||
}
|
|
||||||
|
|
||||||
override def toString: String = "LastOptionStage"
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* INTERNAL API
|
* INTERNAL API
|
||||||
*/
|
*/
|
||||||
@InternalApi private[akka] final class TakeLastStage[T](n: Int) extends GraphStageWithMaterializedValue[SinkShape[T], Future[immutable.Seq[T]]] {
|
@InternalApi private[akka] final class TakeLastStage[T](n: Int) extends GraphStageWithMaterializedValue[SinkShape[T], Future[immutable.Seq[T]]] {
|
||||||
require(n > 0, "n must be greater than 0")
|
if (n <= 0)
|
||||||
|
throw new IllegalArgumentException("requirement failed: n must be greater than 0")
|
||||||
|
|
||||||
val in: Inlet[T] = Inlet("takeLastStage.in")
|
val in: Inlet[T] = Inlet("takeLast.in")
|
||||||
|
|
||||||
override val shape: SinkShape[T] = SinkShape.of(in)
|
override val shape: SinkShape[T] = SinkShape.of(in)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -165,8 +165,8 @@ object Sink {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A `Sink` that materializes into a a `CompletionStage` of `List<In>` containing the last `n` collected elements.
|
* A `Sink` that materializes into a a `CompletionStage` of `List<In>` containing the last `n` collected elements.
|
||||||
* If the stream completes before signaling at least n elements, the CompletionStage will complete with the number
|
*
|
||||||
* of elements taken at that point.
|
* If the stream completes before signaling at least n elements, the `CompletionStage` will complete with all elements seen so far.
|
||||||
* If the stream never completes the `CompletionStage` will never complete.
|
* If the stream never completes the `CompletionStage` will never complete.
|
||||||
* If there is a failure signaled in the stream the `CompletionStage` will be completed with failure.
|
* If there is a failure signaled in the stream the `CompletionStage` will be completed with failure.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -190,8 +190,12 @@ object Sink {
|
||||||
*
|
*
|
||||||
* See also [[lastOption]], [[takeLast]].
|
* See also [[lastOption]], [[takeLast]].
|
||||||
*/
|
*/
|
||||||
def last[T]: Sink[T, Future[T]] = Sink.fromGraph(new LastOptionStage[T]).withAttributes(DefaultAttributes.lastSink)
|
def last[T]: Sink[T, Future[T]] = {
|
||||||
.mapMaterializedValue(e ⇒ e.map(_.getOrElse(throw new NoSuchElementException("last of empty stream")))(ExecutionContexts.sameThreadExecutionContext))
|
Sink.fromGraph(new TakeLastStage[T](1)).withAttributes(DefaultAttributes.lastSink)
|
||||||
|
.mapMaterializedValue { e ⇒
|
||||||
|
e.map(_.headOption.getOrElse(throw new NoSuchElementException("last of empty stream")))(ExecutionContexts.sameThreadExecutionContext)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A `Sink` that materializes into a `Future` of the optional last value received.
|
* A `Sink` that materializes into a `Future` of the optional last value received.
|
||||||
|
|
@ -200,20 +204,22 @@ object Sink {
|
||||||
*
|
*
|
||||||
* See also [[last]], [[takeLast]].
|
* See also [[last]], [[takeLast]].
|
||||||
*/
|
*/
|
||||||
def lastOption[T]: Sink[T, Future[Option[T]]] = Sink.fromGraph(new LastOptionStage[T]).withAttributes(DefaultAttributes.lastOptionSink)
|
def lastOption[T]: Sink[T, Future[Option[T]]] = {
|
||||||
|
Sink.fromGraph(new TakeLastStage[T](1)).withAttributes(DefaultAttributes.lastOptionSink)
|
||||||
|
.mapMaterializedValue { e ⇒
|
||||||
|
e.map(_.headOption)(ExecutionContexts.sameThreadExecutionContext)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A `Sink` that materializes into a a `Future` of `immutable.Seq[T]` containing the last `n` collected elements.
|
* A `Sink` that materializes into a a `Future` of `immutable.Seq[T]` containing the last `n` collected elements.
|
||||||
* If the stream completes before signaling at least n elements, the Future will complete with the number
|
*
|
||||||
* of elements taken at that point.
|
* If the stream completes before signaling at least n elements, the `Future` will complete with all elements seen so far.
|
||||||
* If the stream never completes, the `Future` will never complete.
|
* If the stream never completes, the `Future` will never complete.
|
||||||
* If there is a failure signaled in the stream the `Future` will be completed with failure.
|
* If there is a failure signaled in the stream the `Future` will be completed with failure.
|
||||||
*/
|
*/
|
||||||
def takeLast[T](n: Int): Sink[T, Future[immutable.Seq[T]]] =
|
def takeLast[T](n: Int): Sink[T, Future[immutable.Seq[T]]] =
|
||||||
if (n == 1)
|
Sink.fromGraph(new TakeLastStage[T](n)).withAttributes(DefaultAttributes.takeLastSink)
|
||||||
lastOption.mapMaterializedValue(fut ⇒ fut.map(_.fold(immutable.Seq.empty[T])(m ⇒ immutable.Seq(m)))(ExecutionContexts.sameThreadExecutionContext))
|
|
||||||
else
|
|
||||||
Sink.fromGraph(new TakeLastStage[T](n)).withAttributes(DefaultAttributes.takeLastSink)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A `Sink` that keeps on collecting incoming elements until upstream terminates.
|
* A `Sink` that keeps on collecting incoming elements until upstream terminates.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue