Комбинаторы Scodec: Заголовок содержит магическое число, которое используется для различения типов

Я ищу способ приблизиться к протоколу, как в следующем примере:

case class Request(bodyType: Int, foo: Int, bar: Int, body: RequestBody)

sealed trait RequestBody
case class Read(key: String) extends RequestBody
case class Write(key: String, value: Array[Byte]) extends RequestBody 

Вот, bodyType == 0 будет стоять за Read, а также bodyType != 0 будет кодировать Write, Обратите внимание, что есть несколько полей, отделяющих дискриминатор от различаемого значения.

Я видел пример с порядком байтов. Но, насколько я понимаю, этот закодированный дискриминатор "кальмара" не будет в оба конца. Как правильно решить эту проблему?

1 ответ

Решение

Есть несколько способов сделать это, но я использовал один из них:

import scodec._
import scodec.codecs._
import scodec.bits._

case class Request(bodyType: Int, foo: Int, bar: Int, body: RequestBody)

sealed trait RequestBody
case class Read(key: String) extends RequestBody
object Read {
  implicit val codec: Codec[Read] = ("key" | utf8).as[Read]
  implicit val discriminator: Discriminator[RequestBody, Read, Int] = Discriminator(0)
}
case class Write(key: String, value: ByteVector) extends RequestBody
object Write {
  implicit val codec: Codec[Write] = {
    ("key"   | utf8  ) ::
    ("value" | bytes )
  }.as[Write]
  implicit val discriminator: Discriminator[RequestBody, Write, Int] = Discriminator(1)
}

object Request {
  implicit val codec: Codec[Request] = {
    ("bodyType" | uint16 ).flatPrepend { bodyType =>
    ("foo"      | uint16 ) ::
    ("bar"      | uint16 ) ::
    ("body"     | Codec.coproduct[RequestBody].discriminatedBy(provide(bodyType)).auto)
  }}.as[Request]
} 
Другие вопросы по тегам