New materializer and layout

This commit is contained in:
Endre Sándor Varga 2016-07-27 13:29:23 +02:00 committed by Endre Sándor Varga
parent 1989ef481d
commit ba63c7af8d
60 changed files with 4420 additions and 3181 deletions

View file

@ -6,7 +6,6 @@ package akka.stream.scaladsl
import akka.event.LoggingAdapter
import akka.stream._
import akka.Done
import akka.stream.impl.StreamLayout.Module
import akka.stream.impl._
import akka.stream.impl.fusing._
import akka.stream.stage._
@ -24,12 +23,14 @@ import akka.annotation.DoNotInherit
/**
* A `Flow` is a set of stream processing steps that has one open input and one open output.
*/
final class Flow[-In, +Out, +Mat](override val module: Module)
final class Flow[-In, +Out, +Mat](
override val traversalBuilder: LinearTraversalBuilder,
override val shape: FlowShape[In, Out]
)
extends FlowOpsMat[Out, Mat] with Graph[FlowShape[In, Out], Mat] {
override val shape: FlowShape[In, Out] = module.shape.asInstanceOf[FlowShape[In, Out]]
override def toString: String = s"Flow($shape, $module)"
// TODO: debug string
override def toString: String = s"Flow($shape)"
override type Repr[+O] = Flow[In @uncheckedVariance, O, Mat @uncheckedVariance]
override type ReprMat[+O, +M] = Flow[In @uncheckedVariance, O, M]
@ -37,27 +38,23 @@ final class Flow[-In, +Out, +Mat](override val module: Module)
override type Closed = Sink[In @uncheckedVariance, Mat @uncheckedVariance]
override type ClosedMat[+M] = Sink[In @uncheckedVariance, M]
private[stream] def isIdentity: Boolean = this.module eq GraphStages.Identity.module
private[stream] def isIdentity: Boolean = this.traversalBuilder eq Flow.identityTraversalBuilder
override def via[T, Mat2](flow: Graph[FlowShape[Out, T], Mat2]): Repr[T] = viaMat(flow)(Keep.left)
override def viaMat[T, Mat2, Mat3](flow: Graph[FlowShape[Out, T], Mat2])(combine: (Mat, Mat2) Mat3): Flow[In, T, Mat3] =
override def viaMat[T, Mat2, Mat3](flow: Graph[FlowShape[Out, T], Mat2])(combine: (Mat, Mat2) Mat3): Flow[In, T, Mat3] = {
if (this.isIdentity) {
import Predef.Map.empty
import StreamLayout.{ CompositeModule, Ignore, IgnorableMatValComp, Transform, Atomic, Combine }
val m = flow.module
val mat =
if (combine == Keep.left) {
if (IgnorableMatValComp(m)) Ignore else Transform(_ NotUsed, Atomic(m))
} else Combine(combine.asInstanceOf[(Any, Any) Any], Ignore, Atomic(m))
new Flow(CompositeModule(Set(m), m.shape, empty, empty, mat, Attributes.none))
} else {
val flowCopy = flow.module.carbonCopy
new Flow(
module
.fuse(flowCopy, shape.out, flowCopy.shape.inlets.head, combine)
.replaceShape(FlowShape(shape.in, flowCopy.shape.outlets.head)))
LinearTraversalBuilder.fromBuilder(flow.traversalBuilder, flow.shape, combine),
flow.shape
).asInstanceOf[Flow[In, T, Mat3]]
} else {
new Flow(
traversalBuilder.append(flow.traversalBuilder, flow.shape, combine),
FlowShape[In, T](shape.in, flow.shape.out)
)
}
}
/**
* Connect this [[Flow]] to a [[Sink]], concatenating the processing steps of both.
@ -98,15 +95,16 @@ final class Flow[-In, +Out, +Mat](override val module: Module)
* where appropriate instead of manually writing functions that pass through one of the values.
*/
def toMat[Mat2, Mat3](sink: Graph[SinkShape[Out], Mat2])(combine: (Mat, Mat2) Mat3): Sink[In, Mat3] = {
if (isIdentity)
Sink.fromGraph(sink.asInstanceOf[Graph[SinkShape[In], Mat2]])
.mapMaterializedValue(combine(NotUsed.asInstanceOf[Mat], _))
else {
val sinkCopy = sink.module.carbonCopy
if (isIdentity) {
new Sink(
module
.fuse(sinkCopy, shape.out, sinkCopy.shape.inlets.head, combine)
.replaceShape(SinkShape(shape.in)))
LinearTraversalBuilder.fromBuilder(sink.traversalBuilder, sink.shape, combine),
SinkShape(sink.shape.in)
).asInstanceOf[Sink[In, Mat3]]
} else {
new Sink(
traversalBuilder.append(sink.traversalBuilder, sink.shape, combine),
SinkShape(shape.in)
)
}
}
@ -114,7 +112,10 @@ final class Flow[-In, +Out, +Mat](override val module: Module)
* Transform the materialized value of this Flow, leaving all other properties as they were.
*/
override def mapMaterializedValue[Mat2](f: Mat Mat2): ReprMat[Out, Mat2] =
new Flow(module.transformMaterializedValue(f.asInstanceOf[Any Any]))
new Flow(
traversalBuilder.transformMat(f),
shape
)
/**
* Join this [[Flow]] to another [[Flow]], by cross connecting the inputs and outputs, creating a [[RunnableGraph]].
@ -147,12 +148,11 @@ final class Flow[-In, +Out, +Mat](override val module: Module)
* where appropriate instead of manually writing functions that pass through one of the values.
*/
def joinMat[Mat2, Mat3](flow: Graph[FlowShape[Out, In], Mat2])(combine: (Mat, Mat2) Mat3): RunnableGraph[Mat3] = {
val flowCopy = flow.module.carbonCopy
RunnableGraph(
module
.compose(flowCopy, combine)
.wire(shape.out, flowCopy.shape.inlets.head)
.wire(flowCopy.shape.outlets.head, shape.in))
val resultBuilder = traversalBuilder
.append(flow.traversalBuilder, flow.shape, combine)
.wire(flow.shape.out, shape.in)
RunnableGraph(resultBuilder)
}
/**
@ -194,14 +194,22 @@ final class Flow[-In, +Out, +Mat](override val module: Module)
* where appropriate instead of manually writing functions that pass through one of the values.
*/
def joinMat[I2, O2, Mat2, M](bidi: Graph[BidiShape[Out, O2, I2, In], Mat2])(combine: (Mat, Mat2) M): Flow[I2, O2, M] = {
val copy = bidi.module.carbonCopy
val ins = copy.shape.inlets
val outs = copy.shape.outlets
new Flow(module
.compose(copy, combine)
.wire(shape.out, ins.head)
.wire(outs(1), shape.in)
.replaceShape(FlowShape(ins(1), outs.head)))
val newBidiShape = bidi.shape.deepCopy()
val newFlowShape = shape.deepCopy()
val resultBuilder =
TraversalBuilder.empty()
.add(traversalBuilder, newFlowShape, Keep.right)
.add(bidi.traversalBuilder, newBidiShape, combine)
.wire(newFlowShape.out, newBidiShape.in1)
.wire(newBidiShape.out2, newFlowShape.in)
val newShape = FlowShape(newBidiShape.in2, newBidiShape.out1)
new Flow(
LinearTraversalBuilder.fromBuilder(resultBuilder, newShape, Keep.right),
newShape
)
}
/**
@ -212,8 +220,10 @@ final class Flow[-In, +Out, +Mat](override val module: Module)
* only to the contained processing stages).
*/
override def withAttributes(attr: Attributes): Repr[Out] =
if (isIdentity) this
else new Flow(module.withAttributes(attr))
new Flow(
traversalBuilder.setAttributes(attr),
shape
)
/**
* Add the given attributes to this Flow. Further calls to `withAttributes`
@ -221,7 +231,7 @@ final class Flow[-In, +Out, +Mat](override val module: Module)
* operation has no effect on an empty Flow (because the attributes apply
* only to the contained processing stages).
*/
override def addAttributes(attr: Attributes): Repr[Out] = withAttributes(module.attributes and attr)
override def addAttributes(attr: Attributes): Repr[Out] = withAttributes(traversalBuilder.attributes and attr)
/**
* Add a ``name`` attribute to this Flow.
@ -231,7 +241,12 @@ final class Flow[-In, +Out, +Mat](override val module: Module)
/**
* Put an asynchronous boundary around this `Flow`
*/
override def async: Repr[Out] = addAttributes(Attributes.asyncBoundary)
override def async: Repr[Out] = {
new Flow(
traversalBuilder.makeIsland(GraphStageTag),
shape
)
}
/**
* Connect the `Source` to this `Flow` and then connect it to the `Sink` and run it. The returned tuple contains
@ -265,7 +280,13 @@ final class Flow[-In, +Out, +Mat](override val module: Module)
}
object Flow {
private[this] val identity: Flow[Any, Any, NotUsed] = new Flow[Any, Any, NotUsed](GraphStages.Identity.module)
private[stream] val identityTraversalBuilder =
LinearTraversalBuilder.fromBuilder(GraphStages.Identity.traversalBuilder, GraphStages.Identity.shape, Keep.right)
private[this] val identity: Flow[Any, Any, NotUsed] = new Flow[Any, Any, NotUsed](
identityTraversalBuilder,
GraphStages.Identity.shape
)
/**
* Creates a Flow from a Reactive Streams [[org.reactivestreams.Processor]]
@ -278,7 +299,7 @@ object Flow {
* Creates a Flow from a Reactive Streams [[org.reactivestreams.Processor]] and returns a materialized value.
*/
def fromProcessorMat[I, O, M](processorFactory: () (Processor[I, O], M)): Flow[I, O, M] =
new Flow(ProcessorModule(processorFactory))
fromGraph(ProcessorModule(processorFactory))
/**
* Returns a `Flow` which outputs all its inputs.
@ -299,7 +320,10 @@ object Flow {
g match {
case f: Flow[I, O, M] f
case f: javadsl.Flow[I, O, M] f.asScala
case other new Flow(other.module)
case other new Flow(
LinearTraversalBuilder.fromBuilder(g.traversalBuilder, g.shape, Keep.right),
g.shape
)
}
/**
@ -328,21 +352,20 @@ object RunnableGraph {
def fromGraph[Mat](g: Graph[ClosedShape, Mat]): RunnableGraph[Mat] =
g match {
case r: RunnableGraph[Mat] r
case other RunnableGraph(other.module)
case other RunnableGraph(other.traversalBuilder)
}
}
/**
* Flow with attached input and output, can be executed.
*/
final case class RunnableGraph[+Mat](val module: StreamLayout.Module) extends Graph[ClosedShape, Mat] {
require(module.isRunnable)
final case class RunnableGraph[+Mat](override val traversalBuilder: TraversalBuilder) extends Graph[ClosedShape, Mat] {
override def shape = ClosedShape
/**
* Transform only the materialized value of this RunnableGraph, leaving all other properties as they were.
*/
def mapMaterializedValue[Mat2](f: Mat Mat2): RunnableGraph[Mat2] =
copy(module.transformMaterializedValue(f.asInstanceOf[Any Any]))
copy(traversalBuilder.transformMat(f.asInstanceOf[Any Any]))
/**
* Run this flow and return the materialized instance from the flow.
@ -350,16 +373,16 @@ final case class RunnableGraph[+Mat](val module: StreamLayout.Module) extends Gr
def run()(implicit materializer: Materializer): Mat = materializer.materialize(this)
override def addAttributes(attr: Attributes): RunnableGraph[Mat] =
withAttributes(module.attributes and attr)
withAttributes(traversalBuilder.attributes and attr)
override def withAttributes(attr: Attributes): RunnableGraph[Mat] =
new RunnableGraph(module.withAttributes(attr))
new RunnableGraph(traversalBuilder.setAttributes(attr))
override def named(name: String): RunnableGraph[Mat] =
addAttributes(Attributes.name(name))
override def async: RunnableGraph[Mat] =
addAttributes(Attributes.asyncBoundary)
new RunnableGraph(traversalBuilder.makeIsland(GraphStageTag))
}
/**