scodec - 编码向量长度字段不与向量相邻

标签 scodec

我有以下我喜欢编码的结构。 我知道如果大小字段直接位于矢量数据前面,我可以使用 vector() 对矢量进行编码。但这里编码向量大小的字段不相邻。

case class Item(
    address: Int,
    size: Int,
)
case class Header {
    // lots of other fields before
    numOfItems: Int,
    // lots of other fields after
}
case class Outer(
    hdr: Header,
    items: Vector[]
)

外部解码正常:

从位向量中读取 Header.numOfItems 并使用 vectorOfN(provide(hdr.numOfItems, Item.codec)) 创建项目

外部编码是问题:

编码时,我希望从 items.length 中获取 numOfItem。 我知道我可以在更新 items Vector 时使用附加代码或使用“编码回调之前”之类的内容设置 numOfItems。

问题是是否有更优雅的解决方案。对我来说 Header.numOfItemsOuter.items.length 是多余的,所以理想情况下只有 编码器应该了解 numOfItems。

最佳答案

您可以尝试使用 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]将其他 header 字段打包到它们自己的对象中。即(向 OuterOuterExpanded 添加两种转换方法):

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)
}

这可能适用于更复杂的情况,尽管我并不完全熟悉无形状的异构列表 - 或 HList – 可能有更好的方法来获取向量的长度,而不是调用 _.tail.head.length在上面的示例中,尤其是在编码值数量后面有多个字段时。

此外,Codec scaladoc是发现有用运算符的好地方

关于scodec - 编码向量长度字段不与向量相邻,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40151072/

相关文章:

scala - scodec variableSizePrefixBytes 转换

scala - Scodec:Coproducts 找不到参数 auto 的隐式值:scodec.codecs.CoproductBuilderAuto

scala - 为递归数据结构定义 `Codec`

scala - 编解码器组合器 : Header contains magic number that is used to discriminate types

scala - 展平任意嵌套的编解码器?

scala - 记录是按层次区分的

scala - 以 Codec 表示形式有效打包 Long 列表

Scodec:如何为可选字节创建编解码器