Skip to content

Instantly share code, notes, and snippets.

@pomadchin
Last active December 7, 2019 00:34
Show Gist options
  • Save pomadchin/f24480f148e614d99997d1eb5dbd03dd to your computer and use it in GitHub Desktop.
Save pomadchin/f24480f148e614d99997d1eb5dbd03dd to your computer and use it in GitHub Desktop.
Auto derivation of Circe codecs for shapeless Newtypes and TaggedTypes
import io.circe.{Decoder, Encoder}
trait Implicits {
/** Derive circe codecs for newtypes and tagged types. */
implicit def coercibleEncoder[R, N](implicit ev: Coercible[Encoder[R], Encoder[N]], R: Encoder[R]): Encoder[N] = ev(R)
implicit def coercibleDecoder[R, N](implicit ev: Coercible[Decoder[R], Decoder[N]], R: Decoder[R]): Decoder[N] = ev(R)
}
import shapeless.newtype.Newtype
/** Coercion to derive [[shapeless.newtype.Newtype]] and [[shapeless.tag.Tagged]] type classes */
trait Coercible[A, B] {
def apply(a: A): B = a.asInstanceOf[B]
}
object Coercible {
implicit def newTypeToCoercible[R: * => O, O]: Coercible[R, Newtype[R, O]] = new Coercible[R, Newtype[R, O]] { }
implicit def newTypeToCoercibleK[F[_], R: Coercible[*, Newtype[R, O]]: * => O, O]: Coercible[F[R], F[Newtype[R, O]]] = new Coercible[F[R], F[Newtype[R, O]]] { }
implicit def taggedTpeToCoercible[T, U]: Coercible[T, T @@ U] = new Coercible[T, T @@ U] { }
implicit def taggedTypeToCoercibleK[F[_], T: Coercible[*, T @@ U], U]: Coercible[F[T], F[T @@ U]] = new Coercible[F[T], F[T @@ U]] { }
}
package object derivation {
// to workaround https://github.com/scala/bug/issues/8740
type @@[+T, U] <: shapeless.tag.@@[T, U]
// required to use shapeless.tag
implicit def coerce[T, U](t: shapeless.tag.@@[T, U]): T @@ U = t.asInstanceOf[T @@ U]
// alias in order not to cause extra coercion call above
def stag[T, U](value: T): T @@ U = shapeless.tag[U][T](value)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment