borer-compat-cats

The borer-compat-cats module provides default codecs for the following cats.data._ data structures from the cats cats-core package:

  • Chain[A]
  • Ior[A, B]
  • NonEmptyChain[T]
  • NonEmptyList[T]
  • NonEmptyMap[T]
  • NonEmptySet[T]
  • NonEmptyVector[T]
  • Validated[A, B]

Installation

Include the borer-compat-cats module as a dependency (see the Getting Started chapter for details) and

import io.bullet.borer.compat.cats.*

With this import in place borer will seamlessly encode and decode instances of the types listed above, provided that encoders and/or decoders are available for the respective “inner” types.

Encoding Strategies

While the encoding strategies for most of the above data structures should be relatively straight-forward there are two types, for which there is no clear default encoding:

  • Ior[A, B]
  • Validated[A, B]

The encodings implemented by borer-compat-circe aim for best time and space efficiency, not “readability”.

One easy way to optimize for self-describability rather than efficiency would be to rely on borer-derivation instead. Here is an example contrasting the difference:

sourceimport cats.data.Ior
import io.bullet.borer.{Decoder, Encoder, Codec, Json}

val value = List(
  Ior.Left(1),
  Ior.Right("foo"),
  Ior.Both(42, "bar")
)

// the Ior encoding of `borer-compat-circe` is optimized for efficiency
{
  import io.bullet.borer.compat.cats.*

  Json.encode(value).toUtf8String ==>
  """[[0,1],[1,"foo"],[2,42,"bar"]]"""
}

// the map-based codec generated by `borer-derivation` produces encodings
// that self-describe better, but are less efficient space and time-wise
{
  given [A: Encoder: Decoder, B: Encoder: Decoder]: Codec[Ior[A, B]] =
    MapBasedCodecs.deriveAllCodecs[Ior[A, B]]

  Json.encode(value).toUtf8String ==>
  """[{"Left":{"a":1}},{"Right":{"b":"foo"}},{"Both":{"a":42,"b":"bar"}}]"""
}

See the module sources for full details.