Skip to content

Instantly share code, notes, and snippets.

@ghostdogpr
Created May 3, 2020 08:54
Show Gist options
  • Save ghostdogpr/875ed2db65edff6209fed40e9721a882 to your computer and use it in GitHub Desktop.
Save ghostdogpr/875ed2db65edff6209fed40e9721a882 to your computer and use it in GitHub Desktop.
import scala.deriving._
import scala.quoted._
import scala.quoted.matching._
import scala.compiletime._
trait Show[T] {
def show(x: T): String
}
object Show {
inline def tryShow[T](x: T): String = summonInline[Show[T]].show(x)
inline def showElems[Elems <: Tuple, Labels <: Tuple](n: Int)(x: Any): List[String] =
inline erasedValue[Elems] match {
case _: (elem *: elems1) =>
inline erasedValue[Labels] match {
case _: (label *: labels1) =>
val formal = constValue[label]
val actual = tryShow(productElement[elem](x, n))
s"$formal = $actual" :: showElems[elems1, labels1](n + 1)(x)
}
case _: Unit =>
Nil
}
inline def showCase[T](x: Any, m: Mirror.ProductOf[T]): String = {
val label = constValue[m.MirroredLabel]
inline m match {
case m: Mirror.Singleton => label
case _ => showElems[m.MirroredElemTypes, m.MirroredElemLabels](0)(x).mkString(s"$label(", ", ", ")")
}
}
inline def showCases[Alts <: Tuple](n: Int)(x: Any, ord: Int): String =
inline erasedValue[Alts] match {
case _: (alt *: alts1) =>
if (ord == n) showCase(x, summonInline[Mirror.ProductOf[`alt`]])
else showCases[alts1](n + 1)(x, ord)
case _: Unit =>
throw new MatchError(x)
}
inline def derived[T]: Show[T] =
summonFrom {
case ev: Mirror.Of[T] =>
inline ev match {
case m: Mirror.SumOf[T] =>
new Show[T] {
def show(x: T): String = {
val ord = m.ordinal(x)
showCases[m.MirroredElemTypes](0)(x, ord)
}
}
case m: Mirror.ProductOf[T] =>
new Show[T] {
def show(x: T): String = {
showCase(x, m)
}
}
}
}
implicit object IntShow extends Show[Int] {
def show(x: Int): String = x.toString
}
implicit object StringShow extends Show[String] {
def show(x: String): String = x
}
// implicit object BooleanShow extends Show[Boolean] {
// def show(x: Boolean): String = x.toString
// }
}
@main def showTest() = {
import Show._
case class Address(street: String, a: Boolean)
case class Person(name: String, address: Address)
implicit inline def showGen[T]: Show[T] = Show.derived[T]
println(showGen[Address].show(Address("a", true)))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment