diff options
Diffstat (limited to 'cask/src/cask/router/RoutesEndpointMetadata.scala')
-rw-r--r-- | cask/src/cask/router/RoutesEndpointMetadata.scala | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/cask/src/cask/router/RoutesEndpointMetadata.scala b/cask/src/cask/router/RoutesEndpointMetadata.scala new file mode 100644 index 0000000..7940641 --- /dev/null +++ b/cask/src/cask/router/RoutesEndpointMetadata.scala @@ -0,0 +1,68 @@ +package cask.router + +import cask.router.EntryPoint + +import language.experimental.macros +import scala.reflect.macros.blackbox +case class EndpointMetadata[T](decorators: Seq[RawDecorator], + endpoint: Endpoint[_, _], + entryPoint: EntryPoint[T, _]) +case class RoutesEndpointsMetadata[T](value: EndpointMetadata[T]*) +object RoutesEndpointsMetadata{ + implicit def initialize[T]: RoutesEndpointsMetadata[T] = macro initializeImpl[T] + implicit def initializeImpl[T: c.WeakTypeTag](c: blackbox.Context): c.Expr[RoutesEndpointsMetadata[T]] = { + import c.universe._ + val router = new cask.router.Macros[c.type](c) + + val routeParts = for{ + m <- c.weakTypeOf[T].members + annotations = m.annotations.filter(_.tree.tpe <:< c.weakTypeOf[Decorator[_, _]]) + if annotations.nonEmpty + } yield { + if(!(annotations.last.tree.tpe <:< weakTypeOf[Endpoint[_, _]])) c.abort( + annotations.head.tree.pos, + s"Last annotation applied to a function must be an instance of Endpoint, " + + s"not ${annotations.last.tree.tpe}" + ) + val allEndpoints = annotations.filter(_.tree.tpe <:< weakTypeOf[Endpoint[_, _]]) + if(allEndpoints.length > 1) c.abort( + annotations.last.tree.pos, + s"You can only apply one Endpoint annotation to a function, not " + + s"${allEndpoints.length} in ${allEndpoints.map(_.tree.tpe).mkString(", ")}" + ) + + val annotObjects = + for(annot <- annotations) + yield q"new ${annot.tree.tpe}(..${annot.tree.children.tail})" + + val annotObjectSyms = + for(_ <- annotations.indices) + yield c.universe.TermName(c.freshName("annotObject")) + + val route = router.extractMethod( + m.asInstanceOf[MethodSymbol], + weakTypeOf[T], + q"${annotObjectSyms.last}.convertToResultType", + tq"cask.Request", + annotObjectSyms.reverse.map(annotObjectSym => q"$annotObjectSym.getParamParser"), + annotObjectSyms.reverse.map(annotObjectSym => tq"$annotObjectSym.InputTypeAlias") + ) + + val declarations = + for((sym, obj) <- annotObjectSyms.zip(annotObjects)) + yield q"val $sym = $obj" + + val res = q"""{ + ..$declarations + cask.router.EndpointMetadata( + Seq(..${annotObjectSyms.dropRight(1)}), + ${annotObjectSyms.last}, + $route + ) + }""" + res + } + + c.Expr[RoutesEndpointsMetadata[T]](q"""cask.router.RoutesEndpointsMetadata(..$routeParts)""") + } +}
\ No newline at end of file |