in bijection-macros/src/main/scala/com/twitter/bijection/macros/impl/CaseClassToTuple.scala [24:100]
def caseClassToTupleImpl[T, Tup](
c: Context
)(
proof: c.Expr[IsCaseClass[T]]
)(implicit T: c.WeakTypeTag[T], Tup: c.WeakTypeTag[Tup]): c.Expr[Bijection[T, Tup]] =
caseClassToTupleNoProofImpl(c)(T, Tup)
def caseClassToTupleImplNonRecursive[T, Tup](
c: Context
)(
proof: c.Expr[IsCaseClass[T]]
)(implicit T: c.WeakTypeTag[T], Tup: c.WeakTypeTag[Tup]): c.Expr[Bijection[T, Tup]] =
caseClassToTupleNoProofImplNonRecursive(c)(T, Tup)
def caseClassToTupleNoProofImplNonRecursive[T, Tup](
c: Context
)(implicit T: c.WeakTypeTag[T], Tup: c.WeakTypeTag[Tup]): c.Expr[Bijection[T, Tup]] =
caseClassToTupleNoProofImplCommon(c, false)(T, Tup)
def caseClassToTupleNoProofImpl[T, Tup](
c: Context
)(implicit T: c.WeakTypeTag[T], Tup: c.WeakTypeTag[Tup]): c.Expr[Bijection[T, Tup]] =
caseClassToTupleNoProofImplCommon(c, true)(T, Tup)
def caseClassToTupleNoProofImplCommon[T, Tup](
c: Context,
recursivelyApply: Boolean
)(implicit T: c.WeakTypeTag[T], Tup: c.WeakTypeTag[Tup]): c.Expr[Bijection[T, Tup]] = {
import c.universe._
val tupUtils = new TupleUtils[c.type](c)
val convCache = MMap.empty[Type, TermName]
// TODO can make error handling better
val companion = T.tpe.typeSymbol.companionSymbol
val tuple = Tup.tpe.typeSymbol.companionSymbol
val getPutConv = T.tpe.declarations
.collect { case m: MethodSymbol if m.isCaseAccessor => m }
.zip(tupUtils.tupleCaseClassEquivalent(T.tpe))
.zip(Tup.tpe.declarations.collect { case m: MethodSymbol if m.isCaseAccessor => m })
.zipWithIndex
.map { case (((tM, treeEquiv), tupM), idx) =>
tM.returnType match {
case tpe if recursivelyApply && IsCaseClassImpl.isCaseClassType(c)(tpe) =>
val needDeclaration = !convCache.contains(tpe)
val conv = convCache.getOrElseUpdate(tpe, newTermName("c2t_" + idx))
(
q"""$conv.invert(tup.$tupM)""",
q"""$conv(t.$tM)""",
if (needDeclaration)
Some(
q"""val $conv = implicitly[_root_.com.twitter.bijection.Bijection[${tM.returnType}, $treeEquiv]]"""
)
else None
) // cache these
case tpe =>
(q"""tup.$tupM""", q"""t.$tM""", None)
}
}
val getters = getPutConv.map(_._1)
val putters = getPutConv.map(_._2)
val converters = getPutConv.flatMap(_._3)
c.Expr[Bijection[T, Tup]](q"""
new Bijection[$T,$Tup] with MacroGenerated {
override def apply(t: $T): $Tup = {
..$converters
$tuple(..$putters)
}
override def invert(tup: $Tup): $T = {
..$converters
$companion(..$getters)
}
}
""")
}