Как динамически предоставить N кодеков для обработки полей как VectorCode c для записи двоичных полей, которые не содержат байтов размера - PullRequest
1 голос
/ 06 января 2020

Учитывая эту функцию в декодере:

  final def decodeCollect[F[_], A](dec: Decoder[A], limit: Option[Int])(buffer: BitVector)(implicit cbf: Factory[A, F[A]]): Attempt[DecodeResult[F[A]]] = {

Что мне действительно нужно, так это de c: Vector [Decoder [A]] , например:

  final def decodeCollect[F[_], A](dec: Vector[Decoder[A]], limit: Option[Int])(buffer: BitVector)(implicit cbf: Factory[A, F[A]]): Attempt[DecodeResult[F[A]]] = {

для обработки двоичного формата, в котором есть поля, которые не описывают себя. В начале файла находятся записи описаний, и из них приходят размеры полей, которые необходимо применять позже в записях данных. Поэтому я хочу составить список декодеров и применить его N раз, где N - это количество декодеров.

Я мог бы написать новую функцию, смоделированную на decodeCollect, но она требует неявной фабрики, так что я, вероятно, придется скомпилировать библиотеку scode c и добавить ее.

Существует ли более простой подход с использованием того, что существует в библиотеке scode c? Есть ли способ борьбы с фабрикой или другой подход?

1 Ответ

0 голосов
/ 10 января 2020

Я наконец взломал решение в кодовой базе c. Теперь, когда эта дверь открыта, я буду добавлять все, что мне нужно, пока у меня не получится.

  final def decodeNCollect[F[_], A](dec: Vector[Decoder[A]])(buffer: BitVector)(implicit cbf: Factory[A, F[A]]): Attempt[DecodeResult[F[A]]] = {
    val bldr = cbf.newBuilder
    var remaining = buffer
    var count = 0
    val maxCount = dec.length
    var error: Option[Err] = None
    while (count < maxCount && remaining.nonEmpty) {
      dec(count).decode(remaining) match {
        case Attempt.Successful(DecodeResult(value, rest)) =>
          bldr += value
          count += 1
          remaining = rest
        case Attempt.Failure(err) =>
          error = Some(err.pushContext(count.toString))
          remaining = BitVector.empty
      }
    }
    Attempt.fromErrOption(error, DecodeResult(bldr.result, remaining))
  }

  final def encodeNSeq[A](encs: Vector[Encoder[A]])(seq: collection.immutable.Seq[A]): Attempt[BitVector] = {
    if (encs.length != seq.length)
      return Attempt.failure(Err("encodeNSeq: length of coders and items does not match"))
    val buf = new collection.mutable.ArrayBuffer[BitVector](seq.size)
    ((seq zip (0 until encs.length)): Seq[(A, Int)]) foreach { case (a, i) =>
      encs(i).encode(a) match {
        case Attempt.Successful(aa) => buf += aa
        case Attempt.Failure(err) => return Attempt.failure(err.pushContext(buf.size.toString))
      }
    }
    def merge(offset: Int, size: Int): BitVector = size match {
      case 0 => BitVector.empty
      case 1 => buf(offset)
      case n =>
        val half = size / 2
        merge(offset, half) ++ merge(offset + half, half + (if (size % 2 == 0) 0 else 1))
    }
    Attempt.successful(merge(0, buf.size))
  }


private[codecs] final class VectorNCodec[A](codecs: Vector[Codec[A]]) extends Codec[Vector[A]] {

  def sizeBound = SizeBound(0, Some(codecs.length.toLong))

  def encode(vector: Vector[A]) = Encoder.encodeNSeq(codecs)(vector)

  def decode(buffer: BitVector) =
    Decoder.decodeNCollect[Vector, A](codecs)(buffer)

  override def toString = s"vector($codecs)"

}

  def vectorOf[A](valueCodecs: Vector[Codec[A]]): Codec[Vector[A]] =
    provide(valueCodecs.length).
      flatZip { count => new VectorNCodec(valueCodecs) }.
      narrow[Vector[A]]({ case (cnt, xs) =>
        if (xs.size == cnt) Attempt.successful(xs)
        else Attempt.failure(Err(s"Insufficient number of elements: decoded ${xs.size} but should have decoded $cnt"))
      }, xs => (xs.size, xs)).
      withToString(s"vectorOf($valueCodecs)")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...