Changed ByteString docs to hoist example code from separate file
This commit is contained in:
parent
20e313e6a5
commit
9c6deaa475
2 changed files with 93 additions and 56 deletions
84
akka-docs/scala/code/akka/docs/io/BinaryCoding.scala
Normal file
84
akka-docs/scala/code/akka/docs/io/BinaryCoding.scala
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/**
|
||||
* Copyright (C) 2012 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
package akka.docs.io
|
||||
|
||||
//#imports
|
||||
import akka.actor._
|
||||
import akka.util.{ ByteString, ByteStringBuilder, ByteIterator }
|
||||
//#imports
|
||||
|
||||
abstract class BinaryDecoding {
|
||||
//#decoding
|
||||
implicit val byteOrder = java.nio.ByteOrder.BIG_ENDIAN
|
||||
|
||||
val FrameDecoder = for {
|
||||
frameLenBytes ← IO.take(4)
|
||||
frameLen = frameLenBytes.iterator.getInt
|
||||
frame ← IO.take(frameLen)
|
||||
} yield {
|
||||
val in = frame.iterator
|
||||
|
||||
val n = in.getInt
|
||||
val m = in.getInt
|
||||
|
||||
val a = Array.newBuilder[Short]
|
||||
val b = Array.newBuilder[Long]
|
||||
|
||||
for (i ← 1 to n) {
|
||||
a += in.getShort
|
||||
b += in.getInt
|
||||
}
|
||||
|
||||
val data = Array.ofDim[Double](m)
|
||||
in.getDoubles(data)
|
||||
|
||||
(a.result, b.result, data)
|
||||
}
|
||||
|
||||
//#decoding
|
||||
}
|
||||
|
||||
abstract class RestToSeq {
|
||||
implicit val byteOrder = java.nio.ByteOrder.BIG_ENDIAN
|
||||
val bytes: ByteString
|
||||
val in = bytes.iterator
|
||||
|
||||
//#rest-to-seq
|
||||
val n = in.getInt
|
||||
val m = in.getInt
|
||||
// ... in.get...
|
||||
val rest: ByteString = in.toSeq
|
||||
//#rest-to-seq
|
||||
}
|
||||
|
||||
abstract class BinaryEncoding {
|
||||
//#encoding
|
||||
implicit val byteOrder = java.nio.ByteOrder.BIG_ENDIAN
|
||||
|
||||
val a: Array[Short]
|
||||
val b: Array[Long]
|
||||
val data: Array[Double]
|
||||
|
||||
val frameBuilder = ByteString.newBuilder
|
||||
|
||||
val n = a.length
|
||||
val m = data.length
|
||||
|
||||
frameBuilder.putInt(n)
|
||||
frameBuilder.putInt(m)
|
||||
|
||||
for (i ← 0 to n - 1) {
|
||||
frameBuilder.putShort(a(i))
|
||||
frameBuilder.putLong(b(i))
|
||||
}
|
||||
frameBuilder.putDoubles(data)
|
||||
val frame = frameBuilder.result()
|
||||
//#encoding
|
||||
|
||||
//#sending
|
||||
val socket: IO.SocketHandle
|
||||
socket.write(ByteString.newBuilder.putInt(frame.length).result)
|
||||
socket.write(frame)
|
||||
//#sending
|
||||
}
|
||||
|
|
@ -48,76 +48,29 @@ In this example, the data is to be stored in arrays of ``a``, ``b`` and ``data``
|
|||
|
||||
Decoding of such frames can be efficiently implemented in the following fashion:
|
||||
|
||||
.. code-block:: scala
|
||||
|
||||
implicit val byteOrder = java.nio.ByteOrder.BIG_ENDIAN
|
||||
|
||||
val FrameDecoder = for {
|
||||
frameLenBytes <- IO.take(4)
|
||||
frameLen = frameLenBytes.iterator.getInt
|
||||
frame <- IO.take(frameLen)
|
||||
} yield {
|
||||
val in = frame.iterator
|
||||
|
||||
val n = in.getInt
|
||||
val m = in.getInt
|
||||
|
||||
val a = ArrayBuilder.make[Short]()
|
||||
val b = ArrayBuilder.make[Long]()
|
||||
|
||||
for (i <- 1 to n) {
|
||||
a += in.getShort
|
||||
b += in.getInt
|
||||
}
|
||||
|
||||
val data = Array.ofDim[Double](m)
|
||||
in.getDoubles(data)
|
||||
|
||||
(a.result, b.result, data)
|
||||
}
|
||||
.. includecode:: code/akka/docs/io/BinaryCoding.scala
|
||||
:include: decoding
|
||||
|
||||
This implementation naturally follows the example data format. In a true Scala application, one might, of course, want use specialized immutable Short/Long/Double containers instead of mutable Arrays.
|
||||
|
||||
After extracting data from a ``ByteIterator``, the remaining content can be turned back into a ``ByteString`` using the ``toSeq`` method
|
||||
After extracting data from a ``ByteIterator``, the remaining content can also be turned back into a ``ByteString`` using the ``toSeq`` method
|
||||
|
||||
.. code-block:: scala
|
||||
|
||||
val bytes: ByteString = ...
|
||||
val in: bytes.iterator
|
||||
... = in.getInt()
|
||||
... = in.get...
|
||||
val rest: ByteString = in.toSeq
|
||||
.. includecode:: code/akka/docs/io/BinaryCoding.scala
|
||||
:include: rest-to-seq
|
||||
|
||||
with no copying from bytes to rest involved. In general, conversions from ByteString to ByteIterator and vice versa are O(1) for non-chunked ``ByteString``s and (at worst) O(nChunks) for chunked ByteStrings.
|
||||
|
||||
|
||||
Encoding of data also is very natural, using ``ByteStringBuilder``
|
||||
|
||||
.. code-block:: scala
|
||||
.. includecode:: code/akka/docs/io/BinaryCoding.scala
|
||||
:include: encoding
|
||||
|
||||
implicit val byteOrder = java.nio.ByteOrder.BIG_ENDIAN
|
||||
|
||||
val frameBuilder = ByteString.newBuilder
|
||||
|
||||
val n = a.length
|
||||
val m = data.length
|
||||
|
||||
frameBuilder.putInt(n)
|
||||
frameBuilder.putInt(m)
|
||||
|
||||
for (i <- 0 to n-1) {
|
||||
frameBuilder.putShort(a(i))
|
||||
frameBuilder.putLong(b(i))
|
||||
}
|
||||
frameBuilder.putDoubles(data)
|
||||
val frame = frameBuilder.result()
|
||||
|
||||
The encoded data then can be sent over socket (see ``IOManager``):
|
||||
|
||||
.. code-block:: scala
|
||||
|
||||
socket.send(ByteString.newBuilder.putInt(frame.length).result)
|
||||
socket.send(frame)
|
||||
.. includecode:: code/akka/docs/io/BinaryCoding.scala
|
||||
:include: sending
|
||||
|
||||
|
||||
IO.Handle
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue