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

标签 scodec

我必须为具有以下规范的消息创建编解码器 消息长度由一个字节指示,该字节的最低有效位是扩展标志,当设置该标志时,指示必须使用以下(可选)字节作为最高有效字节。 (希望有意义)可以这样描述:

+----------------------------------------------------------------------------------+
|                                    LENGTH                                        |
|                                                                                  |
+----------------------------------+-----+-+---------------------------------------+
|                                  |     | |                                       |
|               Len1 (LSB)         | Ext | |         Len2 (MSB) - Optional         |
+----+----+----+----+----+----+----+-----+ +----+----+----+----+----+----+----+----+
|    |    |    |    |    |    |    |     | |    |    |    |    |    |    |    |    |
|    |    |    |    |    |    |    |  +  | |    |    |    |    |    |    |    |    |
+----+----+----+----+----+----+----+--|--+ +----+----+----+----+----+----+----+----+
                                      |
                                      |
                                      v
                        Boolean: if true then Len2 is used
                                else only Len1
    

随后的数据长度由该字段确定。我想将编解码器与预定义的编解码器和组合器一起使用。 我想这将涉及使用 flatZip,但我不清楚如何将 flatZip 合并到 HList 组合器中。 任何指向示例或文档的指针都将不胜感激。

最佳答案

一种方法是使用 scodec.codecs.optional 组合器,它返回一个 Codec[Option[A]] 给定一个 Codec[Boolean ] 和一个 Codec[A].

val structure: Codec[(Int, Option[Int])] = uint(7) ~ optional(bool, uint8)

这为我们提供了 (Int, Option[Int]) 的编解码器 - 我们需要将其转换为 Int 的编解码器。为此,我们需要提供从 Int(Int, Option[Int]) 的转换以及反向的另一个转换。我们知道大小字段最多为 2^15 - 1(7 个 LSB 位和 8 个 MSB 位),因此从 (Int, Option[Int]) 转换为 Int是总的,而反向转换可能会失败——例如,2^16 不能在这个结构中表示。因此,我们可以使用 widen 来进行转换:

val size: Codec[Int] = structure.widen[Int](
  { case (lsb, msb) => lsb + msb.map(_ << 7).getOrElse(0) },
  { sz => 
    val msb = sz >>> 7
    if (msb > 255 || msb < 0) Attempt.failure(Err(s"invalid size $sz"))
    else Attempt.successful((sz & 0x7F, if (msb > 0) Some(msb) else None))
  })

最后,我们可以通过variableSizeBytes使用这个大小的编解码器来编码一个可变长度的结构:

val str: Codec[String] = variableSizeBytes(size, ascii)

这为我们提供了一个 Codec[String],它在编码后的字符串字节前加上字节大小,根据上面定义的方案进行编码。

关于Scodec:如何为可选字节创建编解码器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30248412/

相关文章:

scala - scodec 忽略 hlist 和 case 类之间的编解码器转换中的最后一个值

scala - 将 List[OF[C]] 转换为 F[B],其中案例类 B 的类型与 A 对齐

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

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

scala - 无形:在 HList 上反转 filterNot

scala - scodec variableSizePrefixBytes 转换

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

c - 在 Scala 中映射 C 结构