implement and document Pipelines, see #3174

- heavily inspired by spray.io.Pipeline
- fully functional style: a stage returns the resulting commands and
  events, which makes it impossible to mess with the pipeline from the
  inside
- object allocations are optimized away for emtpy and 1-elem results
- added type-safety, verifying that stages match up
- management commands “from the side” for configuration or async events
- full Java API and docs
This commit is contained in:
Roland 2013-04-01 16:35:43 +02:00
parent d9d7d45ac2
commit d794b14b2b
18 changed files with 2530 additions and 64 deletions

View file

@ -69,6 +69,11 @@ object ByteString {
*/
def fromString(string: String, charset: String): ByteString = apply(string, charset)
/**
* Creates a new ByteString by copying bytes out of a ByteBuffer.
*/
def fromByteBuffer(buffer: ByteBuffer): ByteString = apply(buffer)
val empty: ByteString = CompactByteString(Array.empty[Byte])
def newBuilder: ByteStringBuilder = new ByteStringBuilder
@ -324,6 +329,11 @@ sealed abstract class ByteString extends IndexedSeq[Byte] with IndexedSeqOptimiz
*/
def ++(that: ByteString): ByteString
/**
* Java API: efficiently concatenate another ByteString.
*/
def concat(that: ByteString): ByteString = this ++ that
/**
* Copy as many bytes as possible to a ByteBuffer, starting from it's
* current position. This method will not overflow the buffer.
@ -570,6 +580,11 @@ final class ByteStringBuilder extends Builder[Byte, ByteString] {
this
}
/**
* Java API: append a ByteString to this builder.
*/
def append(bs: ByteString): this.type = this ++= bs
/**
* Add a single Byte to this builder.
*/
@ -592,19 +607,18 @@ final class ByteStringBuilder extends Builder[Byte, ByteString] {
* Add a single Int to this builder.
*/
def putInt(x: Int)(implicit byteOrder: ByteOrder): this.type = {
fillArray(4) {
case (target, offset)
if (byteOrder == ByteOrder.BIG_ENDIAN) {
target(offset + 0) = (x >>> 24).toByte
target(offset + 1) = (x >>> 16).toByte
target(offset + 2) = (x >>> 8).toByte
target(offset + 3) = (x >>> 0).toByte
} else if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
target(offset + 0) = (x >>> 0).toByte
target(offset + 1) = (x >>> 8).toByte
target(offset + 2) = (x >>> 16).toByte
target(offset + 3) = (x >>> 24).toByte
} else throw new IllegalArgumentException("Unknown byte order " + byteOrder)
fillArray(4) { (target, offset)
if (byteOrder == ByteOrder.BIG_ENDIAN) {
target(offset + 0) = (x >>> 24).toByte
target(offset + 1) = (x >>> 16).toByte
target(offset + 2) = (x >>> 8).toByte
target(offset + 3) = (x >>> 0).toByte
} else if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
target(offset + 0) = (x >>> 0).toByte
target(offset + 1) = (x >>> 8).toByte
target(offset + 2) = (x >>> 16).toByte
target(offset + 3) = (x >>> 24).toByte
} else throw new IllegalArgumentException("Unknown byte order " + byteOrder)
}
this
}
@ -613,31 +627,45 @@ final class ByteStringBuilder extends Builder[Byte, ByteString] {
* Add a single Long to this builder.
*/
def putLong(x: Long)(implicit byteOrder: ByteOrder): this.type = {
fillArray(8) {
case (target, offset)
if (byteOrder == ByteOrder.BIG_ENDIAN) {
target(offset + 0) = (x >>> 56).toByte
target(offset + 1) = (x >>> 48).toByte
target(offset + 2) = (x >>> 40).toByte
target(offset + 3) = (x >>> 32).toByte
target(offset + 4) = (x >>> 24).toByte
target(offset + 5) = (x >>> 16).toByte
target(offset + 6) = (x >>> 8).toByte
target(offset + 7) = (x >>> 0).toByte
} else if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
target(offset + 0) = (x >>> 0).toByte
target(offset + 1) = (x >>> 8).toByte
target(offset + 2) = (x >>> 16).toByte
target(offset + 3) = (x >>> 24).toByte
target(offset + 4) = (x >>> 32).toByte
target(offset + 5) = (x >>> 40).toByte
target(offset + 6) = (x >>> 48).toByte
target(offset + 7) = (x >>> 56).toByte
} else throw new IllegalArgumentException("Unknown byte order " + byteOrder)
fillArray(8) { (target, offset)
if (byteOrder == ByteOrder.BIG_ENDIAN) {
target(offset + 0) = (x >>> 56).toByte
target(offset + 1) = (x >>> 48).toByte
target(offset + 2) = (x >>> 40).toByte
target(offset + 3) = (x >>> 32).toByte
target(offset + 4) = (x >>> 24).toByte
target(offset + 5) = (x >>> 16).toByte
target(offset + 6) = (x >>> 8).toByte
target(offset + 7) = (x >>> 0).toByte
} else if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
target(offset + 0) = (x >>> 0).toByte
target(offset + 1) = (x >>> 8).toByte
target(offset + 2) = (x >>> 16).toByte
target(offset + 3) = (x >>> 24).toByte
target(offset + 4) = (x >>> 32).toByte
target(offset + 5) = (x >>> 40).toByte
target(offset + 6) = (x >>> 48).toByte
target(offset + 7) = (x >>> 56).toByte
} else throw new IllegalArgumentException("Unknown byte order " + byteOrder)
}
this
}
/**
* Add the `n` least significant bytes of the given Long to this builder.
*/
def putLongPart(x: Long, n: Int)(implicit byteOrder: ByteOrder): this.type = {
fillArray(n) { (target, offset)
if (byteOrder == ByteOrder.BIG_ENDIAN) {
val start = n * 8 - 8
(0 until n) foreach (i target(offset + i) = (x >>> start - 8 * i).toByte)
} else if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
val end = offset + n - 1
(0 until n) foreach (i target(end - i) = (x >>> 8 * i).toByte)
} else throw new IllegalArgumentException("Unknown byte order " + byteOrder)
}
}
/**
* Add a single Float to this builder.
*/