你可以尝试使用consume()
建设一个编解码器,并没有建立Outer
对象开始:
case class OuterExpanded(
fieldBefore: Int, // Field before number of items in the binary encoding
fieldAdter: Int, // Field after number of items in the binary encoding
items: Vector[Item] // Encoded items
)
// Single Item codec
def itemC: Codec[Item] = (int32 :: int32).as[Item]
def outerExpandedC: Codec[OuterExpanded] = (
int32 :: // Field before count
int32.consume(c => // Item count
int32 :: // Field after count
vectorOfN(provide(c), itemC)) // 'consume' (use and forget) the count
(_.tail.head.length) // provide the length when encoding
).as[OuterExpanded]
如上定义,你得到的编码时,以下几点:outerExpandedC.encode(OuterExpanded(-1, -1, Vector(Item(1,2), Item(3,4))))
回报
Successful(BitVector(224 bits,
0xffffffff00000002fffffffe00000001000000020000000300000004))
^ ^ ^ ^-------^-> First Item
|-1 | |-2
|Vector length inserted between the two header fields
之后,您可以xmap()
Codec[OuterExpanded]
将其他标题字段一起打包到它们自己的对象中。即(增加了两个转换方法来Outer
和OuterExpanded
):
def outerC: Codec[Outer] =
outerExpandedC.xmap(_.toOuter,_.expand)
case class OuterExpanded(fieldBefore: Int, fieldAfter: Int, items: Vector[Item]) {
def toOuter = Outer(Hdr(fieldBefore,fieldAfter), items)
}
case class Outer(header: Hdr, items: Vector[Item]) {
def expand = OuterExpanded(header.beforeField1, header.beforeField1, items)
}
这大概可以适应更复杂的情况,虽然我不是无形的异类名单完全familar - 或HList
- 有可能是更好的方法来达到向量的长度,而不是在上面的例子中调用_.tail.head.length
,特别是如果最终在编码值的数目后面有多个字段。
另外,Codec scaladoc是一个不错的地方,发现有用的运营商
好的。与“Atomic ...”解决方案相比有点重复,但拥有“无状态”编解码器的优势。除非还有更好的解决办法,否则我会说这是公认的答案。 –