Skip to content

Instantly share code, notes, and snippets.

@Arneball
Last active June 27, 2018 19:32
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Arneball/fe41dae3543c5f681c57 to your computer and use it in GitHub Desktop.
Save Arneball/fe41dae3543c5f681c57 to your computer and use it in GitHub Desktop.
object ToFromMap {
implicit def materialize[T]: ToFromMap[T] = macro impl[T]
def impl[T: c.WeakTypeTag](c: Context): c.Expr[ToFromMap[T]] = {
import c.universe._
val wt = weakTypeOf[T]
// Gets the type parameters, eg Holder[T, J] => List(T, J)
val baseTypes = wt.baseClasses.head.asType.typeParams.map{ _.asType.toType }
// Gives a Map(T -> Int, J -> Double) if we are extracting Holder[Int, Double]
val myTypes = baseTypes zip wt.typeArgs toMap;
println(myTypes)
def replace(t: Type) = t.map{
case t if myTypes.contains(t) => myTypes(t)
case t => t
}
val (getters, setters) = wt.decls.collect{
case m: MethodSymbol if m.isCaseAccessor =>
val name = m.name
val t = m.returnType
val encName = m.name.encodedName.toString
println("Orig: " + t.typeArgs)
val recursed = replace(t)
println("New: " + recursed)
q"$encName -> t.$m" -> q"$name = map($encName).asInstanceOf[$recursed]"
}.unzip
c.Expr[ToFromMap[T]]{
q"""new ToFromMap[$wt] {
def toMap(t: $wt) = Map(..$getters)
def fromMap(map: Map[String, Any]) = new $wt(..$setters)
}"""
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment