From 70dbe3ed561172a80ebff0515e727434b03040bf Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Wed, 9 Oct 2019 10:54:16 +0800 Subject: Convert `Decorator#OuterReturned` into a type parameter --- cask/src/cask/endpoints/JsonEndpoint.scala | 4 ++-- cask/src/cask/endpoints/StaticEndpoints.scala | 6 +++--- cask/src/cask/endpoints/WebSocketEndpoint.scala | 4 ++-- cask/src/cask/main/Main.scala | 4 ++-- cask/src/cask/main/Routes.scala | 2 +- cask/src/cask/router/Decorators.scala | 21 +++++++++------------ cask/src/cask/router/RoutesEndpointMetadata.scala | 8 ++++---- cask/test/src/test/cask/FailureTests.scala | 2 +- 8 files changed, 24 insertions(+), 27 deletions(-) (limited to 'cask') diff --git a/cask/src/cask/endpoints/JsonEndpoint.scala b/cask/src/cask/endpoints/JsonEndpoint.scala index 31109d9..098bc82 100644 --- a/cask/src/cask/endpoints/JsonEndpoint.scala +++ b/cask/src/cask/endpoints/JsonEndpoint.scala @@ -44,7 +44,7 @@ class postJson(val path: String, override val subpath: Boolean = false) extends HttpEndpoint[Response[JsonData], ujson.Value]{ val methods = Seq("post") type InputParser[T] = JsReader[T] - override type OuterReturned = Result[Response.Raw] + def wrapFunction(ctx: Request, delegate: Delegate): Result[Response.Raw] = { val obj = for{ @@ -83,7 +83,7 @@ class getJson(val path: String, override val subpath: Boolean = false) extends HttpEndpoint[Response[JsonData], Seq[String]]{ val methods = Seq("get") type InputParser[T] = QueryParamReader[T] - override type OuterReturned = Result[Response.Raw] + def wrapFunction(ctx: Request, delegate: Delegate): Result[Response.Raw] = { delegate(WebEndpoint.buildMapFromQueryParams(ctx)) } diff --git a/cask/src/cask/endpoints/StaticEndpoints.scala b/cask/src/cask/endpoints/StaticEndpoints.scala index 618da5f..c36551b 100644 --- a/cask/src/cask/endpoints/StaticEndpoints.scala +++ b/cask/src/cask/endpoints/StaticEndpoints.scala @@ -1,6 +1,6 @@ package cask.endpoints -import cask.router.HttpEndpoint +import cask.router.{HttpEndpoint, Result} import cask.model.Request object StaticUtil{ def makePath(t: String, ctx: Request) = { @@ -14,7 +14,7 @@ class staticFiles(val path: String, headers: Seq[(String, String)] = Nil) extend val methods = Seq("get") type InputParser[T] = QueryParamReader[T] override def subpath = true - def wrapFunction(ctx: Request, delegate: Delegate): OuterReturned = { + def wrapFunction(ctx: Request, delegate: Delegate) = { delegate(Map()).map(t => cask.model.StaticFile(StaticUtil.makePath(t, ctx), headers)) } @@ -28,7 +28,7 @@ class staticResources(val path: String, val methods = Seq("get") type InputParser[T] = QueryParamReader[T] override def subpath = true - def wrapFunction(ctx: Request, delegate: Delegate): OuterReturned = { + def wrapFunction(ctx: Request, delegate: Delegate) = { delegate(Map()).map(t => cask.model.StaticResource(StaticUtil.makePath(t, ctx), resourceRoot, headers) ) diff --git a/cask/src/cask/endpoints/WebSocketEndpoint.scala b/cask/src/cask/endpoints/WebSocketEndpoint.scala index 994f015..905c5f1 100644 --- a/cask/src/cask/endpoints/WebSocketEndpoint.scala +++ b/cask/src/cask/endpoints/WebSocketEndpoint.scala @@ -21,11 +21,11 @@ object WebsocketResult{ } class websocket(val path: String, override val subpath: Boolean = false) - extends cask.router.Endpoint[WebsocketResult, Seq[String]]{ + extends cask.router.Endpoint[WebsocketResult, WebsocketResult, Seq[String]]{ val methods = Seq("websocket") type InputParser[T] = QueryParamReader[T] type OuterReturned = Result[WebsocketResult] - def wrapFunction(ctx: Request, delegate: Delegate): OuterReturned = { + def wrapFunction(ctx: Request, delegate: Delegate) = { delegate(WebEndpoint.buildMapFromQueryParams(ctx)) } diff --git a/cask/src/cask/main/Main.scala b/cask/src/cask/main/Main.scala index 0bc1abf..a96d706 100644 --- a/cask/src/cask/main/Main.scala +++ b/cask/src/cask/main/Main.scala @@ -27,7 +27,7 @@ class MainRoutes extends Main with Routes{ * application-wide properties. */ abstract class Main{ - def mainDecorators: Seq[Decorator[_, _]] = Nil + def mainDecorators: Seq[Decorator[_, _, _]] = Nil def allRoutes: Seq[Routes] def port: Int = 8080 def host: String = "localhost" @@ -61,7 +61,7 @@ abstract class Main{ object Main{ class DefaultHandler(routeTries: Map[String, DispatchTrie[(Routes, EndpointMetadata[_])]], - mainDecorators: Seq[Decorator[_, _]], + mainDecorators: Seq[Decorator[_, _, _]], debugMode: Boolean, handleNotFound: () => Response.Raw, handleError: (Routes, EndpointMetadata[_], Result.Error) => Response.Raw) diff --git a/cask/src/cask/main/Routes.scala b/cask/src/cask/main/Routes.scala index 59da2c7..1b83be3 100644 --- a/cask/src/cask/main/Routes.scala +++ b/cask/src/cask/main/Routes.scala @@ -6,7 +6,7 @@ import language.experimental.macros trait Routes{ - def decorators = Seq.empty[cask.router.Decorator[_, _]] + def decorators = Seq.empty[cask.router.Decorator[_, _, _]] implicit def executionContext = concurrent.ExecutionContext.Implicits.global private[this] var metadata0: RoutesEndpointsMetadata[this.type] = null def caskMetadata = diff --git a/cask/src/cask/router/Decorators.scala b/cask/src/cask/router/Decorators.scala index d661177..895be53 100644 --- a/cask/src/cask/router/Decorators.scala +++ b/cask/src/cask/router/Decorators.scala @@ -14,12 +14,11 @@ import cask.model.{Request, Response} * to `wrapFunction`, which takes a `Map` representing any additional argument * lists (if any). */ -trait Decorator[InnerReturned, Input]{ +trait Decorator[OuterReturned, InnerReturned, Input]{ final type InputTypeAlias = Input type InputParser[T] <: ArgReader[Input, T, Request] final type Delegate = Map[String, Input] => Result[InnerReturned] - type OuterReturned <: Result[Any] - def wrapFunction(ctx: Request, delegate: Delegate): OuterReturned + def wrapFunction(ctx: Request, delegate: Delegate): Result[OuterReturned] def getParamParser[T](implicit p: InputParser[T]) = p } object Decorator{ @@ -35,15 +34,15 @@ object Decorator{ * used as the first argument list. */ def invoke[T](ctx: Request, - endpoint: Endpoint[_, _], + endpoint: Endpoint[_, _, _], entryPoint: EntryPoint[T, _], routes: T, routeBindings: Map[String, String], - remainingDecorators: List[Decorator[_, _]], + remainingDecorators: List[Decorator[_, _, _]], bindings: List[Map[String, Any]]): Result[Any] = try { remainingDecorators match { case head :: rest => - head.asInstanceOf[Decorator[Any, Any]].wrapFunction( + head.asInstanceOf[Decorator[Any, Any, Any]].wrapFunction( ctx, args => invoke(ctx, endpoint, entryPoint, routes, routeBindings, rest, args :: bindings) .asInstanceOf[Result[Nothing]] @@ -70,8 +69,7 @@ object Decorator{ * A [[RawDecorator]] is a decorator that operates on the raw request and * response stream, before and after the primary [[Endpoint]] does it's job. */ -trait RawDecorator extends Decorator[Response.Raw, Any]{ - type OuterReturned = Result[Response.Raw] +trait RawDecorator extends Decorator[Response.Raw, Response.Raw, Any]{ type InputParser[T] = NoOpParser[Any, T] } @@ -80,7 +78,8 @@ trait RawDecorator extends Decorator[Response.Raw, Any]{ * An [[HttpEndpoint]] that may return something else than a HTTP response, e.g. * a websocket endpoint which may instead return a websocket event handler */ -trait Endpoint[InnerReturned, Input] extends Decorator[InnerReturned, Input]{ +trait Endpoint[OuterReturned, InnerReturned, Input] + extends Decorator[OuterReturned, InnerReturned, Input]{ /** * What is the path that this particular endpoint matches? */ @@ -119,9 +118,7 @@ trait Endpoint[InnerReturned, Input] extends Decorator[InnerReturned, Input]{ * Annotates a Cask endpoint that returns a HTTP [[Response]]; similar to a * [[RawDecorator]] but with additional metadata and capabilities. */ -trait HttpEndpoint[InnerReturned, Input] extends Endpoint[InnerReturned, Input] { - type OuterReturned = Result[Response.Raw] -} +trait HttpEndpoint[InnerReturned, Input] extends Endpoint[Response.Raw, InnerReturned, Input] class NoOpParser[Input, T] extends ArgReader[Input, T, Request] { diff --git a/cask/src/cask/router/RoutesEndpointMetadata.scala b/cask/src/cask/router/RoutesEndpointMetadata.scala index 7940641..2445c9d 100644 --- a/cask/src/cask/router/RoutesEndpointMetadata.scala +++ b/cask/src/cask/router/RoutesEndpointMetadata.scala @@ -5,7 +5,7 @@ import cask.router.EntryPoint import language.experimental.macros import scala.reflect.macros.blackbox case class EndpointMetadata[T](decorators: Seq[RawDecorator], - endpoint: Endpoint[_, _], + endpoint: Endpoint[_, _, _], entryPoint: EntryPoint[T, _]) case class RoutesEndpointsMetadata[T](value: EndpointMetadata[T]*) object RoutesEndpointsMetadata{ @@ -16,15 +16,15 @@ object RoutesEndpointsMetadata{ val routeParts = for{ m <- c.weakTypeOf[T].members - annotations = m.annotations.filter(_.tree.tpe <:< c.weakTypeOf[Decorator[_, _]]) + annotations = m.annotations.filter(_.tree.tpe <:< c.weakTypeOf[Decorator[_, _, _]]) if annotations.nonEmpty } yield { - if(!(annotations.last.tree.tpe <:< weakTypeOf[Endpoint[_, _]])) c.abort( + 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[_, _]]) + 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 " + diff --git a/cask/test/src/test/cask/FailureTests.scala b/cask/test/src/test/cask/FailureTests.scala index 25530fa..bd27971 100644 --- a/cask/test/src/test/cask/FailureTests.scala +++ b/cask/test/src/test/cask/FailureTests.scala @@ -5,7 +5,7 @@ import utest._ object FailureTests extends TestSuite { class myDecorator extends cask.RawDecorator { - def wrapFunction(ctx: Request, delegate: Delegate): OuterReturned = { + def wrapFunction(ctx: Request, delegate: Delegate) = { delegate(Map("extra" -> 31337)) } } -- cgit v1.2.3