简体   繁体   English

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

[英]Scodec: How to create a codec for an optional byte

I must create a codec for a message that has the following specification The message length is indicated by a byte of which the least significant bit is an extension flag that, when set indicates that the following (optional) byte must be used as the most significant byte. 我必须为具有以下规范的消息创建一个编解码器。消息长度由一个字节指示,该字节的最低有效位是扩展标志,当置位时表示必须使用以下(可选)字节作为最高有效位字节。 (Hope it make sense) It can be depicted as follows: (希望有道理)可以描述如下:

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

The length of the data that will follow is determined by this field(s). 后续数据的长度由该字段决定。 I would like to use the codec along with predefined codecs and combinators. 我想将编解码器与预定义的编解码器和组合器一起使用。 I guess it will involve using flatZip but I am not clear on how to incorporate flatZip into an HList combinator. 我想它将涉及使用flatZip,但是我不清楚如何将flatZip合并到HList组合器中。 Any pointers to examples or documentation will be much appreciated. 任何指向示例或文档的指针将不胜感激。

One way to do this is using the scodec.codecs.optional combinator, which returns a Codec[Option[A]] given a Codec[Boolean] and a Codec[A] . 一种实现方法是使用scodec.codecs.optional组合器,该组合Codec[Option[A]]给定Codec[Boolean]Codec[A]返回Codec[Option[A]] Codec[A]

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

This gives us a codec of (Int, Option[Int]) - we need to convert this to a codec of Int . 这为我们提供了(Int, Option[Int])的编解码器-我们需要将其转换为Int的编解码器。 To do so, we'll need to provide a conversion from Int to (Int, Option[Int]) and another conversion in the reverse direction. 为此,我们需要提供从Int(Int, Option[Int])转换,以及相反的转换。 We know the size field is at most 2^15 - 1 (7 LSB bits and 8 MSB bits), so converting from (Int, Option[Int]) to Int is total, whereas converting in the reverse direction could possibly fail -- for example, 2^16 cannot be represented in this structure. 我们知道大小字段最多为2 ^ 15-1(7个LSB位和8个MSB位),因此从(Int, Option[Int])Int转换是总计,而在反向方向转换可能会失败-例如,在此结构中不能表示2 ^ 16。 Hence, we can use widen to do the conversion: 因此,我们可以使用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))
  })

Finally, we can use this size codec to encode a variable length structure via variableSizeBytes : 最后,我们可以使用此大小编解码器通过variableSizeBytes对可变长度结构进行编码:

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

This gives us a Codec[String] which prefixes the encoded string bytes with the size in bytes, encoded according to the scheme defined above. 这为我们提供了一个Codec[String] ,它根据上面定义的方案对已编码的字符串字节加上以字节为单位的大小作为前缀。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM