Преобразование scodec variableSizePrefixBytes
У меня есть случай использования, когда заголовок может содержать 7 байтов плюс необязательный 0-15 байт информации, где информация о размере находится в младших 4 битах 5-го байта, поэтому формат:
4 bytes | 4 bits | 4 bits <- length of extra bytes | 2 bytes | 0-15 extra Bytes
И я смоделировал это в следующем случае класса
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 Docs в этом случае я могу использовать variableSizePrefixedBytes
метод для моделирования 2 дополнительных байтов между размером и дополнительными байтами.
Но я делаю что-то не так, так как компилятор не может доказать, что этот кодек может быть преобразован в / из FHDR
класс, я смотрю на это некоторое время сейчас, но я не знаю,
1 ответ
Ошибка в этом случае:
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]
Здесь мы используем .toHList
на Tuple2
, который исходит от shapeless.syntax.std.product._
Импортировать. Мы также используем .tupled
чтобы изменить это преобразование.