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))
Try