How to ignore Codec after using it to limit size bytes

179 Views Asked by At

I would create a model for the KMIP protocols that works with TTLV encoding (Tag, Type, Length, Value)

The ttlv function is "high level" and accepts the tag, the type and the codec of the value.

 def ttlv[A<:HList](tag:ByteVector, itype:ByteVector, value: Codec[A]) =
   constant(tag) :: constant(itype) :: 
   (uint32 >>:~ {
     case length => limitedSizeBytes(length, value)
   })

The result is a Codec[Unit :: Unit :: Long :: A]. However, I would have a Codec[Unit :: Unit :: Unit :: A] (or Codec[A]) to cast the codec to a case class with only the value A. How to ignore the uint32 after used by limitedSizeBytes ? Otherwise I am interested for comments for better approaches.


Here are case class examples:

case class RequestHeader(protocol:Int)
case class RequestPayload(payload:CompromiseDate, name:CertificateName)
case class RequestMessage(header:RequestHeader, payload: RequestPayload)
case class CompromiseDate(value:Int)
case class CertificateName(value:String)

More high level functions like ttlvStructure

def ttlvStructure[A<:HList](tag:ByteVector, struct:Codec[A]) =
  ttlv(tag, hex"01", struct)
def ttlvTextString(tag:ByteVector) =
  ttlv(tag, hex"07", utf8.hlist)
def ttlvInt(tag:ByteVector) =
  ttlv(tag, hex"02", int32.hlist)

And the final codec:

implicit val certificateNameCodec =
  ttlvTextString(hex"420020").as[CertificateName]

implicit val compromiseDateCodec =
  ttlvInt(hex"420021").as[CompromiseDate]

implicit val requestPayloadCodec =
  ttlvStructure(hex"420003", Codec[CompromiseDate] :: Codec[CertificateName]).as[RequestPayload]

implicit val requestHeaderCodec =
  ttlvInt(hex"420002").as[RequestHeader]

implicit val requestMessageCodec =
  ttlvStructure(hex"420001", Codec[RequestHeader] :: Codec[RequestPayload]).as[RequestMessage]

Example of object to encode:

val m = RequestMessage(
      RequestHeader(14),
      RequestPayload(
        CompromiseDate(8),
        CertificateName("certificate name")
      )
    )

Solution:

variableSizeBytesLong is here to do what I want:

def ttlv[A<:HList](tag:ByteVector, itype:ByteVector, value: Codec[A]): Codec[A] =
    (constant(tag) :~>: constant(itype) :~>: variableSizeBytesLong(uint32, value))
1

There are 1 best solutions below

1
On

Try

val defaultLength: Long = ???

def ttlv[A<:HList](tag:ByteVector, itype:ByteVector, value: Codec[A]): Codec[A] =
  constant(tag) :~>: constant(itype) :~>:
    (uint32 >>:~ (length => limitedSizeBytes(length, value))).xmap[A](_.tail, defaultLength :: _)