Skip to content

Commit

Permalink
Merge pull request #555 from disneystreaming/polyfunction-revamp
Browse files Browse the repository at this point in the history
Polyfunction revamp
  • Loading branch information
Baccata authored Oct 28, 2022
2 parents 5bac4e9 + 2b92cbf commit d57f7d1
Show file tree
Hide file tree
Showing 59 changed files with 2,305 additions and 849 deletions.
2 changes: 1 addition & 1 deletion .scalafmt.conf
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ version = "3.1.2"
runner.dialect = scala213
project {
excludePaths = [
"glob:**/core/src/generated/*.scala",
"glob:**/core/src-*/generated/*.scala",
"glob:**/example/src/smithy4s/**/*.scala",
"glob:**/schematic-core/src/generated/*.scala",
"glob:**/schematic-scalacheck/src/generated/*.scala"
Expand Down
24 changes: 21 additions & 3 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,27 @@ lazy val core = projectMatrix
),
genDiscoverModels := true,
Compile / sourceGenerators := Seq(genSmithyScala(Compile).taskValue),
Compile / sourceGenerators += sourceDirectory
.map(Boilerplate.gen(_, Boilerplate.BoilerplateModule.Core))
.taskValue,
Compile / sourceGenerators += {
sourceDirectory
.map(Boilerplate.gen(_, Boilerplate.BoilerplateModule.Core))
.taskValue,
},
Compile / sourceGenerators += {
sourceDirectory
.zip(scalaVersion)
.map { case (sd, sv) =>
val base = sd.getParentFile()
sv match {
case Scala3 =>
Boilerplate
.gen(base / "src-3", Boilerplate.BoilerplateModule.Core3)
case _ =>
Boilerplate
.gen(base / "src-2", Boilerplate.BoilerplateModule.Core2)
}
}
.taskValue
},
libraryDependencies ++= Seq(
Dependencies.collectionsCompat.value,
Dependencies.Cats.core.value % Test
Expand Down
6 changes: 3 additions & 3 deletions modules/aws/src/smithy4s/aws/AwsClient.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ package smithy4s.aws
import cats.MonadThrow
import cats.effect.Resource
import cats.syntax.all._
import smithy4s.Transformation

import internals.AwsJsonRPCInterpreter
import smithy4s.kinds.PolyFunction5

object AwsClient {

Expand Down Expand Up @@ -58,7 +58,7 @@ object AwsClient {

def build[F[_]: MonadThrow](
awsEnv: AwsEnvironment[F]
): Transformation[Op, AwsCall[F, *, *, *, *, *]] =
): PolyFunction5[Op, AwsCall[F, *, *, *, *, *]] =
awsProtocol match {
case AwsProtocol.AWS_JSON_1_0(_) =>
new AwsJsonRPCInterpreter[Alg, Op, F](
Expand All @@ -79,7 +79,7 @@ object AwsClient {

def interpret[F[_]: MonadThrow](
awsEnv: AwsEnvironment[F]
): AwsClient[Alg, F] = service.transform(build(awsEnv))
): AwsClient[Alg, F] = service.fromPolyFunction(build(awsEnv))
}
private def initError(msg: String): Throwable = InitialisationError(msg)
case class InitialisationError(msg: String) extends Throwable(msg)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ package internals

import cats.MonadThrow
import smithy4s.Endpoint
import smithy4s.Transformation
import smithy4s.kinds._

// format: off
/**
Expand All @@ -31,7 +31,7 @@ private[aws] class AwsJsonRPCInterpreter[Alg[_[_, _, _, _, _]], Op[_,_,_,_,_], F
awsEnv: AwsEnvironment[F],
contentType: String
)(implicit F: MonadThrow[F])
extends Transformation[Op, AwsCall[F, *, *, *, *, *]] {
extends PolyFunction5[Op, AwsCall[F, *, *, *, *, *]] {
// format: on

val codecAPI = new json.AwsJsonCodecAPI()
Expand All @@ -51,14 +51,17 @@ private[aws] class AwsJsonRPCInterpreter[Alg[_[_, _, _, _, _]], Op[_,_,_,_,_], F
)

private val awsEndpoints =
new Transformation[
new PolyFunction5[
Endpoint[Op, *, *, *, *, *],
AwsUnaryEndpoint[F, Op, *, *, *, *, *]
] {
def apply[I, E, O, SI, SO](
endpoint: Endpoint[Op, I, E, O, SI, SO]
): AwsUnaryEndpoint[F, Op, I, E, O, SI, SO] =
new AwsUnaryEndpoint(awsEnv, signer, endpoint, codecAPI)
}.precompute(service.endpoints.map(smithy4s.Kind5.existential(_)))
}.unsafeCacheBy(
service.endpoints.map(Kind5.existential(_)),
identity
)

}
5 changes: 3 additions & 2 deletions modules/codegen/src/smithy4s/codegen/CollisionAvoidance.scala
Original file line number Diff line number Diff line change
Expand Up @@ -259,13 +259,14 @@ object CollisionAvoidance {

def getReservedNames: Set[String] = reservedNames

val Transformation_ = NameRef("smithy4s", "Transformation")
val Transformation = NameRef("smithy4s.capability", "Transformation")
val PolyFunction5_ = NameRef("smithy4s.kinds", "PolyFunction5")
val Service_ = NameRef("smithy4s", "Service")
val Endpoint_ = NameRef("smithy4s", "Endpoint")
val NoInput_ = NameRef("smithy4s", "NoInput")
val ShapeId_ = NameRef("smithy4s", "ShapeId")
val Schema_ = NameRef("smithy4s", "Schema")
val Monadic_ = NameRef("smithy4s", "Monadic")
val FunctorAlgebra_ = NameRef("smithy4s.kinds", "FunctorAlgebra")
val StreamingSchema_ = NameRef("smithy4s", "StreamingSchema")
val Enumeration_ = NameRef("smithy4s", "Enumeration")
val EnumValue_ = NameRef("smithy4s.schema", "EnumValue")
Expand Down
30 changes: 15 additions & 15 deletions modules/codegen/src/smithy4s/codegen/Renderer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ private[codegen] class Renderer(compilationUnit: CompilationUnit) { self =>
val name = s.name
val nameGen = NameRef(s"${name}Gen")
lines(
line"type ${NameDef(name)}[F[_]] = $Monadic_[$nameGen, F]",
line"type ${NameDef(name)}[F[_]] = $FunctorAlgebra_[$nameGen, F]",
block(
line"object ${NameRef(name)} extends $Service_.Provider[$nameGen, ${name}Operation]"
)(
Expand Down Expand Up @@ -200,24 +200,15 @@ private[codegen] class Renderer(compilationUnit: CompilationUnit) { self =>

},
newline,
line"def transform[G[_, _, _, _, _]](transformation : $Transformation_[F, G]) : $genNameRef[G] = new Transformed(transformation)",
block(
line"class $Transformed_[G[_, _, _, _, _]](transformation : $Transformation_[F, G]) extends $genNameRef[G]"
) {
ops.map { op =>
val opName = op.methodName
line"def $opName(${op.renderArgs}) = transformation[${op
.renderAlgParams(genName.name)}](self.$opName(${op.renderParams}))"
}
}
line"def transform : $Transformation.PartiallyApplied[$genName[F]] = new $Transformation.PartiallyApplied[$genName[F]](this)"
),
newline,
obj(
genNameRef,
ext = line"$Service_[$genNameRef, $opTraitNameRef]"
)(
newline,
line"def apply[F[_]](implicit F: $Monadic_[$genNameRef, F]): F.type = F",
line"def apply[F[_]](implicit F: $FunctorAlgebra_[$genNameRef, F]): F.type = F",
newline,
renderId(shapeId),
newline,
Expand Down Expand Up @@ -257,12 +248,21 @@ private[codegen] class Renderer(compilationUnit: CompilationUnit) { self =>
}
},
newline,
line"def transform[P[_, _, _, _, _]](transformation: $Transformation_[$opTraitNameRef, P]): $genNameRef[P] = reified.transform(transformation)",
line"def mapK5[P[_, _, _, _, _], P1[_, _, _, _, _]](alg: $genNameRef[P], f: $PolyFunction5_[P, P1]): $genNameRef[P1] = new $Transformed_(alg, f)",
newline,
line"def transform[P[_, _, _, _, _], P1[_, _, _, _, _]](alg: $genNameRef[P], transformation: $Transformation_[P, P1]): $genNameRef[P1] = alg.transform(transformation)",
line"def fromPolyFunction[P[_, _, _, _, _]](f: $PolyFunction5_[$opTraitNameRef, P]): $genNameRef[P] = new $Transformed_(reified, f)",
block(
line"class $Transformed_[P[_, _, _, _, _], P1[_ ,_ ,_ ,_ ,_]](alg: $genNameRef[P], f : $PolyFunction5_[P, P1]) extends $genNameRef[P1]"
) {
ops.map { op =>
val opName = op.methodName
line"def $opName(${op.renderArgs}) = f[${op
.renderAlgParams(genName.name)}](alg.$opName(${op.renderParams}))"
}
},
newline,
block(
line"def asTransformation[P[_, _, _, _, _]](impl : $genNameRef[P]): $Transformation_[$opTraitNameRef, P] = new $Transformation_[$opTraitNameRef, P]"
line"def toPolyFunction[P[_, _, _, _, _]](impl : $genNameRef[P]): $PolyFunction5_[$opTraitNameRef, P] = new $PolyFunction5_[$opTraitNameRef, P]"
) {
if (ops.isEmpty) {
line"""def apply[I, E, O, SI, SO](op : $opTraitNameRef[I, E, O, SI, SO]) : P[I, E, O, SI, SO] = sys.error("impossible")""".toLines
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import smithy4s.Endpoint
import smithy4s.http.PayloadError
import smithy4s.Service
import smithy4s.ShapeTag
import smithy4s.kinds._
import smithy4s.tests.DefaultSchemaVisitor

import scala.concurrent.duration._
Expand All @@ -59,7 +60,7 @@ abstract class ClientHttpComplianceTestCase[
import org.http4s.implicits._
private val baseUri = uri"http://localhost/"

def getClient(app: HttpApp[IO]): Resource[IO, smithy4s.Monadic[Alg, IO]]
def getClient(app: HttpApp[IO]): Resource[IO, FunctorAlgebra[Alg, IO]]
def codecs: CodecAPI

private def matchRequest(
Expand Down Expand Up @@ -141,7 +142,7 @@ abstract class ClientHttpComplianceTestCase[
input
.flatMap { in =>
service
.asTransformation[R](client)
.toPolyFunction[R](client)
.apply(endpoint.wrap(in))
}
// deal with the empty response generated in the mock
Expand Down Expand Up @@ -235,7 +236,7 @@ abstract class ClientHttpComplianceTestCase[
case Left(onError) =>
onError(doc).flatMap { expectedErr =>
service
.asTransformation[R](client)
.toPolyFunction[R](client)
.apply(endpoint.wrap(dummyInput))
.map { _ => assert.success }
.recover { case ex: Throwable =>
Expand All @@ -245,7 +246,7 @@ abstract class ClientHttpComplianceTestCase[
case Right(onOutput) =>
onOutput(doc).flatMap { expectedOutput =>
service
.asTransformation[R](client)
.toPolyFunction[R](client)
.apply(endpoint.wrap(dummyInput))
.map { output => assert.eql(expectedOutput, output) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ import smithy4s.Endpoint
import smithy4s.http.CodecAPI
import smithy4s.Service
import smithy4s.ShapeTag
import smithy4s.kinds._

import scala.concurrent.duration._
import smithy4s.Transformation
import smithy4s.ShapeId
import smithy4s.Hints
import smithy4s.Errorable
Expand All @@ -52,7 +52,7 @@ abstract class ServerHttpComplianceTestCase[
private val baseUri = uri"http://localhost/"

def getServer[Alg2[_[_, _, _, _, _]], Op2[_, _, _, _, _]](
impl: smithy4s.Monadic[Alg2, IO]
impl: FunctorAlgebra[Alg2, IO]
)(implicit s: Service[Alg2, Op2]): Resource[IO, HttpRoutes[IO]]
def codecs: CodecAPI

Expand Down Expand Up @@ -118,9 +118,9 @@ abstract class ServerHttpComplianceTestCase[
name = endpoint.id.toString + "(server|request): " + testCase.id,
run = {
deferred[I].flatMap { inputDeferred =>
val fakeImpl: smithy4s.Monadic[Alg, IO] =
originalService.transform[R](
new smithy4s.Interpreter[Op, IO] {
val fakeImpl: FunctorAlgebra[Alg, IO] =
originalService.fromPolyFunction[R](
new FunctorInterpreter[Op, IO] {
def apply[I_, E_, O_, SE_, SO_](
op: Op[I_, E_, O_, SE_, SO_]
): IO[O_] = {
Expand Down Expand Up @@ -159,8 +159,6 @@ abstract class ServerHttpComplianceTestCase[
errorSchema: Option[ErrorResponseTest[_, E]] = None
): ComplianceTest[IO] = {

type R[I_, E_, O_, SE_, SO_] = IO[O_]

ComplianceTest[IO](
name = endpoint.id.toString + "(server|response): " + testCase.id,
run = {
Expand Down Expand Up @@ -189,21 +187,19 @@ abstract class ServerHttpComplianceTestCase[
}
}

val fakeImpl: smithy4s.Monadic[NoOpService, IO] =
ammendedService.transform[R] {
new smithy4s.Interpreter[NoInputOp, IO] {
def apply[I_, E_, O_, SE_, SO_](
op: NoInputOp[I_, E_, O_, SE_, SO_]
): IO[O_] = {
val doc = testCase.params.getOrElse(Document.obj())
buildResult match {
case Left(onError) =>
onError(doc).flatMap { err =>
IO.raiseError[O_](err)
}
case Right(onOutput) =>
onOutput(doc).map(_.asInstanceOf[O_])
}
val fakeImpl: FunctorInterpreter[NoInputOp, IO] =
new FunctorInterpreter[NoInputOp, IO] {
def apply[I_, E_, O_, SE_, SO_](
op: NoInputOp[I_, E_, O_, SE_, SO_]
): IO[O_] = {
val doc = testCase.params.getOrElse(Document.obj())
buildResult match {
case Left(onError) =>
onError(doc).flatMap { err =>
IO.raiseError[O_](err)
}
case Right(onOutput) =>
onOutput(doc).map(_.asInstanceOf[O_])
}
}
}
Expand Down Expand Up @@ -235,22 +231,9 @@ abstract class ServerHttpComplianceTestCase[
}

private case class NoInputOp[I_, E_, O_, SE_, SO_]()
private trait NoOpService[F[_, _, _, _, _]] {
self =>

def void(): F[Unit, Nothing, Unit, Nothing, Nothing]
def transform[G[_, _, _, _, _]](
transformation: Transformation[F, G]
): NoOpService[G] = new Transformed(transformation)
class Transformed[G[_, _, _, _, _]](transformation: Transformation[F, G])
extends NoOpService[G] {
def void() =
transformation[Unit, Nothing, Unit, Nothing, Nothing](self.void())
}
}
private def prepareService[I, E, O, SE, SO](
endpoint: Endpoint[Op, I, E, O, SE, SO]
): (Service[NoOpService, NoInputOp], Request[IO]) = {
): (Service.Reflective[NoInputOp], Request[IO]) = {
val amendedEndpoint =
// format: off
new Endpoint[NoInputOp, Unit, E, O, Nothing, Nothing] {
Expand Down Expand Up @@ -278,27 +261,12 @@ abstract class ServerHttpComplianceTestCase[
val request = Request[IO](Method.GET, Uri.unsafeFromString("/"))
val amendedService =
// format: off
new Service[NoOpService, NoInputOp]() {
object reified extends NoOpService[NoInputOp] {
def void() = NoInputOp()
}
new Service.Reflective[NoInputOp] {
override def id: ShapeId = ShapeId("custom", "service")
override def endpoints: List[Endpoint[NoInputOp, _, _, _, _, _]] = List(amendedEndpoint)
override def endpoint[I_, E_, O_, SI_, SO_](op: NoInputOp[I_, E_, O_, SI_, SO_]): (I_, Endpoint[NoInputOp, I_, E_, O_, SI_, SO_]) = ???
override def version: String = originalService.version
override def hints: Hints = originalService.hints

override def transform[P2[_, _, _, _, _]](transformation: Transformation[NoInputOp, P2]): NoOpService[P2] = reified.transform(transformation)

override def transform[F[_, _, _, _, _], G[_, _, _, _, _]](
alg: NoOpService[F],
transformation: Transformation[F, G]
): NoOpService[G] = alg.transform(transformation)
override def asTransformation[P2[_, _, _, _, _]](impl: NoOpService[P2]): Transformation[NoInputOp, P2] = new Transformation[NoInputOp, P2]() {
def apply[I_, E_, O_, SI_, SO_](op : NoInputOp[I_, E_, O_, SI_, SO_]) : P2[I_, E_, O_, SI_, SO_] ={
impl.void().asInstanceOf[P2[I_, E_, O_, SI_, SO_]]
}
}
}
// format: on
(amendedService, request)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ object WeaverComplianceTest extends SimpleIOSuite {
smithy4s.api.SimpleRestJson()
) {
def getServer[Alg2[_[_, _, _, _, _]], Op2[_, _, _, _, _]](
impl: smithy4s.Monadic[Alg2, IO]
impl: smithy4s.kinds.FunctorAlgebra[Alg2, IO]
)(implicit s: Service[Alg2, Op2]): Resource[IO, HttpRoutes[IO]] =
SimpleRestJsonBuilder(s).routes(impl).resource

Expand Down
29 changes: 0 additions & 29 deletions modules/core/src-2/ExistentialsPlatformCompat.scala

This file was deleted.

Loading

0 comments on commit d57f7d1

Please sign in to comment.