diff --git a/smithy4s-tests/src/test/scala-2/com/dwolla/consul/smithy4s/ConsulMiddlewareSpec.scala b/smithy4s-tests/src/test/scala-2/com/dwolla/consul/smithy4s/ConsulMiddlewareSpec.scala index ac7f319..be0f154 100644 --- a/smithy4s-tests/src/test/scala-2/com/dwolla/consul/smithy4s/ConsulMiddlewareSpec.scala +++ b/smithy4s-tests/src/test/scala-2/com/dwolla/consul/smithy4s/ConsulMiddlewareSpec.scala @@ -58,7 +58,7 @@ class ConsulMiddlewareSpec expected: GreetOutput) => SimpleRestJsonBuilder(HelloService) .client(Client.fromHttpApp(new TestServiceImpl[IO](consulAuthority, expected).routes.orNotFound)) - .uri(UriFromService[HelloService]) + .uri(UriFromService(HelloService)) .middleware(new ConsulMiddleware(new FakeConsuleUriResolver[IO](consulAuthority))) .resource .use(_.greet(input)) @@ -69,7 +69,7 @@ class ConsulMiddlewareSpec } class FakeConsuleUriResolver[F[_] : Applicative : Console](consulAuthority: Uri.Authority) extends ConsulUriResolver[F] { - private val baseAuthority: Uri.Authority = UriAuthorityFromService[HelloService] + private val baseAuthority: Uri.Authority = UriAuthorityFromService(HelloService) private val consul = scheme"consul" override def resolve(uri: Uri): F[Uri] = diff --git a/smithy4s-tests/src/test/scala-2/com/dwolla/consul/smithy4s/UriFromServiceSpec.scala b/smithy4s-tests/src/test/scala-2/com/dwolla/consul/smithy4s/UriFromServiceSpec.scala index e5c2a87..756e950 100644 --- a/smithy4s-tests/src/test/scala-2/com/dwolla/consul/smithy4s/UriFromServiceSpec.scala +++ b/smithy4s-tests/src/test/scala-2/com/dwolla/consul/smithy4s/UriFromServiceSpec.scala @@ -8,37 +8,23 @@ class UriFromServiceSpec extends FunSuite { test("Service URI is derived from Smithy hint at compile time") { import org.http4s.syntax.all._ - val uri = UriFromService[com.dwolla.test.HelloService] + val uri = UriFromService(com.dwolla.test.HelloService) assertEquals(uri, uri"consul://hello-world") } test("Service Host is derived from Smithy hint at compile time") { - val uri = HostFromService[com.dwolla.test.HelloService] + val uri = HostFromService(com.dwolla.test.HelloService) assertEquals(uri, Uri.Host.fromIp4sHost(host"hello-world")) } test("Service URI.Authority is derived from Smithy hint at compile time") { - val uri = UriAuthorityFromService[com.dwolla.test.HelloService] + val uri = UriAuthorityFromService(com.dwolla.test.HelloService) assertEquals(uri, Uri.Authority(host = Uri.Host.fromIp4sHost(host"hello-world"))) } - test("traits of the right shape are rejected at compile time if they aren't smithy4s Services") { - assert { - compileErrors("UriFromService[NotASmithy4sServiceAndHasNoCompanionObject]") - .contains("com.dwolla.consul.smithy4s.NotASmithy4sServiceAndHasNoCompanionObject is not a Smithy4s Service") - } - } - - test("traits of the right shape are rejected at compile time if they aren't smithy4s Services, even if they have a companion object") { - assert { - compileErrors("UriFromService[NotASmithy4sService]") - .contains("value hints is not a member of object com.dwolla.consul.smithy4s.NotASmithy4sService (is com.dwolla.consul.smithy4s.NotASmithy4sService a Smithy4s Service?)") - } - } - test("unannotated Smithy services are rejected at compile time") { assert { - compileErrors("UriFromService[com.dwolla.test.UnannotatedService]") + compileErrors("UriFromService(com.dwolla.test.UnannotatedService)") .contains("could not find Discoverable hint for com.dwolla.test.UnannotatedService") } } diff --git a/smithy4s/src/main/scala-2/com/dwolla/consul/smithy4s/UriFromService.scala b/smithy4s/src/main/scala-2/com/dwolla/consul/smithy4s/UriFromService.scala index 77b15f5..71f9440 100644 --- a/smithy4s/src/main/scala-2/com/dwolla/consul/smithy4s/UriFromService.scala +++ b/smithy4s/src/main/scala-2/com/dwolla/consul/smithy4s/UriFromService.scala @@ -2,74 +2,62 @@ package com.dwolla.consul.smithy4s import com.dwolla.consul.smithy.{Discoverable, ServiceName} import org.http4s.Uri -import smithy4s.Hints +import smithy4s.{Hints, Service} import cats.syntax.all._ import org.http4s.Uri.{Host, Scheme} import org.http4s.syntax.all._ import scala.reflect.macros.blackbox -import scala.util.Try object DiscoveryMacros { private val consulScheme: Scheme = scheme"consul" - def makeUri(c: blackbox.Context): c.Expr[Uri] = { + def makeUri[Alg[_[_, _, _, _, _]], Op[_, _, _, _, _]](c: blackbox.Context) + (service: c.Expr[smithy4s.Service.Mixin[Alg, Op]]): c.Expr[Uri] = { import c.universe.{Try => _, _} - c.Expr[Uri](q"org.http4s.Uri(scheme = scala.Option(org.http4s.Uri.Scheme.unsafeFromString(${consulScheme.value})), authority = scala.Option(org.http4s.Uri.Authority(None, ${makeHost(c)}, None)))") + c.Expr[Uri](q"org.http4s.Uri(scheme = scala.Option(org.http4s.Uri.Scheme.unsafeFromString(${consulScheme.value})), authority = scala.Option(org.http4s.Uri.Authority(None, ${makeHost[Alg, Op](c)(service)}, None)))") } - def makeUriAuthority(c: blackbox.Context): c.Expr[Uri.Authority] = { + def makeUriAuthority[Alg[_[_, _, _, _, _]], Op[_, _, _, _, _]](c: blackbox.Context) + (service: c.Expr[smithy4s.Service.Mixin[Alg, Op]]): c.Expr[Uri.Authority] = { import c.universe.{Try => _, _} - c.Expr[Uri.Authority](q"org.http4s.Uri.Authority(host =${makeHost(c)})") + c.Expr[Uri.Authority](q"org.http4s.Uri.Authority(host =${makeHost[Alg, Op](c)(service)})") } - def makeHost(c: blackbox.Context): c.Expr[Host] = { + def makeHost[Alg[_[_, _, _, _, _]], Op[_, _, _, _, _]](c: blackbox.Context) + (service: c.Expr[smithy4s.Service.Mixin[Alg, Op]]): c.Expr[Host] = { import c.universe.{Try => _, _} - c.macroApplication match { - case TypeApply(_, List(tpe)) if tpe.symbol.companion != NoSymbol => - Try { - tpe - .collect { - case x: TypTree => - c.eval(c.Expr[Hints](q"${x.symbol.companion}.hints")) - } - .headOption - .toRight(s"could not find hints for $tpe") - } - .toEither - .leftMap(_.toString ++ s" (is $tpe a Smithy4s Service?)") - .flatten - .flatMap { - _.get(Discoverable.tagInstance) - .toRight(s"could not find Discoverable hint for $tpe") - } - .flatMap { - case Discoverable(ServiceName(serviceName)) => - Host.fromString(serviceName) - .leftMap(_.message) - } - .map { host => - c.Expr[Host](q"org.http4s.Uri.Host.unsafeFromString(${host.value})") - } - .fold(c.abort(c.enclosingPosition, _), identity) - case TypeApply(_, List(tpe)) if tpe.symbol.companion == NoSymbol => - c.abort(c.enclosingPosition, s"$tpe is not a Smithy4s Service") - case other => c.abort(c.enclosingPosition, s"found $other, which is not a Smithy4s Service") - } + val cleanService = c.untypecheck(service.tree.duplicate) + + c.eval(c.Expr[Hints](q"$cleanService.hints")) + .get(Discoverable.tagInstance) + .toRight(s"could not find Discoverable hint for ${cleanService.symbol.fullName}") + .flatMap { + case Discoverable(ServiceName(serviceName)) => + Host.fromString(serviceName) + .leftMap(_.message) + } + .map { host => + c.Expr[Host](q"org.http4s.Uri.Host.unsafeFromString(${host.value})") + } + .fold(c.abort(c.enclosingPosition, _), identity) } } object UriAuthorityFromService { - def apply[Alg[_[_]]]: Uri.Authority = macro DiscoveryMacros.makeUriAuthority + def apply[Alg[_[_, _, _, _, _]], Op[_, _, _, _, _]](service: Service.Mixin[Alg, Op]): Uri.Authority = + macro DiscoveryMacros.makeUriAuthority[Alg, Op] } object HostFromService { - def apply[Alg[_[_]]]: Host = macro DiscoveryMacros.makeHost + def apply[Alg[_[_, _, _, _, _]], Op[_, _, _, _, _]](service: Service.Mixin[Alg, Op]): Host = + macro DiscoveryMacros.makeHost[Alg, Op] } object UriFromService { - def apply[Alg[_[_]]]: Uri = macro DiscoveryMacros.makeUri + def apply[Alg[_[_, _, _, _, _]], Op[_, _, _, _, _]](service: Service.Mixin[Alg, Op]): Uri = + macro DiscoveryMacros.makeUri[Alg, Op] }