diff options
Diffstat (limited to 'core/src/main/scala/forge/Discovered.scala')
-rw-r--r-- | core/src/main/scala/forge/Discovered.scala | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/core/src/main/scala/forge/Discovered.scala b/core/src/main/scala/forge/Discovered.scala new file mode 100644 index 00000000..03577b1f --- /dev/null +++ b/core/src/main/scala/forge/Discovered.scala @@ -0,0 +1,57 @@ +package forge + +import forge.util.Labelled +import play.api.libs.json.Format + +import language.experimental.macros +import reflect.macros.blackbox.Context + +class Discovered[T](val value: Seq[(Seq[String], Format[_], T => Target[_])]){ + def apply(t: T) = value.map{case (a, f, b) => (a, f, b(t)) } + +} +object Discovered { + def makeTuple[T, V](path: Seq[String], func: T => Target[V])(implicit f: Format[V]) = { + (path, f, func) + } + + + def mapping[T: Discovered](t: T): Map[Target[_], Labelled[_]] = { + implicitly[Discovered[T]].apply(t) + .map(x => x._3 -> Labelled(x._3.asInstanceOf[Target[Any]], x._2.asInstanceOf[Format[Any]], x._1)) + .toMap + } + + implicit def apply[T]: Discovered[T] = macro applyImpl[T] + + def applyImpl[T: c.WeakTypeTag](c: Context): c.Expr[Discovered[T]] = { + import c.universe._ + val tpe = c.weakTypeTag[T].tpe + def rec(segments: List[String], t: c.Type): Seq[Seq[String]] = for { + m <- t.members.toSeq + if m.isTerm && (m.asTerm.isGetter || m.asTerm.isLazy) || m.isModule + res <- { + val extendedSegments = m.name.toString :: segments + val self = + if (m.typeSignature.resultType <:< c.weakTypeOf[Target[_]]) Seq(extendedSegments) + else Nil + val children = rec(extendedSegments, m.typeSignature) + self ++ children + } + } yield res + + val reversedPaths = rec(Nil, tpe) + + val result = for(reversedPath <- reversedPaths.toList) yield { + val base = q"${TermName(c.freshName())}" + val segments = reversedPath.reverse.toList + val ident = segments.foldLeft[Tree](base)((prefix, name) => + q"$prefix.${TermName(name)}" + ) + + q"forge.Discovered.makeTuple($segments, ($base: $tpe) => $ident)" + } + + c.Expr[Discovered[T]](q"new _root_.forge.Discovered($result)") + } +} |