3

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

+-------------------------------------------------- ---------------------------------+
| 长度 |
| |
+---------------------------------+-----+-+------ ---------------------------------+
| | | | |
| Len1 (LSB) | 分机 | | Len2 (MSB) - 可选 |
+----+----+----+----+----+----+----+-----+ +----+-- --+----+----+----+----+----+----+
| | | | | | | | | | | | | | | | | |
| | | | | | | | + | | | | | | | | | |
+----+----+----+----+----+----+----+--|--+ +----+-- --+----+----+----+----+----+----+
                                      |
                                      |
                                      v
                        布尔值:如果为真,则使用 Len2
                                否则只有 Len1
    

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

4

1 回答 1

8

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

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

这为我们提供了一个编解码器(Int, Option[Int])- 我们需要将其转换为Int. 为此,我们需要提供从Intto的转换(Int, Option[Int])和反向的另一个转换。我们知道大小字段最多为 2^15 - 1(7 个 LSB 位和 8 个 MSB 位),因此从(Int, Option[Int])to转换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]以字节大小为单位的编码字符串字节的前缀,根据上面定义的方案进行编码。

于 2015-05-15T12:25:15.833 回答