I have the following structure I like to encode. I'm aware that I can encode a vector with vector() if the size field is directly in front of the vector data. But here the field encoding the vector size is not adjacent.
case class Item(
address: Int,
size: Int,
)
case class Header {
// lots of other fields before
numOfItems: Int,
// lots of other fields after
}
case class Outer(
hdr: Header,
items: Vector[]
)
Decoding of Outer is OK:
Header.numOfItems is read from the bit vector and items is created with vectorOfN(provide(hdr.numOfItems, Item.codec))
Encoding of Outer is the problem:
When encoding I would like to have numOfItem be taken from the items.length. I'm aware that I could set numOfItems with additional code when the items Vector is updated or with something like a "before encoding callback".
The question is if there is a more elegant solution. To me Header.numOfItems is redundant with Outer.items.length, so ideally only the
Encoder should know about numOfItems.
You could try building a Codec using
consume()and start without building theOuterobject:As defined above, you get the following when encoding:
outerExpandedC.encode(OuterExpanded(-1, -1, Vector(Item(1,2), Item(3,4))))returnsAfterwards, you can
xmap()theCodec[OuterExpanded]to pack the other header fields together into their own object. Ie (adding two conversion methods toOuterandOuterExpanded):This can probably be adapted to more complex cases, though I'm not entirely familar with shapeless' heterogeneous lists – or
HList– and there might be nicer ways to get to the length of the vector rather than calling_.tail.head.lengthin the example above, especially if you end up with more than one field after the number of encoded values.Also, the Codec scaladoc is a nice place to discover useful operators