Skip to content

Commit

Permalink
Make ShapeId a datatype (#25)
Browse files Browse the repository at this point in the history
* Makes ShapeID a datatype, that can be used as a hint, and as a key to maps. 
* Change rendering of newtype to facilitate the use of ids as hints 
* Bump smithy to 1.16.0
  • Loading branch information
Baccata committed Jan 5, 2022
1 parent 7cb7e24 commit 7aadebd
Show file tree
Hide file tree
Showing 50 changed files with 234 additions and 222 deletions.
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,7 @@ lazy val Dependencies = new {
)

val Smithy = new {
val smithyVersion = "1.15.0"
val smithyVersion = "1.16.0"
val model = "software.amazon.smithy" % "smithy-model" % smithyVersion
val awsTraits =
"software.amazon.smithy" % "smithy-aws-traits" % smithyVersion
Expand Down
3 changes: 1 addition & 2 deletions modules/aws-kernel/src/smithy4s/aws/AwsRegion.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ import smithy4s.Newtype

object AwsRegion extends Newtype[String] {

val namespace = "smithy4s.aws"
val name = "AwsRegion"
val id = smithy4s.ShapeId("smithy4s.aws", "AwsRegion")

val AF_SOUTH_1: AwsRegion = apply("af-south-1")
val AP_EAST_1: AwsRegion = apply("ap-east-1")
Expand Down
4 changes: 2 additions & 2 deletions modules/aws/src/smithy4s/aws/AwsClient.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,14 @@ object AwsClient {
awsService <- service.hints
.get(_root_.aws.api.Service)
.liftTo[Resource[F, *]](
initError(s"${service.identifier} is not an AWS service")
initError(s"${service.id.show} is not an AWS service")
)
endpointPrefix <- awsService.endpointPrefix.liftTo[Resource[F, *]](
initError(s"No endpoint prefix for $awsService")
)
awsProtocol <- AwsProtocol(service.hints).liftTo[Resource[F, *]](
initError(
s"AWS protocol used by ${service.identifier} is not yet supported"
s"AWS protocol used by ${service.id.show} is not yet supported"
)
)
} yield service.transform(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ private[aws] class AwsJsonRPCInterpreter[Alg[_[_, _, _, _, _]], Op[_,_,_,_,_], F
}

private val signer: AwsSigner[F] = AwsSigner.rpcSigner[F](
service,
service.id,
endpointPrefix,
awsEnv,
contentType
Expand Down
6 changes: 3 additions & 3 deletions modules/aws/src/smithy4s/aws/internals/AwsSigner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ package internals

import cats.Monad
import cats.syntax.all._
import smithy4s.HasId
import smithy4s.aws.kernel.AwsSignature
import smithy4s.http.CaseInsensitive
import smithy4s.http.HttpMethod
import smithy4s.http.Metadata
import smithy4s.ShapeId

private[aws] trait AwsSigner[F[_]] {
def sign(
Expand All @@ -38,15 +38,15 @@ object AwsSigner {
private[aws] val EMPTY_PATH = "/"

private[aws] def rpcSigner[F[_]: Monad](
serviceId: HasId,
serviceId: ShapeId,
endpointPrefix: String,
environment: AwsEnvironment[F],
contentType: String
): AwsSigner[F] =
new RPCSigner[F](serviceId, endpointPrefix, environment, contentType)

private class RPCSigner[F[_]: Monad](
serviceId: HasId,
serviceId: ShapeId,
endpointPrefix: String,
awsEnv: AwsEnvironment[F],
contentType: String
Expand Down
3 changes: 3 additions & 0 deletions modules/codegen/src/smithy4s/codegen/CollisionAvoidance.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ object CollisionAvoidance {
val newOps = ops.map {
case Operation(
name,
ns,
params,
input,
errors,
Expand All @@ -41,6 +42,7 @@ object CollisionAvoidance {
) =>
Operation(
protect(name.capitalize),
ns,
params.map(modField),
modType(input),
errors.map(modType),
Expand Down Expand Up @@ -224,6 +226,7 @@ object CollisionAvoidance {
val Service_ = "smithy4s.Service"
val Endpoint_ = "smithy4s.Endpoint"
val NoInput_ = "smithy4s.NoInput"
val ShapeId_ = "smithy4s.ShapeId"
val Schema_ = "smithy4s.Schema"
val StreamingSchema_ = "smithy4s.StreamingSchema"
val Enumeration_ = "smithy4s.Enumeration"
Expand Down
1 change: 1 addition & 0 deletions modules/codegen/src/smithy4s/codegen/IR.scala
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ case class Service(

case class Operation(
name: String,
originalNamespace: String,
params: List[Field],
input: Type,
errors: List[Type],
Expand Down
57 changes: 27 additions & 30 deletions modules/codegen/src/smithy4s/codegen/Renderer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,6 @@ private[codegen] class Renderer(compilationUnit: CompilationUnit) { self =>
block(
s"package object ${compilationUnit.namespace.split('.').last}"
)(
line(s"""val NAMESPACE: String = "${compilationUnit.namespace}""""),
newline,
compilationUnit.declarations.map(renderDeclPackageContents),
newline,
typeAliases,
Expand All @@ -117,8 +115,7 @@ private[codegen] class Renderer(compilationUnit: CompilationUnit) { self =>
)(
s"def apply[F[_]](implicit F: $name[F]): F.type = F",
s"def service : smithy4s.Service[${name}Gen, ${name}Operation] = ${name}Gen",
s"def namespace: String = service.namespace",
s"def name: String = service.name"
s"val id: $ShapeId_ = service.id"
)
)
case _ => empty
Expand Down Expand Up @@ -167,12 +164,12 @@ private[codegen] class Renderer(compilationUnit: CompilationUnit) { self =>
s"def apply[F[_]](implicit F: smithy4s.Monadic[$genName, F]): F.type = F"
),
newline,
renderHintsVal(hints),
renderId(originalName),
newline,
renderHintsValWithId(hints),
newline,
line(s"val endpoints = List").args(ops.map(_.name)),
newline,
line(s"""def namespace: String = "$namespace""""),
line(s"""val name: String = "$originalName""""),
line(s"""val version: String = "$version""""),
newline,
if (ops.isEmpty) {
Expand Down Expand Up @@ -288,7 +285,8 @@ private[codegen] class Renderer(compilationUnit: CompilationUnit) { self =>
s"val output: $Schema_[${op.output.render}] = ${op.output.schemaRef}.withHints(smithy4s.internals.InputOutput.Output)",
renderStreamingSchemaVal("streamedInput", op.streamedInput),
renderStreamingSchemaVal("streamedOutput", op.streamedOutput),
renderHintsVal(op.hints),
renderId(op.name, op.originalNamespace),
renderHintsValWithId(op.hints),
s"def wrap(input: ${op.input.render}) = ${opName}($input)",
renderErrorable(op),
renderHttpSpecific(op)
Expand Down Expand Up @@ -346,10 +344,9 @@ private[codegen] class Renderer(compilationUnit: CompilationUnit) { self =>
}
} else line(decl),
obj(name, ext = hintKey(name, hints))(
line(s"""def namespace: String = NAMESPACE"""),
line(s"""val name: String = "$name""""),
renderId(name),
newline,
renderHintsVal(hints),
renderHintsValWithId(hints),
newline,
if (fields.nonEmpty) {
val definition = if (recursive) "recursive(struct" else "struct"
Expand Down Expand Up @@ -450,10 +447,9 @@ private[codegen] class Renderer(compilationUnit: CompilationUnit) { self =>
lines(
s"sealed trait $name",
obj(name, ext = hintKey(name, hints))(
line(s"""def namespace: String = NAMESPACE"""),
line(s"""val name: String = "$name""""),
renderId(name),
newline,
renderHintsVal(hints),
renderHintsValWithId(hints),
newline,
alts.map { case Alt(altName, _, tpe, _) =>
val cn = caseName(altName)
Expand Down Expand Up @@ -508,8 +504,7 @@ private[codegen] class Renderer(compilationUnit: CompilationUnit) { self =>
): RenderResult = lines(
s"sealed abstract class $name(val value: String, val ordinal: Int) extends Product with Serializable",
obj(name, ext = s"$Enumeration_[$name]", w = hintKey(name, hints))(
line(s"""def namespace: String = NAMESPACE"""),
line(s"""val name: String = "$name""""),
renderId(name),
newline,
values.zipWithIndex.map { case (e @ EnumValue(value, _, _), index) =>
line(
Expand All @@ -536,27 +531,21 @@ private[codegen] class Renderer(compilationUnit: CompilationUnit) { self =>
): RenderResult = {
val imports = tpe.imports ++ Set("smithy4s.Newtype") ++ syntaxImport

val (hintsVal, hintsRef, withHints) =
val (hintsVal, withHints) =
if (hints.nonEmpty)
(
renderHintsVal(hints),
s"val hints: $Hints_ = T.hints",
renderHintsValWithId(hints),
".withHints(hints)"
)
else (RenderResult.empty, "", "")
else (RenderResult.empty, "")

lines(
obj(name, extensions = List(s"Newtype[${tpe.render}]"))(
obj("T")(
hintsVal,
s"val schema : $Schema_[${tpe.render}] = ${tpe.schemaRef}$withHints",
s"implicit val staticSchema : $Static_[$Schema_[${tpe.render}]] = $Static_(schema)"
),
renderId(name),
hintsVal,
s"val underlyingSchema : $Schema_[${tpe.render}] = ${tpe.schemaRef}$withHints",
lines(
line("def namespace = NAMESPACE"),
line(s"""val name = "${name}""""),
hintsRef,
s"val schema : $Schema_[$name] = bijection(T.schema, $name(_), (_ : $name).value)",
s"val schema : $Schema_[$name] = bijection(underlyingSchema, $name(_), (_ : $name).value)",
s"implicit val staticSchema : $Static_[$Schema_[$name]] = $Static_(schema)"
)
)
Expand Down Expand Up @@ -650,7 +639,7 @@ private[codegen] class Renderer(compilationUnit: CompilationUnit) { self =>
case Type.Alias(_, name, Type.PrimitiveType(_)) =>
s"$name.schema"
case Type.Alias(_, name, _) =>
s"$name.T.schema"
s"$name.underlyingSchema"
case Type.Ref(_, name) => s"$name.schema"
}

Expand Down Expand Up @@ -693,6 +682,14 @@ private[codegen] class Renderer(compilationUnit: CompilationUnit) { self =>
case _ => None
}

def renderId(name: String, ns: String = namespace): RenderResult =
line(s"""val id: $ShapeId_ = $ShapeId_("$ns", "$name")""")

def renderHintsValWithId(hints: List[Hint]): RenderResult =
line(s"val hints : $Hints_ = $Hints_").args {
"id" :: hints.flatMap(renderHint(_).toList)
}

def renderHintsVal(hints: List[Hint]): RenderResult =
line(s"val hints : $Hints_ = $Hints_").args {
hints.flatMap(renderHint(_).toList)
Expand Down
18 changes: 10 additions & 8 deletions modules/codegen/src/smithy4s/codegen/SmithyToIR.scala
Original file line number Diff line number Diff line change
Expand Up @@ -112,21 +112,20 @@ private[codegen] class SmithyToIR(model: Model, namespace: String) {
.map(model.getShape(_).asScala)
.collect { case Some(S.Operation(op)) =>
val inputType =
op.getInput().asScala.flatMap(_.tpe).getOrElse(Type.unit)
op.getInputShape().tpe.getOrElse(Type.unit)

val params =
op.getInput()
.asScala
.flatMap(_.shape)
op.getInputShape()
.shape
.toList
.flatMap(_.fields)

def streamedMember(shapeId: ShapeId) =
shapeId.shape
.map(_.members().asScala.toList)
.flatMap(_.collectFirstSome(streamingField))
val streamedInput = op.getInput().asScala.flatMap(streamedMember)
val streamedOutput = op.getOutput().asScala.flatMap(streamedMember)
val streamedInput = streamedMember(op.getInputShape())
val streamedOutput = streamedMember(op.getOutputShape())

val errorTypes = (generalErrors ++ op
.getErrors()
Expand All @@ -138,10 +137,11 @@ private[codegen] class SmithyToIR(model: Model, namespace: String) {
.toList).distinct

val outputType =
op.getOutput().asScala.flatMap(_.tpe).getOrElse(Type.unit)
op.getOutputShape().tpe.getOrElse(Type.unit)

Operation(
op.name,
op.namespace,
params,
inputType,
errorTypes,
Expand Down Expand Up @@ -330,7 +330,9 @@ private[codegen] class SmithyToIR(model: Model, namespace: String) {
}

def structureShape(x: StructureShape): Option[Type] =
Type.Ref(x.namespace, x.name).some
if (x.getId() == ShapeId.fromParts("smithy.api", "Unit"))
Some(Type.unit)
else Type.Ref(x.namespace, x.name).some

def unionShape(x: UnionShape): Option[Type] =
Type.Ref(x.namespace, x.name).some
Expand Down
19 changes: 9 additions & 10 deletions modules/core/src-2/Hints.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ package smithy4s
*/
trait Hints {
def isEmpty: Boolean
def all: Seq[Hints.Binding[_]]
def toMap: Map[Hints.Key[_], Hint]
def all: Iterable[Hints.Binding[_]]
def get[A](implicit key: Hints.Key[A]): Option[A]
final def get[A](key: Hints.Key.Has[A]): Option[A] = get(key.getKey)
final def get[T](nt: Newtype[T]): Option[nt.Type] = get(nt.key)
Expand All @@ -38,7 +39,7 @@ trait Hints {
object Hints {

def apply[S](bindings: Hint*): Hints = {
new Impl(bindings, bindings.map(_.tuple: (Key[_], Hint)).toMap)
new Impl(bindings.map(_.tuple: (Key[_], Hint)).toMap)
}

trait Schematic[F[_]] {
Expand Down Expand Up @@ -79,21 +80,19 @@ object Hints {
}

private[smithy4s] class Impl(
bindings: Seq[Hint],
map: Map[Key[_], Hint]
val toMap: Map[Key[_], Hint]
) extends Hints {
val isEmpty = bindings.isEmpty
val all: Seq[Hint] = bindings
val isEmpty = toMap.isEmpty
def all: Iterable[Hint] = toMap.values
def get[A](implicit key: Key[A]): Option[A] =
map.get(key).map { case Binding(_, value) =>
toMap.get(key).map { case Binding(_, value) =>
value.asInstanceOf[A]
}
def ++(other: Hints): Hints = {
val b = bindings ++ other.all
new Impl(b, b.map(_.tuple: (Key[_], Hint)).toMap)
new Impl(toMap ++ other.toMap)
}
override def toString(): String =
s"Hints(${bindings.map(_.value).mkString(", ")})"
s"Hints(${all.map(_.value).mkString(", ")})"
}

case class Binding[A](key: Key[A], value: A) {
Expand Down
3 changes: 1 addition & 2 deletions modules/core/src-2/Newtype.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@ abstract class Newtype[A] extends HasId { self =>
}

implicit val key: Hints.Key[Type] = new Hints.Key[Type] {
def namespace: String = self.namespace
def name: String = self.name
def id: ShapeId = self.id
}

def unapply(t: Type): Some[A] = Some(t.value)
Expand Down
Loading

0 comments on commit 7aadebd

Please sign in to comment.