Skip to content

Instantly share code, notes, and snippets.

@kubukoz
Created May 21, 2021 17:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kubukoz/9c40a24acfde0c1ec60b7108473eb26f to your computer and use it in GitHub Desktop.
Save kubukoz/9c40a24acfde0c1ec60b7108473eb26f to your computer and use it in GitHub Desktop.
Deriving a nice Show in scala 3
import scala.deriving.*
import scala.compiletime.*
trait Show[T]:
extension (t: T) def show: String
given Show[String] = s => s
given Show[Int] = _.toString
object Show:
private inline def instances[T <: Tuple]: List[Show[Any]] =
summonAll[Tuple.Map[T, Show]].toList.asInstanceOf[List[Show[Any]]]
private inline def deriveAll[T <: Tuple]: Tuple = inline erasedValue[T] match {
case _: EmptyTuple => EmptyTuple
case _: (h *: t) =>
summonFrom { case given Mirror.Of[`h`] =>
derived[h]
} *: deriveAll[t]
}
inline def derived[T](
using m: Mirror.Of[T]
): Show[T] = new Show[T]:
extension (t: T)
def show: String =
inline m match {
case p: Mirror.ProductOf[T] =>
val label = summonInline[ValueOf[m.MirroredLabel]].value
val fields = t.asInstanceOf[Product].productElementNames.toList
val values = t.asInstanceOf[Product].productIterator.toList
val paramString =
if (fields.nonEmpty)(fields
.zip(values)
.zip(instances[p.MirroredElemTypes]))
.map { case ((name, value), show) =>
s"$name = ${show.show(value)}"
}
.mkString("(", ", ", ")")
else ""
s"""$label$paramString"""
case s: Mirror.SumOf[T] =>
deriveAll[s.MirroredElemTypes].toList.asInstanceOf[List[Show[Any]]](s.ordinal(t)).show(t)
}
enum Permission derives Show:
case View
case Edit
case Both(p: Permission, p2: Permission)
import Show.given
@main def run =
println((Permission.Both(Permission.View, Permission.Edit): Permission).show)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment