Выравнивание байта BitVector после декодирования смещенного значения

Я столкнулся с интересной проблемой со Scodec. У меня есть своеобразная схема кодирования, которая требует выравнивания байтов потока, когда текущий указатель бита mod 8 не равен нулю (не выровнен по ближайшему байту).

Теперь, как правило, это будет обработано byteAligned кодек, но ситуация, похоже, нуждается в глобальном контексте всей операции декодирования.

Вот минимальный пример проблемы

case class Baz(abc : Int, qux : Int)  
case class Foo(bar : Int,
               items : Vector[Baz])

object Foo {
   implicit val codec : Codec[Foo] = (
      ("bar" | uint8L) ::
      ("items" | vectorOfN(uint8L, (
            ("abc" | uint8L) ::
            ("qux" | uint2L)
         ).as[Baz]
      ))).as[Foo]
}

items будет закодирован и декодирован как Vector из Baz Предметы. Обратите внимание, что qux член в Baz представляется в виде 2-битного целого без знака. Мы хотим abc элемент должен быть выровнен по байту, что означает, что во время его декодирования он будет декодировать, и, если поток байтов не выровнен, после декодированных битов должно быть добавлено заполнение (случай C).

Это означает, что для вектора размера 1 (случай A) выходной битовый сектор будет смещен на 6 битов, что хорошо, поскольку больше нет элементов (abc никогда не достигается снова в цикле векторного декодирования).

Вектор размера 2 без байтового выравнивания показан в случае B. Вектор с байтовым выравниванием показан в случае C.

Ниже каждого случая находится комментарий, разбивающий поток битов. 0x0a является шестнадцатеричным для 10 десятичных и 0b01 является двоичным для 1 десятичного числа. Я буду переключаться между ними, когда требуется больше деталей и когда поток не выровнен по байту.

Случай А

Codec.encode(Foo(10, Vector(Baz(4,1))))
res43: Attempt[BitVector] = Successful(BitVector(26 bits, 0x0a01044))
// bar  N items   abc(0)  qux(0)
// 0x0a   0x01     0x04    0b01   

Дело Б

Codec.encode(Foo(10, Vector(Baz(4,1), Baz(15,3))))
res42: Attempt[BitVector] = Successful(BitVector(36 bits, 0x0a020443f))
// bar  N items   abc(0)  qux(0)    abc(1)    qux(1)
// 0x0a   0x02     0x04    0b01   0b00001111   0b11 

Дело С

Codec.encode(Foo(10, Vector(Baz(4,1), Baz(15,3))))
res42: Attempt[BitVector] = Successful(BitVector(42 bits, 0x0a020443c0c))
// bar  N items   abc(0)  qux(0)    abc(1)    padding   qux(1)
// 0x0a   0x02     0x04    0b01   0b00001111  0b000000   0b11 

Еще один способ взглянуть на дело C - это развернуть кодеки.

// bar     N items   abc(0)     qux(0)   abc(1)    padding       qux(1)
(uint8L :: uint8L :: uint8L :: uint2L :: uint8L :: ignore(6) :: uint2L).
   dropUnits.encode(10 :: 2 :: 4 :: 1 :: 15 :: 3 :: HNil)
res47: Attempt[BitVector] = Successful(BitVector(42 bits, 0x0a020443c0c))

Обратите внимание, что не было никаких отступов после abc(0) поскольку поток был выровнен по байту в этой точке. В abc(1) это не было выровнено из-за декодирования qux(0), После выравнивания qux будет декодировать на выровненной границе. Мы всегда хотим qux декодировать в позиции, выровненной по байту.

Мне нужен какой-то метод для получения глобального контекста, чтобы выяснить, выровнен ли текущий битовый указатель в общем BitVector. Если нет, мне нужен кодек, чтобы разумно знать, когда он не декодирует на выровненной границе, и корректировать поток после декодирования его текущего значения.

Я знаю, что кодеки могут получить текущий битовый поток для декодирования, но они не имеют представления о том, где они находятся в общем битовом потоке.

Любое направление или код будет наиболее ценным.

PS

Если вы хотите пройти тестирование в Аммоните, вам нужно это запустить

load.ivy("org.scodec" %% "scodec-core" % "1.8.3")
import scodec.codecs._
import scodec._
import shapeless._ 

При копировании и вставке необходимо начать с { чтобы убедиться, что case-класс и case-объект определены одновременно.

0 ответов

Другие вопросы по тегам