summaryrefslogtreecommitdiff
path: root/cask/src/cask/main/RoutesEndpointMetadata.scala
diff options
context:
space:
mode:
authorLi Haoyi <haoyi.sg@gmail.com>2019-09-15 12:36:39 +0800
committerLi Haoyi <haoyi.sg@gmail.com>2019-09-15 12:36:39 +0800
commit0e098a93da94c251eb05d42bc7ef48394600508c (patch)
treeb4c3e7ec654e16aa50f149ce255ef187791461e7 /cask/src/cask/main/RoutesEndpointMetadata.scala
parent38c6a84a0e8fbc3debb93bbacaf8c092e675ecb3 (diff)
downloadcask-0e098a93da94c251eb05d42bc7ef48394600508c.tar.gz
cask-0e098a93da94c251eb05d42bc7ef48394600508c.tar.bz2
cask-0e098a93da94c251eb05d42bc7ef48394600508c.zip
Break circular dependency by splitting `RouteEndpointMetadata` into its own file
Diffstat (limited to 'cask/src/cask/main/RoutesEndpointMetadata.scala')
-rw-r--r--cask/src/cask/main/RoutesEndpointMetadata.scala68
1 files changed, 68 insertions, 0 deletions
diff --git a/cask/src/cask/main/RoutesEndpointMetadata.scala b/cask/src/cask/main/RoutesEndpointMetadata.scala
new file mode 100644
index 0000000..fa93a0c
--- /dev/null
+++ b/cask/src/cask/main/RoutesEndpointMetadata.scala
@@ -0,0 +1,68 @@
+package cask.main
+
+import cask.internal.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.internal.Router[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.main.EndpointMetadata(
+ Seq(..${annotObjectSyms.dropRight(1)}),
+ ${annotObjectSyms.last},
+ $route
+ )
+ }"""
+ res
+ }
+
+ c.Expr[RoutesEndpointsMetadata[T]](q"""cask.main.RoutesEndpointsMetadata(..$routeParts)""")
+ }
+} \ No newline at end of file