我必须为具有以下规范的消息创建编解码器 消息长度由一个字节表示,其中最低有效位是一个扩展标志,当置位时表示必须使用以下(可选)字节作为最高有效字节。 (希望它有意义)它可以描述如下:
+----------------------------------------------------------------------------------+ | LENGTH | | | +----------------------------------+-----+-+---------------------------------------+ | | | | | | Len1 (LSB) | Ext | | Len2 (MSB) - Optional | +----+----+----+----+----+----+----+-----+ +----+----+----+----+----+----+----+----+ | | | | | | | | | | | | | | | | | | | | | | | | | | + | | | | | | | | | | +----+----+----+----+----+----+----+--|--+ +----+----+----+----+----+----+----+----+ | | v Boolean: if true then Len2 is used else only Len1
将遵循的数据长度由此字段确定。我想使用编解码器以及预定义的编解码器和组合器。 我想它将涉及使用flatZip,但我不清楚如何将flatZip合并到HList组合器中。 任何指向示例或文档的指针都将非常感激。
答案 0 :(得分:4)
执行此操作的一种方法是使用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]
,它以编码的字符串字节为前缀,以字节为单位,根据上面定义的方案编码。