Skip to content

Instantly share code, notes, and snippets.

@reimai
Created November 26, 2016 23:48
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 reimai/2ac1172b78c0190f32b7e9f2c5cf1c12 to your computer and use it in GitHub Desktop.
Save reimai/2ac1172b78c0190f32b7e9f2c5cf1c12 to your computer and use it in GitHub Desktop.
package rei
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
object Macros {
def ?[T](s: T): Option[T] = macro opt_impl[T]
def opt[T](s: T): Option[T] = macro opt_impl[T]
def opt_impl[T](c: blackbox.Context)(s: c.Expr[T]): c.Expr[Option[T]] = {
import c.universe._
def fail(message: String): Nothing = c.abort(c.enclosingPosition, message)
val usage =
"""
Hi, this is a macro for accessing protobuf option fields w/o manually writing "enrichers"
this is how to use it:
val optUser: Option[User] = opt(offer.getUser())
it will wrap the dratted thing with an Option using protoc's "has" method
because defaults are not nulls and we'd like to distinguish 'em
""".stripMargin
def check(that: Boolean, msg: String): Unit = if (!that) fail(s"$usage\n\nProblem: $msg")
check(s.tree.symbol.isMethod, s"${s.tree.symbol} is not a method")
//somehow calling 'isGetter' returns false, may be because it's java
check(s.tree.symbol.owner.isClass, s"Are you sure ${s.tree.symbol.owner} is a protobuf generated class?")
val get = s.tree.symbol.asMethod
val item = get.name.toString.substring(3)
val clazz = s.tree.symbol.owner.asClass
val maybeHas = clazz.toType.members
.find(s => s.isMethod && s.asMethod.name.toString == s"has$item")
check(maybeHas.isDefined,
s"There is no has$item method in class ${clazz.name.toString}, " +
s"are you sure ${item.toLowerCase} is a protobuf optional field?")
val has = maybeHas.get.asMethod
s.tree match {
case q"$obj.$get()" =>
c.Expr(
q"""
if ($obj.$has())
Some($s)
else
None
""")
case otherwise => fail(s"Something went wrong, tree: $otherwise")
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment