scodec variableSizePrefixBytes 转换
scodec variableSizePrefixBytes transformation
我有一个用例,其中 header 可以包含 7 个字节加上可选的 0-15 字节信息,其中大小信息位于第 5 个字节的低 4 位
所以格式是:
4 bytes | 4 bits | 4 bits <- length of extra bytes | 2 bytes | 0-15 extra Bytes
我在下面的案例中对此进行了建模 class
case class FHDR(DevAddr:Long, ADR:Boolean, ADRACKReq:Boolean, ACK:Boolean, FPending:Boolean, FCnt:Int, FOpts:ByteVector)
implicit val FHDRCodec = {
("dev_addr" | uint32L) ::
("adr" | bool) ::
("adr_ack_req" | bool) ::
("ack" | bool) ::
("f_pending" | bool) ::
variableSizePrefixedBytes(uint4,
"f_cnt" | uint16L,
"f_opts" | bytes)
}.as[FHDR]
在这种情况下,根据 scala 文档,我可以使用 variableSizePrefixedBytes
方法对大小和额外字节之间的 2 个额外字节进行建模。
但我做错了,因为编译器无法证明此编解码器可以转换 to/from FHDR
class,我已经盯着这个看了一段时间了, 但我一无所知
本例中的错误是:
error: Could not prove that shapeless.::[Long,shapeless.::[Boolean,shapeless.::[Boolean,shapeless.::[Boolean,shapeless.::[Boolean,shapeless.::[(Int, scodec.bits.ByteVector),shapeless.HNil]]]]]] can be converted to/from FHDR.
}.as[FHDR]
^
重新格式化错误以在中缀位置使用 ::
给出:
error: Could not prove that Long :: Boolean :: Boolean :: Boolean :: Boolean :: (Int, ByteVector) :: HNil can be converted to/from FHDR.
}.as[FHDR]
^
FHDR
的通用表示是 Long :: Boolean :: Boolean :: Boolean :: Boolean :: Int :: ByteVector :: HNil
。这里的问题是 HList
中的最后一个类型是 (Int, ByteVector)
,由 variableSizePrefixedBytes
引起,它具有以下签名:
def variableSizePrefixedBytes[A, B](size: Codec[Int], prefix: Codec[A], value: Codec[B], sizePadding: Int = 0): Codec[(A, B)] = ...
我们需要将该元组展平到外部 HList
结构中,这将导致编解码器的形状与 FHDR
.
的通用表示的形状相匹配
import scodec.bits._
import scodec.codecs._
import shapeless.syntax.std.product._
case class FHDR(DevAddr:Long, ADR:Boolean, ADRACKReq:Boolean, ACK:Boolean, FPending:Boolean, FCnt:Int, FOpts:ByteVector)
implicit val FHDRCodec = {
("dev_addr" | uint32L) ::
("adr" | bool) ::
("adr_ack_req" | bool) ::
("ack" | bool) ::
("f_pending" | bool) ::
variableSizePrefixedBytes(uint4,
"f_cnt" | uint16L,
"f_opts" | bytes
).xmapc(_.toHList)(_.tupled)
}.as[FHDR]
在这里,我们在 Tuple2
上使用 .toHList
,它来自 shapeless.syntax.std.product._
导入。我们还使用 .tupled
来反转该转换。
我有一个用例,其中 header 可以包含 7 个字节加上可选的 0-15 字节信息,其中大小信息位于第 5 个字节的低 4 位 所以格式是:
4 bytes | 4 bits | 4 bits <- length of extra bytes | 2 bytes | 0-15 extra Bytes
我在下面的案例中对此进行了建模 class
case class FHDR(DevAddr:Long, ADR:Boolean, ADRACKReq:Boolean, ACK:Boolean, FPending:Boolean, FCnt:Int, FOpts:ByteVector)
implicit val FHDRCodec = {
("dev_addr" | uint32L) ::
("adr" | bool) ::
("adr_ack_req" | bool) ::
("ack" | bool) ::
("f_pending" | bool) ::
variableSizePrefixedBytes(uint4,
"f_cnt" | uint16L,
"f_opts" | bytes)
}.as[FHDR]
在这种情况下,根据 scala 文档,我可以使用 variableSizePrefixedBytes
方法对大小和额外字节之间的 2 个额外字节进行建模。
但我做错了,因为编译器无法证明此编解码器可以转换 to/from FHDR
class,我已经盯着这个看了一段时间了, 但我一无所知
本例中的错误是:
error: Could not prove that shapeless.::[Long,shapeless.::[Boolean,shapeless.::[Boolean,shapeless.::[Boolean,shapeless.::[Boolean,shapeless.::[(Int, scodec.bits.ByteVector),shapeless.HNil]]]]]] can be converted to/from FHDR.
}.as[FHDR]
^
重新格式化错误以在中缀位置使用 ::
给出:
error: Could not prove that Long :: Boolean :: Boolean :: Boolean :: Boolean :: (Int, ByteVector) :: HNil can be converted to/from FHDR.
}.as[FHDR]
^
FHDR
的通用表示是 Long :: Boolean :: Boolean :: Boolean :: Boolean :: Int :: ByteVector :: HNil
。这里的问题是 HList
中的最后一个类型是 (Int, ByteVector)
,由 variableSizePrefixedBytes
引起,它具有以下签名:
def variableSizePrefixedBytes[A, B](size: Codec[Int], prefix: Codec[A], value: Codec[B], sizePadding: Int = 0): Codec[(A, B)] = ...
我们需要将该元组展平到外部 HList
结构中,这将导致编解码器的形状与 FHDR
.
import scodec.bits._
import scodec.codecs._
import shapeless.syntax.std.product._
case class FHDR(DevAddr:Long, ADR:Boolean, ADRACKReq:Boolean, ACK:Boolean, FPending:Boolean, FCnt:Int, FOpts:ByteVector)
implicit val FHDRCodec = {
("dev_addr" | uint32L) ::
("adr" | bool) ::
("adr_ack_req" | bool) ::
("ack" | bool) ::
("f_pending" | bool) ::
variableSizePrefixedBytes(uint4,
"f_cnt" | uint16L,
"f_opts" | bytes
).xmapc(_.toHList)(_.tupled)
}.as[FHDR]
在这里,我们在 Tuple2
上使用 .toHList
,它来自 shapeless.syntax.std.product._
导入。我们还使用 .tupled
来反转该转换。