Skip to content

Instantly share code, notes, and snippets.

@echojc
Last active February 26, 2016 05:21
Show Gist options
  • Save echojc/ab4c7d2d758ab0f78442 to your computer and use it in GitHub Desktop.
Save echojc/ab4c7d2d758ab0f78442 to your computer and use it in GitHub Desktop.
trait MapReader[T] {
// should really return Option[T], but let's keep it simple in this example
def read(map: Map[String, Any], key: String): T
}
object MapReader extends MapReaderLowPriorityImplicits {
// convenience method to retrieve implicit instance explicitly
def apply[T: MapReader]: MapReader[T] = implicitly[MapReader[T]]
// these implicits are always implicitly available as long as `MapReader` is in scope
implicit object IntMapReader extends MapReader[Int] {
def read(map: Map[String, Any], key: String): Int =
map(key).asInstanceOf[Int]
}
implicit object StringMapReader extends MapReader[String] {
def read(map: Map[String, Any], key: String): String =
map(key).toString
}
// etc. for all the basic types
}
// these are only attempted if none of the implicits in the companion object work
trait MapReaderLowPriorityImplicits {
implicit def caseClassMapReader[T]: MapReader[T] = macro caseClassMapReaderImpl
def caseClassMapReaderImpl[T: c.WeakTypeTag](c: Context): c.Expr[MapReader[T]] = {
// ...
// rest of the code from http://blog.echo.sh/2013/11/04/exploring-scala-macros-map-to-case-class-conversion.html
// ...
val fromMapParams = fields.map { field ⇒
val name = field.name
val decoded = name.decoded
val returnType = tpe.declaration(name).typeSignature
q"MapReader[$returnType].read(map, $decoded)"
}
c.Expr[MapReader[T]] { q"""
new MapReader[$tpe] {
def read(map: Map[String, Any], key: String): $tpe =
$companion(..$fromMapParams)
}
""" }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment