diff --git a/build.sbt b/build.sbt index 534545d98..c1390091f 100644 --- a/build.sbt +++ b/build.sbt @@ -841,7 +841,7 @@ lazy val complianceTests = projectMatrix */ lazy val example = projectMatrix .in(file("modules/example")) - .dependsOn(`http4s-swagger`) + .dependsOn(`http4s-swagger`, cats) .disablePlugins(ScalafixPlugin) .disablePlugins(HeaderPlugin) .settings( @@ -871,7 +871,8 @@ lazy val example = projectMatrix (ThisBuild / baseDirectory).value / "sampleSpecs" / "mixins.smithy", (ThisBuild / baseDirectory).value / "sampleSpecs" / "defaults.smithy", (ThisBuild / baseDirectory).value / "sampleSpecs" / "quoted_string.smithy", - (ThisBuild / baseDirectory).value / "sampleSpecs" / "numeric.smithy" + (ThisBuild / baseDirectory).value / "sampleSpecs" / "numeric.smithy", + (ThisBuild / baseDirectory).value / "sampleSpecs" / "typeclass.smithy" ), Compile / resourceDirectory := (ThisBuild / baseDirectory).value / "modules" / "example" / "resources", libraryDependencies += Dependencies.Http4s.emberServer.value, diff --git a/modules/cats/src/smithy4s/interopcats/SchemaVisitorHash.scala b/modules/cats/src/smithy4s/interopcats/SchemaVisitorHash.scala index 5b20cad5d..bb5976303 100644 --- a/modules/cats/src/smithy4s/interopcats/SchemaVisitorHash.scala +++ b/modules/cats/src/smithy4s/interopcats/SchemaVisitorHash.scala @@ -25,21 +25,24 @@ import cats.implicits.{ import smithy4s.{Bijection, Hints, Lazy, Refinement, ShapeId} import smithy4s.capability.EncoderK import smithy4s.interopcats.instances.HashInstances._ -import smithy4s.schema.{ - Alt, - CollectionTag, - EnumValue, - Field, - Primitive, - Schema, - SchemaAlt, - SchemaField, - SchemaVisitor -} +import smithy4s.schema.Schema +import smithy4s.schema._ import scala.util.hashing.MurmurHash3.productSeed -object SchemaVisitorHash extends SchemaVisitor[Hash] { self => +object SchemaVisitorHash extends CachedSchemaCompiler.Impl[Hash] { + protected type Aux[A] = Hash[A] + def fromSchema[A]( + schema: Schema[A], + cache: Cache + ): Hash[A] = { + schema.compile(new SchemaVisitorHash(cache)) + } +} + +final class SchemaVisitorHash( + val cache: CompilationCache[Hash] +) extends SchemaVisitor.Cached[Hash] { self => override def primitive[P]( shapeId: ShapeId, diff --git a/modules/cats/src/smithy4s/interopcats/SchemaVisitorShow.scala b/modules/cats/src/smithy4s/interopcats/SchemaVisitorShow.scala index 9816648fe..69594ccc8 100644 --- a/modules/cats/src/smithy4s/interopcats/SchemaVisitorShow.scala +++ b/modules/cats/src/smithy4s/interopcats/SchemaVisitorShow.scala @@ -21,20 +21,23 @@ import cats.implicits.toContravariantOps import smithy4s._ import smithy4s.capability.EncoderK import smithy4s.interopcats.instances.ShowInstances._ -import smithy4s.schema.{ - Alt, - CollectionTag, - EnumValue, - Field, - Primitive, - Schema, - SchemaAlt, - SchemaField, - SchemaVisitor -} +import smithy4s.schema.Schema +import smithy4s.schema._ import smithy4s.schema.Alt.Precompiler -object SchemaVisitorShow extends SchemaVisitor[Show] { self => +object SchemaVisitorShow extends CachedSchemaCompiler.Impl[Show] { + protected type Aux[A] = Show[A] + def fromSchema[A]( + schema: Schema[A], + cache: Cache + ): Show[A] = { + schema.compile(new SchemaVisitorShow(cache)) + } +} + +final class SchemaVisitorShow( + val cache: CompilationCache[Show] +) extends SchemaVisitor.Cached[Show] { self => override def primitive[P]( shapeId: ShapeId, diff --git a/modules/cats/test/src/HashVisitorSpec.scala b/modules/cats/test/src/HashVisitorSpec.scala index d8ddde681..533299405 100644 --- a/modules/cats/test/src/HashVisitorSpec.scala +++ b/modules/cats/test/src/HashVisitorSpec.scala @@ -18,7 +18,7 @@ package smithy4s.interopcats import cats.Hash import smithy4s.schema.Schema._ -import smithy4s.schema.{Schema, SchemaVisitor} +import smithy4s.schema.Schema import smithy4s.{ByteArray, Hints, ShapeId, Timestamp} import smithy4s.interopcats.testcases.FooBar import smithy4s.interopcats.testcases._ @@ -30,7 +30,7 @@ import HashTestUtils._ object HashVisitorSpec extends FunSuite with CompatProvider { - val visitor: SchemaVisitor[Hash] = SchemaVisitorHash + def visitor[A]: Schema[A] => Hash[A] = SchemaVisitorHash.fromSchema(_) test("int") { val schema: Schema[Int] = int diff --git a/modules/cats/test/src/ShowVisitorSpec.scala b/modules/cats/test/src/ShowVisitorSpec.scala index 01c2e59df..7afe579a2 100644 --- a/modules/cats/test/src/ShowVisitorSpec.scala +++ b/modules/cats/test/src/ShowVisitorSpec.scala @@ -16,6 +16,7 @@ package smithy4s.interopcats +import cats.Show import smithy4s.{ByteArray, ShapeId, Timestamp} import smithy4s.schema.Schema import smithy4s.schema.Schema._ @@ -26,7 +27,8 @@ import smithy4s.interopcats.testcases.IntOrString._ object ShowVisitorSpec extends FunSuite with CompatProvider { - val schemaVisitorShow = SchemaVisitorShow + def schemaVisitorShow[A]: Schema[A] => Show[A] = + SchemaVisitorShow.fromSchema(_) test("int") { val schema: Schema[Int] = int diff --git a/modules/codegen/src/smithy4s/codegen/internals/IR.scala b/modules/codegen/src/smithy4s/codegen/internals/IR.scala index d6947bbed..aad8874f1 100644 --- a/modules/codegen/src/smithy4s/codegen/internals/IR.scala +++ b/modules/codegen/src/smithy4s/codegen/internals/IR.scala @@ -280,6 +280,8 @@ private[internals] object Hint { case object IndexedSeq extends SpecializedList } case object UniqueItems extends Hint + case class Typeclass(id: ShapeId, targetType: String, interpreter: String) + extends Hint implicit val eq: Eq[Hint] = Eq.fromUniversalEquals } diff --git a/modules/codegen/src/smithy4s/codegen/internals/Renderer.scala b/modules/codegen/src/smithy4s/codegen/internals/Renderer.scala index 4858cd139..533199928 100644 --- a/modules/codegen/src/smithy4s/codegen/internals/Renderer.scala +++ b/modules/codegen/src/smithy4s/codegen/internals/Renderer.scala @@ -78,7 +78,7 @@ private[internals] object Renderer { ) val classes = unit.declarations.map { decl => - val renderResult = r.renderDecl(decl) + val renderResult = r.renderDecl(decl) ++ newline val p = s"package ${unit.namespace}" val segments = renderResult.list.flatMap(_.segments.toList) @@ -516,6 +516,23 @@ private[internals] class Renderer(compilationUnit: CompilationUnit) { self => } } + private def renderTypeclass(hint: Hint.Typeclass, tpe: NameRef): Line = { + val target = NameRef(hint.targetType) + val interpreter = NameRef(hint.interpreter) + val lowerCasedName = uncapitalise(tpe.name) + line"implicit val $lowerCasedName${hint.id.getName.capitalize}: $target[$tpe] = $interpreter.fromSchema(schema)" + } + + private def renderTypeclasses( + hints: List[Hint], + tpe: NameRef + ): Lines = { + val result = hints.collect { case h: Hint.Typeclass => + renderTypeclass(h, tpe) + } + if (result.isEmpty) Lines.empty else newline ++ Lines(result) + } + private def renderProductNonMixin( product: Product, adtParent: Option[NameRef], @@ -606,6 +623,7 @@ private[internals] class Renderer(compilationUnit: CompilationUnit) { self => } else { line"implicit val schema: $Schema_[${product.nameRef}] = $constant_(${product.nameRef}()).withId(id).addHints(hints)" }, + renderTypeclasses(product.hints, product.nameRef), additionalLines ) ) @@ -857,7 +875,8 @@ private[internals] class Renderer(compilationUnit: CompilationUnit) { self => if (error) "" else ".withId(id).addHints(hints)" ) .appendToLast(if (recursive) ")" else "") - } + }, + renderTypeclasses(hints, name) ) ) } @@ -929,7 +948,8 @@ private[internals] class Renderer(compilationUnit: CompilationUnit) { self => line"val values: $list[$name] = $list".args( values.map(_.name) ), - line"implicit val schema: $Schema_[$name] = $enumeration_(values).withId(id).addHints(hints)" + line"implicit val schema: $Schema_[$name] = $enumeration_(values).withId(id).addHints(hints)", + renderTypeclasses(hints, name) ) ) @@ -955,7 +975,8 @@ private[internals] class Renderer(compilationUnit: CompilationUnit) { self => line"val underlyingSchema: $Schema_[$tpe] = ${tpe.schemaRef}$trailingCalls", lines( line"implicit val schema: $Schema_[$name] = $definition$bijection_(underlyingSchema, asBijection)$closing" - ) + ), + renderTypeclasses(hints, name) ) ) } diff --git a/modules/codegen/src/smithy4s/codegen/internals/SmithyToIR.scala b/modules/codegen/src/smithy4s/codegen/internals/SmithyToIR.scala index f5a3ab51c..9df0f8d8f 100644 --- a/modules/codegen/src/smithy4s/codegen/internals/SmithyToIR.scala +++ b/modules/codegen/src/smithy4s/codegen/internals/SmithyToIR.scala @@ -38,6 +38,7 @@ import scala.annotation.nowarn import scala.jdk.CollectionConverters._ import Type.Alias +import smithy4s.meta.TypeclassTrait private[codegen] object SmithyToIR { @@ -810,6 +811,27 @@ private[codegen] class SmithyToIR(model: Model, namespace: String) { } } + def maybeTypeclassesHint(shape: Shape): List[Hint.Typeclass] = { + shape + .getAllTraits() + .asScala + .flatMap { case (_, trt) => + model + .getShape(trt.toShapeId) + .asScala + .flatMap(_.getTrait(classOf[TypeclassTrait]).asScala) + .map(trt -> _) + } + .map { case (typeclassName, typeclassInfo) => + Hint.Typeclass( + typeclassName.toShapeId, + typeclassInfo.getTargetType, + typeclassInfo.getInterpreter + ) + } + .toList + } + @annotation.nowarn( "msg=class UniqueItemsTrait in package traits is deprecated" ) @@ -897,7 +919,8 @@ private[codegen] class SmithyToIR(model: Model, namespace: String) { } traits.collect(traitToHint(shape)) ++ documentationHint(shape) ++ - nonConstraintNonMetaTraits.map(unfoldTrait) + nonConstraintNonMetaTraits.map(unfoldTrait) ++ + maybeTypeclassesHint(shape) } case class AltInfo(name: String, tpe: Type, isAdtMember: Boolean) diff --git a/modules/codegen/test/src/smithy4s/codegen/internals/DefaultRenderModeSpec.scala b/modules/codegen/test/src/smithy4s/codegen/internals/DefaultRenderModeSpec.scala index b27283d3d..56dc23708 100644 --- a/modules/codegen/test/src/smithy4s/codegen/internals/DefaultRenderModeSpec.scala +++ b/modules/codegen/test/src/smithy4s/codegen/internals/DefaultRenderModeSpec.scala @@ -142,7 +142,8 @@ final class DefaultRenderModeSpec extends munit.FunSuite { | ){ | Test.apply | }.withId(id).addHints(hints) - |}""".stripMargin + |} + |""".stripMargin TestUtils.runTest(smithy, scalaCode) } diff --git a/modules/codegen/test/src/smithy4s/codegen/internals/TestUtils.scala b/modules/codegen/test/src/smithy4s/codegen/internals/TestUtils.scala index 9acb462c4..65d70e85f 100644 --- a/modules/codegen/test/src/smithy4s/codegen/internals/TestUtils.scala +++ b/modules/codegen/test/src/smithy4s/codegen/internals/TestUtils.scala @@ -45,7 +45,10 @@ object TestUtils { loc: Location ): Unit = { val scalaResults = generateScalaCode(smithySpec).values.toList - Assertions.assertEquals(scalaResults, List(expectedScalaCode)) + Assertions.assertEquals( + scalaResults.map(_.trim()), + List(expectedScalaCode.trim()) + ) } /** diff --git a/modules/core/src/smithy4s/schema/CachedSchemaCompiler.scala b/modules/core/src/smithy4s/schema/CachedSchemaCompiler.scala index b4f53141c..94f61bd9d 100644 --- a/modules/core/src/smithy4s/schema/CachedSchemaCompiler.scala +++ b/modules/core/src/smithy4s/schema/CachedSchemaCompiler.scala @@ -27,7 +27,7 @@ trait CachedSchemaCompiler[+F[_]] { object CachedSchemaCompiler { - private[smithy4s] abstract class Impl[F[_]] extends CachedSchemaCompiler[F] { + abstract class Impl[F[_]] extends CachedSchemaCompiler[F] { protected type Aux[_] type Cache = CompilationCache[Aux] diff --git a/modules/docs/markdown/04-codegen/01-customisation/09-typeclass.md b/modules/docs/markdown/04-codegen/01-customisation/09-typeclass.md new file mode 100644 index 000000000..de2744eda --- /dev/null +++ b/modules/docs/markdown/04-codegen/01-customisation/09-typeclass.md @@ -0,0 +1,66 @@ +--- +sidebar_label: Typeclass Instances +title: Non-Orphan Typeclass Instances +--- + +As of smithy4s version `0.18.x` you are able to create custom typeclass instances inside the companion objects of classes in the code generated by smithy4s. This allows you to have instances that are found via implicit resolution without any need to special imports. Common examples where this will come in handy are for the `cats.Show` and `cats.Eq` typeclasses, but you can use this feature for any typeclass. + +Here we will show an example using the `cats.Hash` typeclass. + +## Setup Typeclass in Smithy + +Here we will use the `smithy4s.meta#typeclass` trait to define a `hash` trait that represents the `cats.Hash` typeclass. + +```smithy +use smithy4s.meta#typeclass + +@trait +@typeclass(targetType: "cats.Hash", interpreter: "smithy4s.interopcats.SchemaVisitorHash") +structure hash {} +``` + +We are specifying `cats.hash` as the `targetType` since that is the typeclass which this trait represents. We are then specifying `smithy4s.interopcats.SchemaVisitorHash` as the classpath which points to a `CachedSchemaCompiler` for the `cats.Hash` typeclass. + +## Implement CachedSchemaCompiler + +Smithy4s has a concept called `CachedSchemaCompiler` which is an abstraction which we use here to interpret a `smithy4s.Schema` to produce an instance of a typeclass. Here is what this will look like: + +```scala +object SchemaVisitorHash extends CachedSchemaCompiler.Impl[Hash] { + protected type Aux[A] = Hash[A] + def fromSchema[A]( + schema: Schema[A], + cache: Cache + ): Hash[A] = { + schema.compile(new SchemaVisitorHash(cache)) + } +} +``` + +Here we are delegating to the `SchemaVisitorHash` which is doing the heavy lifting of interpreting the `smithy4s.Schema`. The `CachedSchemaCompiler.Impl` provides a `Cache` which we utilize to make sure we are not recompiling the same schema more than once. For more details on implementing a `SchemaVisitor`, you can check out the full `cats.Hash` schema compiler and visitor [here](https://github.com/disneystreaming/smithy4s/blob/series/0.18/modules/cats/src/smithy4s/interopcats/SchemaVisitorHash.scala). + +## Use the hash typeclass trait + +Now we are ready to use the `hash` trait we defined above. + +```smithy +@hash +structure MovieTheater { + name: String +} +``` + +This tells smithy4s to generate an instance of the `Hash` typeclass in the companion object of the `MovieTheater` type and to use the `CachedSchemaCompiler` defined above for the implementation. The generated code will look like: + +```scala +case class MovieTheater(name: Option[String] = None) +object MovieTheater extends ShapeTag.Companion[MovieTheater] { + val id: ShapeId = ShapeId("smithy4s.example", "MovieTheater") + + // ... + + implicit val schema: Schema[MovieTheater] = // ... + + implicit val movieTheaterHash: cats.Hash[MovieTheater] = SchemaVisitorHash.fromSchema(schema) +} +``` diff --git a/modules/example/src/smithy4s/example/AString.scala b/modules/example/src/smithy4s/example/AString.scala index 3ccde2010..6f2c8787c 100644 --- a/modules/example/src/smithy4s/example/AString.scala +++ b/modules/example/src/smithy4s/example/AString.scala @@ -15,4 +15,4 @@ object AString extends Newtype[String] { ) val underlyingSchema: Schema[String] = string.withId(id).addHints(hints) implicit val schema: Schema[AString] = bijection(underlyingSchema, asBijection) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/AStructure.scala b/modules/example/src/smithy4s/example/AStructure.scala index 0490c50a2..e2286a6f0 100644 --- a/modules/example/src/smithy4s/example/AStructure.scala +++ b/modules/example/src/smithy4s/example/AStructure.scala @@ -20,4 +20,4 @@ object AStructure extends ShapeTag.Companion[AStructure] { ){ AStructure.apply }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/AddBrandsInput.scala b/modules/example/src/smithy4s/example/AddBrandsInput.scala index 683b7ba96..1e9ee74c8 100644 --- a/modules/example/src/smithy4s/example/AddBrandsInput.scala +++ b/modules/example/src/smithy4s/example/AddBrandsInput.scala @@ -18,4 +18,4 @@ object AddBrandsInput extends ShapeTag.Companion[AddBrandsInput] { ){ AddBrandsInput.apply }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/AdtMixinOne.scala b/modules/example/src/smithy4s/example/AdtMixinOne.scala index cba4aac62..be5ae8479 100644 --- a/modules/example/src/smithy4s/example/AdtMixinOne.scala +++ b/modules/example/src/smithy4s/example/AdtMixinOne.scala @@ -3,4 +3,4 @@ package smithy4s.example trait AdtMixinOne { def lng: Option[Long] -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/AdtMixinThree.scala b/modules/example/src/smithy4s/example/AdtMixinThree.scala index 27c952189..e6fbd111e 100644 --- a/modules/example/src/smithy4s/example/AdtMixinThree.scala +++ b/modules/example/src/smithy4s/example/AdtMixinThree.scala @@ -4,4 +4,4 @@ import smithy4s.ByteArray trait AdtMixinThree { def blb: Option[ByteArray] -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/AdtMixinTwo.scala b/modules/example/src/smithy4s/example/AdtMixinTwo.scala index bfba95eb1..4a54d8b60 100644 --- a/modules/example/src/smithy4s/example/AdtMixinTwo.scala +++ b/modules/example/src/smithy4s/example/AdtMixinTwo.scala @@ -3,4 +3,4 @@ package smithy4s.example trait AdtMixinTwo { def sht: Option[Short] -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/Age.scala b/modules/example/src/smithy4s/example/Age.scala index 8facee21e..68195f1cd 100644 --- a/modules/example/src/smithy4s/example/Age.scala +++ b/modules/example/src/smithy4s/example/Age.scala @@ -15,4 +15,4 @@ object Age extends Newtype[smithy4s.example.refined.Age] { ) val underlyingSchema: Schema[smithy4s.example.refined.Age] = int.refined[smithy4s.example.refined.Age](smithy4s.example.AgeFormat()).withId(id).addHints(hints) implicit val schema: Schema[Age] = bijection(underlyingSchema, asBijection) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/AgeFormat.scala b/modules/example/src/smithy4s/example/AgeFormat.scala index 4fe6b7836..97d69be72 100644 --- a/modules/example/src/smithy4s/example/AgeFormat.scala +++ b/modules/example/src/smithy4s/example/AgeFormat.scala @@ -15,4 +15,4 @@ object AgeFormat extends ShapeTag.Companion[AgeFormat] { ) implicit val schema: Schema[AgeFormat] = constant(AgeFormat()).withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/AnotherString.scala b/modules/example/src/smithy4s/example/AnotherString.scala index 9a862c837..8077223de 100644 --- a/modules/example/src/smithy4s/example/AnotherString.scala +++ b/modules/example/src/smithy4s/example/AnotherString.scala @@ -18,4 +18,4 @@ object AnotherString extends Newtype[String] { ) val underlyingSchema: Schema[String] = string.withId(id).addHints(hints) implicit val schema: Schema[AnotherString] = bijection(underlyingSchema, asBijection) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/ArbitraryData.scala b/modules/example/src/smithy4s/example/ArbitraryData.scala index c3fa0046c..cfd11bc5e 100644 --- a/modules/example/src/smithy4s/example/ArbitraryData.scala +++ b/modules/example/src/smithy4s/example/ArbitraryData.scala @@ -16,4 +16,4 @@ object ArbitraryData extends Newtype[Document] { ) val underlyingSchema: Schema[Document] = document.withId(id).addHints(hints) implicit val schema: Schema[ArbitraryData] = recursive(bijection(underlyingSchema, asBijection)) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/ArbitraryDataTest.scala b/modules/example/src/smithy4s/example/ArbitraryDataTest.scala index 8b67c331c..721fe72d9 100644 --- a/modules/example/src/smithy4s/example/ArbitraryDataTest.scala +++ b/modules/example/src/smithy4s/example/ArbitraryDataTest.scala @@ -15,4 +15,4 @@ object ArbitraryDataTest extends ShapeTag.Companion[ArbitraryDataTest] { ) implicit val schema: Schema[ArbitraryDataTest] = constant(ArbitraryDataTest()).withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/BrandService.scala b/modules/example/src/smithy4s/example/BrandService.scala index 62df4b5df..854e546b9 100644 --- a/modules/example/src/smithy4s/example/BrandService.scala +++ b/modules/example/src/smithy4s/example/BrandService.scala @@ -80,3 +80,4 @@ object BrandServiceOperation { def wrap(input: AddBrandsInput) = AddBrands(input) } } + diff --git a/modules/example/src/smithy4s/example/BucketName.scala b/modules/example/src/smithy4s/example/BucketName.scala index 12a9f978c..cd11c8033 100644 --- a/modules/example/src/smithy4s/example/BucketName.scala +++ b/modules/example/src/smithy4s/example/BucketName.scala @@ -12,4 +12,4 @@ object BucketName extends Newtype[String] { val hints: Hints = Hints.empty val underlyingSchema: Schema[String] = string.withId(id).addHints(hints) implicit val schema: Schema[BucketName] = bijection(underlyingSchema, asBijection) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/Candy.scala b/modules/example/src/smithy4s/example/Candy.scala index 6c9664c29..2533e02cf 100644 --- a/modules/example/src/smithy4s/example/Candy.scala +++ b/modules/example/src/smithy4s/example/Candy.scala @@ -18,4 +18,4 @@ object Candy extends ShapeTag.Companion[Candy] { ){ Candy.apply }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/CommonFieldsOne.scala b/modules/example/src/smithy4s/example/CommonFieldsOne.scala index 145f016c1..0875c7e14 100644 --- a/modules/example/src/smithy4s/example/CommonFieldsOne.scala +++ b/modules/example/src/smithy4s/example/CommonFieldsOne.scala @@ -4,4 +4,4 @@ package smithy4s.example trait CommonFieldsOne { def a: Option[String] def b: Option[Int] -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/CommonFieldsTwo.scala b/modules/example/src/smithy4s/example/CommonFieldsTwo.scala index e6f7ba385..9f19c6362 100644 --- a/modules/example/src/smithy4s/example/CommonFieldsTwo.scala +++ b/modules/example/src/smithy4s/example/CommonFieldsTwo.scala @@ -3,4 +3,4 @@ package smithy4s.example trait CommonFieldsTwo { def c: Option[Long] -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/DefaultInMixinTest.scala b/modules/example/src/smithy4s/example/DefaultInMixinTest.scala index 7feb59c27..fd9fdf0c4 100644 --- a/modules/example/src/smithy4s/example/DefaultInMixinTest.scala +++ b/modules/example/src/smithy4s/example/DefaultInMixinTest.scala @@ -3,4 +3,4 @@ package smithy4s.example trait DefaultInMixinTest { def one: String -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/DefaultInMixinUsageTest.scala b/modules/example/src/smithy4s/example/DefaultInMixinUsageTest.scala index 1637a88ca..3c9b3af22 100644 --- a/modules/example/src/smithy4s/example/DefaultInMixinUsageTest.scala +++ b/modules/example/src/smithy4s/example/DefaultInMixinUsageTest.scala @@ -18,4 +18,4 @@ object DefaultInMixinUsageTest extends ShapeTag.Companion[DefaultInMixinUsageTes ){ DefaultInMixinUsageTest.apply }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/DefaultOrderingTest.scala b/modules/example/src/smithy4s/example/DefaultOrderingTest.scala index 2e10edb2c..0757f7bc3 100644 --- a/modules/example/src/smithy4s/example/DefaultOrderingTest.scala +++ b/modules/example/src/smithy4s/example/DefaultOrderingTest.scala @@ -21,4 +21,4 @@ object DefaultOrderingTest extends ShapeTag.Companion[DefaultOrderingTest] { ){ DefaultOrderingTest.apply }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/DefaultStringMap.scala b/modules/example/src/smithy4s/example/DefaultStringMap.scala index c2f6466b2..ea00b8c55 100644 --- a/modules/example/src/smithy4s/example/DefaultStringMap.scala +++ b/modules/example/src/smithy4s/example/DefaultStringMap.scala @@ -13,4 +13,4 @@ object DefaultStringMap extends Newtype[Map[String, String]] { val hints: Hints = Hints.empty val underlyingSchema: Schema[Map[String, String]] = map(string, string).withId(id).addHints(hints) implicit val schema: Schema[DefaultStringMap] = bijection(underlyingSchema, asBijection) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/DefaultTest.scala b/modules/example/src/smithy4s/example/DefaultTest.scala index 53b1410bc..a09cf0a4f 100644 --- a/modules/example/src/smithy4s/example/DefaultTest.scala +++ b/modules/example/src/smithy4s/example/DefaultTest.scala @@ -48,4 +48,4 @@ object DefaultTest extends ShapeTag.Companion[DefaultTest] { ){ DefaultTest.apply }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/DeprecatedService.scala b/modules/example/src/smithy4s/example/DeprecatedService.scala index e8ae6af18..841ffbf7e 100644 --- a/modules/example/src/smithy4s/example/DeprecatedService.scala +++ b/modules/example/src/smithy4s/example/DeprecatedService.scala @@ -84,3 +84,4 @@ object DeprecatedServiceOperation { def wrap(input: Unit) = DeprecatedOperation() } } + diff --git a/modules/example/src/smithy4s/example/DeprecatedString.scala b/modules/example/src/smithy4s/example/DeprecatedString.scala index 32bb4cf3e..ed56c9215 100644 --- a/modules/example/src/smithy4s/example/DeprecatedString.scala +++ b/modules/example/src/smithy4s/example/DeprecatedString.scala @@ -15,4 +15,4 @@ object DeprecatedString extends Newtype[String] { ) val underlyingSchema: Schema[String] = string.withId(id).addHints(hints) implicit val schema: Schema[DeprecatedString] = bijection(underlyingSchema, asBijection) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/DeprecatedStructure.scala b/modules/example/src/smithy4s/example/DeprecatedStructure.scala index 2edae9495..99d0a5890 100644 --- a/modules/example/src/smithy4s/example/DeprecatedStructure.scala +++ b/modules/example/src/smithy4s/example/DeprecatedStructure.scala @@ -23,4 +23,4 @@ object DeprecatedStructure extends ShapeTag.Companion[DeprecatedStructure] { ){ DeprecatedStructure.apply }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/DeprecatedUnion.scala b/modules/example/src/smithy4s/example/DeprecatedUnion.scala index d9d4e6232..622a0b70a 100644 --- a/modules/example/src/smithy4s/example/DeprecatedUnion.scala +++ b/modules/example/src/smithy4s/example/DeprecatedUnion.scala @@ -74,4 +74,4 @@ object DeprecatedUnion extends ShapeTag.Companion[DeprecatedUnion] { case c: DeprecatedUnionProductCase => DeprecatedUnionProductCase.alt(c) case c: UnionProductCaseDeprecatedAtCallSite => UnionProductCaseDeprecatedAtCallSite.alt(c) }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/DocTest.scala b/modules/example/src/smithy4s/example/DocTest.scala index d085b415d..ef9a06da7 100644 --- a/modules/example/src/smithy4s/example/DocTest.scala +++ b/modules/example/src/smithy4s/example/DocTest.scala @@ -18,4 +18,4 @@ object DocTest extends ShapeTag.Companion[DocTest] { ) implicit val schema: Schema[DocTest] = constant(DocTest()).withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/DogName.scala b/modules/example/src/smithy4s/example/DogName.scala index db127673f..7aecce595 100644 --- a/modules/example/src/smithy4s/example/DogName.scala +++ b/modules/example/src/smithy4s/example/DogName.scala @@ -12,4 +12,4 @@ object DogName extends Newtype[smithy4s.example.refined.Name] { val hints: Hints = Hints.empty val underlyingSchema: Schema[smithy4s.example.refined.Name] = string.refined[smithy4s.example.refined.Name](smithy4s.example.NameFormat()).withId(id).addHints(hints) implicit val schema: Schema[DogName] = bijection(underlyingSchema, asBijection) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/EmptyMixin.scala b/modules/example/src/smithy4s/example/EmptyMixin.scala index 4a446d9bc..dac6d1e40 100644 --- a/modules/example/src/smithy4s/example/EmptyMixin.scala +++ b/modules/example/src/smithy4s/example/EmptyMixin.scala @@ -2,4 +2,4 @@ package smithy4s.example trait EmptyMixin { -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/EnumWithDeprecations.scala b/modules/example/src/smithy4s/example/EnumWithDeprecations.scala index d0c1f5e5b..f36c4fa0e 100644 --- a/modules/example/src/smithy4s/example/EnumWithDeprecations.scala +++ b/modules/example/src/smithy4s/example/EnumWithDeprecations.scala @@ -35,4 +35,4 @@ object EnumWithDeprecations extends Enumeration[EnumWithDeprecations] with Shape NEW, ) implicit val schema: Schema[EnumWithDeprecations] = enumeration(values).withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/FaceCard.scala b/modules/example/src/smithy4s/example/FaceCard.scala index cdd7f92a7..6bc8e695f 100644 --- a/modules/example/src/smithy4s/example/FaceCard.scala +++ b/modules/example/src/smithy4s/example/FaceCard.scala @@ -40,4 +40,4 @@ object FaceCard extends Enumeration[FaceCard] with ShapeTag.Companion[FaceCard] JOKER, ) implicit val schema: Schema[FaceCard] = enumeration(values).withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/FancyList.scala b/modules/example/src/smithy4s/example/FancyList.scala index 827fcbc5d..7b969a817 100644 --- a/modules/example/src/smithy4s/example/FancyList.scala +++ b/modules/example/src/smithy4s/example/FancyList.scala @@ -13,4 +13,4 @@ object FancyList extends Newtype[smithy4s.example.refined.FancyList] { val hints: Hints = Hints.empty val underlyingSchema: Schema[smithy4s.example.refined.FancyList] = list(string).refined[smithy4s.example.refined.FancyList](smithy4s.example.FancyListFormat()).withId(id).addHints(hints) implicit val schema: Schema[FancyList] = bijection(underlyingSchema, asBijection) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/FancyListFormat.scala b/modules/example/src/smithy4s/example/FancyListFormat.scala index b06f64e7f..d523390d0 100644 --- a/modules/example/src/smithy4s/example/FancyListFormat.scala +++ b/modules/example/src/smithy4s/example/FancyListFormat.scala @@ -15,4 +15,4 @@ object FancyListFormat extends ShapeTag.Companion[FancyListFormat] { ) implicit val schema: Schema[FancyListFormat] = constant(FancyListFormat()).withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/Foo.scala b/modules/example/src/smithy4s/example/Foo.scala index d1a582f1f..79119fee2 100644 --- a/modules/example/src/smithy4s/example/Foo.scala +++ b/modules/example/src/smithy4s/example/Foo.scala @@ -67,4 +67,4 @@ object Foo extends ShapeTag.Companion[Foo] { case c: BIntCase => BIntCase.alt(c) case c: BDecCase => BDecCase.alt(c) }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/FooService.scala b/modules/example/src/smithy4s/example/FooService.scala index bec52dbba..71024e80e 100644 --- a/modules/example/src/smithy4s/example/FooService.scala +++ b/modules/example/src/smithy4s/example/FooService.scala @@ -91,3 +91,4 @@ object FooServiceOperation { def wrap(input: Unit) = GetFoo() } } + diff --git a/modules/example/src/smithy4s/example/GetFooOutput.scala b/modules/example/src/smithy4s/example/GetFooOutput.scala index f09b68ae5..e3247db6e 100644 --- a/modules/example/src/smithy4s/example/GetFooOutput.scala +++ b/modules/example/src/smithy4s/example/GetFooOutput.scala @@ -22,4 +22,4 @@ object GetFooOutput extends ShapeTag.Companion[GetFooOutput] { ){ GetFooOutput.apply }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/GetObjectInput.scala b/modules/example/src/smithy4s/example/GetObjectInput.scala index e2616bb3d..1789d3185 100644 --- a/modules/example/src/smithy4s/example/GetObjectInput.scala +++ b/modules/example/src/smithy4s/example/GetObjectInput.scala @@ -31,4 +31,4 @@ object GetObjectInput extends ShapeTag.Companion[GetObjectInput] { ){ GetObjectInput.apply }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/GetObjectOutput.scala b/modules/example/src/smithy4s/example/GetObjectOutput.scala index 83a00ca35..45cdb79fe 100644 --- a/modules/example/src/smithy4s/example/GetObjectOutput.scala +++ b/modules/example/src/smithy4s/example/GetObjectOutput.scala @@ -19,4 +19,4 @@ object GetObjectOutput extends ShapeTag.Companion[GetObjectOutput] { ){ GetObjectOutput.apply }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/GetStreamedObjectInput.scala b/modules/example/src/smithy4s/example/GetStreamedObjectInput.scala index c6f025b4f..dc515b3ac 100644 --- a/modules/example/src/smithy4s/example/GetStreamedObjectInput.scala +++ b/modules/example/src/smithy4s/example/GetStreamedObjectInput.scala @@ -18,4 +18,4 @@ object GetStreamedObjectInput extends ShapeTag.Companion[GetStreamedObjectInput] ){ GetStreamedObjectInput.apply }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/GetStreamedObjectOutput.scala b/modules/example/src/smithy4s/example/GetStreamedObjectOutput.scala index 3a175f269..a5dd2d732 100644 --- a/modules/example/src/smithy4s/example/GetStreamedObjectOutput.scala +++ b/modules/example/src/smithy4s/example/GetStreamedObjectOutput.scala @@ -13,4 +13,4 @@ object GetStreamedObjectOutput extends ShapeTag.Companion[GetStreamedObjectOutpu val hints: Hints = Hints.empty implicit val schema: Schema[GetStreamedObjectOutput] = constant(GetStreamedObjectOutput()).withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/Hash.scala b/modules/example/src/smithy4s/example/Hash.scala new file mode 100644 index 000000000..1b5e522f4 --- /dev/null +++ b/modules/example/src/smithy4s/example/Hash.scala @@ -0,0 +1,18 @@ +package smithy4s.example + +import smithy4s.Hints +import smithy4s.Schema +import smithy4s.ShapeId +import smithy4s.ShapeTag +import smithy4s.schema.Schema.constant + +final case class Hash() +object Hash extends ShapeTag.Companion[Hash] { + val id: ShapeId = ShapeId("smithy4s.example", "hash") + + val hints: Hints = Hints( + smithy.api.Trait(selector = None, structurallyExclusive = None, conflicts = None, breakingChanges = None), + ) + + implicit val schema: Schema[Hash] = constant(Hash()).withId(id).addHints(hints) +} diff --git a/modules/example/src/smithy4s/example/Letters.scala b/modules/example/src/smithy4s/example/Letters.scala index b56b814e6..ca46ec958 100644 --- a/modules/example/src/smithy4s/example/Letters.scala +++ b/modules/example/src/smithy4s/example/Letters.scala @@ -31,4 +31,4 @@ object Letters extends Enumeration[Letters] with ShapeTag.Companion[Letters] { C, ) implicit val schema: Schema[Letters] = enumeration(values).withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/LowHigh.scala b/modules/example/src/smithy4s/example/LowHigh.scala index 2710fa72a..fcee1fe05 100644 --- a/modules/example/src/smithy4s/example/LowHigh.scala +++ b/modules/example/src/smithy4s/example/LowHigh.scala @@ -31,4 +31,4 @@ object LowHigh extends Enumeration[LowHigh] with ShapeTag.Companion[LowHigh] { HIGH, ) implicit val schema: Schema[LowHigh] = enumeration(values).withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/MixinErrorExample.scala b/modules/example/src/smithy4s/example/MixinErrorExample.scala index c98302641..07afba73e 100644 --- a/modules/example/src/smithy4s/example/MixinErrorExample.scala +++ b/modules/example/src/smithy4s/example/MixinErrorExample.scala @@ -27,4 +27,4 @@ object MixinErrorExample extends ShapeTag.Companion[MixinErrorExample] { ){ MixinErrorExample.apply }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/MixinExample.scala b/modules/example/src/smithy4s/example/MixinExample.scala index 0074da55a..c346f2e11 100644 --- a/modules/example/src/smithy4s/example/MixinExample.scala +++ b/modules/example/src/smithy4s/example/MixinExample.scala @@ -24,4 +24,4 @@ object MixinExample extends ShapeTag.Companion[MixinExample] { ){ MixinExample.apply }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/MixinOptionalMember.scala b/modules/example/src/smithy4s/example/MixinOptionalMember.scala index a0c00b820..cd728e186 100644 --- a/modules/example/src/smithy4s/example/MixinOptionalMember.scala +++ b/modules/example/src/smithy4s/example/MixinOptionalMember.scala @@ -3,4 +3,4 @@ package smithy4s.example trait MixinOptionalMember { def a: Option[String] -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/MixinOptionalMemberDefaultAdded.scala b/modules/example/src/smithy4s/example/MixinOptionalMemberDefaultAdded.scala index 9afee5e94..758107025 100644 --- a/modules/example/src/smithy4s/example/MixinOptionalMemberDefaultAdded.scala +++ b/modules/example/src/smithy4s/example/MixinOptionalMemberDefaultAdded.scala @@ -18,4 +18,4 @@ object MixinOptionalMemberDefaultAdded extends ShapeTag.Companion[MixinOptionalM ){ MixinOptionalMemberDefaultAdded.apply }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/MixinOptionalMemberOverride.scala b/modules/example/src/smithy4s/example/MixinOptionalMemberOverride.scala index 27b5a09a5..b96d9288e 100644 --- a/modules/example/src/smithy4s/example/MixinOptionalMemberOverride.scala +++ b/modules/example/src/smithy4s/example/MixinOptionalMemberOverride.scala @@ -18,4 +18,4 @@ object MixinOptionalMemberOverride extends ShapeTag.Companion[MixinOptionalMembe ){ MixinOptionalMemberOverride.apply }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/MovieTheater.scala b/modules/example/src/smithy4s/example/MovieTheater.scala new file mode 100644 index 000000000..8a9ddda15 --- /dev/null +++ b/modules/example/src/smithy4s/example/MovieTheater.scala @@ -0,0 +1,26 @@ +package smithy4s.example + +import smithy4s.Hints +import smithy4s.Schema +import smithy4s.ShapeId +import smithy4s.ShapeTag +import smithy4s.interopcats.SchemaVisitorHash +import smithy4s.schema.Schema.string +import smithy4s.schema.Schema.struct + +final case class MovieTheater(name: Option[String] = None) +object MovieTheater extends ShapeTag.Companion[MovieTheater] { + val id: ShapeId = ShapeId("smithy4s.example", "MovieTheater") + + val hints: Hints = Hints( + smithy4s.example.Hash(), + ) + + implicit val schema: Schema[MovieTheater] = struct( + string.optional[MovieTheater]("name", _.name), + ){ + MovieTheater.apply + }.withId(id).addHints(hints) + + implicit val movieTheaterHash: cats.Hash[MovieTheater] = SchemaVisitorHash.fromSchema(schema) +} diff --git a/modules/example/src/smithy4s/example/MyOpError.scala b/modules/example/src/smithy4s/example/MyOpError.scala index 5ac494326..e1a65233e 100644 --- a/modules/example/src/smithy4s/example/MyOpError.scala +++ b/modules/example/src/smithy4s/example/MyOpError.scala @@ -16,4 +16,4 @@ object MyOpError extends ShapeTag.Companion[MyOpError] { ) implicit val schema: Schema[MyOpError] = constant(MyOpError()).withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/Name.scala b/modules/example/src/smithy4s/example/Name.scala index b07fb40b0..2ce5f32ed 100644 --- a/modules/example/src/smithy4s/example/Name.scala +++ b/modules/example/src/smithy4s/example/Name.scala @@ -12,4 +12,4 @@ object Name extends Newtype[smithy4s.example.refined.Name] { val hints: Hints = Hints.empty val underlyingSchema: Schema[smithy4s.example.refined.Name] = string.refined[smithy4s.example.refined.Name](smithy4s.example.NameFormat()).withId(id).addHints(hints) implicit val schema: Schema[Name] = bijection(underlyingSchema, asBijection) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/NameCollision.scala b/modules/example/src/smithy4s/example/NameCollision.scala index 7d53155a0..e75debc7f 100644 --- a/modules/example/src/smithy4s/example/NameCollision.scala +++ b/modules/example/src/smithy4s/example/NameCollision.scala @@ -132,3 +132,4 @@ object NameCollisionOperation { def wrap(input: Unit) = Endpoint() } } + diff --git a/modules/example/src/smithy4s/example/NameFormat.scala b/modules/example/src/smithy4s/example/NameFormat.scala index 7f2a1388f..349ad2d7b 100644 --- a/modules/example/src/smithy4s/example/NameFormat.scala +++ b/modules/example/src/smithy4s/example/NameFormat.scala @@ -15,4 +15,4 @@ object NameFormat extends ShapeTag.Companion[NameFormat] { ) implicit val schema: Schema[NameFormat] = constant(NameFormat()).withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/NetworkConnectionType.scala b/modules/example/src/smithy4s/example/NetworkConnectionType.scala new file mode 100644 index 000000000..72346a354 --- /dev/null +++ b/modules/example/src/smithy4s/example/NetworkConnectionType.scala @@ -0,0 +1,37 @@ +package smithy4s.example + +import smithy4s.Enumeration +import smithy4s.Hints +import smithy4s.Schema +import smithy4s.ShapeId +import smithy4s.ShapeTag +import smithy4s.interopcats.SchemaVisitorHash +import smithy4s.schema.Schema.enumeration + +sealed abstract class NetworkConnectionType(_value: String, _name: String, _intValue: Int, _hints: Hints) extends Enumeration.Value { + override type EnumType = NetworkConnectionType + override val value: String = _value + override val name: String = _name + override val intValue: Int = _intValue + override val hints: Hints = _hints + override def enumeration: Enumeration[EnumType] = NetworkConnectionType + @inline final def widen: NetworkConnectionType = this +} +object NetworkConnectionType extends Enumeration[NetworkConnectionType] with ShapeTag.Companion[NetworkConnectionType] { + val id: ShapeId = ShapeId("smithy4s.example", "NetworkConnectionType") + + val hints: Hints = Hints( + smithy4s.example.Hash(), + ) + + case object ETHERNET extends NetworkConnectionType("ETHERNET", "ETHERNET", 0, Hints()) + case object WIFI extends NetworkConnectionType("WIFI", "WIFI", 1, Hints()) + + val values: List[NetworkConnectionType] = List( + ETHERNET, + WIFI, + ) + implicit val schema: Schema[NetworkConnectionType] = enumeration(values).withId(id).addHints(hints) + + implicit val networkConnectionTypeHash: cats.Hash[NetworkConnectionType] = SchemaVisitorHash.fromSchema(schema) +} diff --git a/modules/example/src/smithy4s/example/NoMoreSpace.scala b/modules/example/src/smithy4s/example/NoMoreSpace.scala index c1ffdd68b..f250b0b10 100644 --- a/modules/example/src/smithy4s/example/NoMoreSpace.scala +++ b/modules/example/src/smithy4s/example/NoMoreSpace.scala @@ -29,4 +29,4 @@ object NoMoreSpace extends ShapeTag.Companion[NoMoreSpace] { ){ NoMoreSpace.apply }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/NonEmptyCandies.scala b/modules/example/src/smithy4s/example/NonEmptyCandies.scala index 6ed78d69f..8242d9759 100644 --- a/modules/example/src/smithy4s/example/NonEmptyCandies.scala +++ b/modules/example/src/smithy4s/example/NonEmptyCandies.scala @@ -13,4 +13,4 @@ object NonEmptyCandies extends Newtype[NonEmptyList[Candy]] { val hints: Hints = Hints.empty val underlyingSchema: Schema[NonEmptyList[Candy]] = list(Candy.schema).refined[NonEmptyList[Candy]](smithy4s.example.NonEmptyListFormat()).withId(id).addHints(hints) implicit val schema: Schema[NonEmptyCandies] = bijection(underlyingSchema, asBijection) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/NonEmptyListFormat.scala b/modules/example/src/smithy4s/example/NonEmptyListFormat.scala index 6b1415b19..f2b31906d 100644 --- a/modules/example/src/smithy4s/example/NonEmptyListFormat.scala +++ b/modules/example/src/smithy4s/example/NonEmptyListFormat.scala @@ -15,4 +15,4 @@ object NonEmptyListFormat extends ShapeTag.Companion[NonEmptyListFormat] { ) implicit val schema: Schema[NonEmptyListFormat] = constant(NonEmptyListFormat()).withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/NonEmptyMapFormat.scala b/modules/example/src/smithy4s/example/NonEmptyMapFormat.scala index ffbc9a788..d1ed7403b 100644 --- a/modules/example/src/smithy4s/example/NonEmptyMapFormat.scala +++ b/modules/example/src/smithy4s/example/NonEmptyMapFormat.scala @@ -15,4 +15,4 @@ object NonEmptyMapFormat extends ShapeTag.Companion[NonEmptyMapFormat] { ) implicit val schema: Schema[NonEmptyMapFormat] = constant(NonEmptyMapFormat()).withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/NonEmptyMapNumbers.scala b/modules/example/src/smithy4s/example/NonEmptyMapNumbers.scala index 2a56db7ad..8210cb534 100644 --- a/modules/example/src/smithy4s/example/NonEmptyMapNumbers.scala +++ b/modules/example/src/smithy4s/example/NonEmptyMapNumbers.scala @@ -15,4 +15,4 @@ object NonEmptyMapNumbers extends Newtype[NonEmptyMap[String, Int]] { val hints: Hints = Hints.empty val underlyingSchema: Schema[NonEmptyMap[String, Int]] = map(string, int).refined[NonEmptyMap[String, Int]](smithy4s.example.NonEmptyMapFormat()).withId(id).addHints(hints) implicit val schema: Schema[NonEmptyMapNumbers] = bijection(underlyingSchema, asBijection) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/NonEmptyNames.scala b/modules/example/src/smithy4s/example/NonEmptyNames.scala index 1b3c17dd5..a1dee3804 100644 --- a/modules/example/src/smithy4s/example/NonEmptyNames.scala +++ b/modules/example/src/smithy4s/example/NonEmptyNames.scala @@ -13,4 +13,4 @@ object NonEmptyNames extends Newtype[NonEmptyList[Name]] { val hints: Hints = Hints.empty val underlyingSchema: Schema[NonEmptyList[Name]] = list(Name.schema).refined[NonEmptyList[Name]](smithy4s.example.NonEmptyListFormat()).withId(id).addHints(hints) implicit val schema: Schema[NonEmptyNames] = bijection(underlyingSchema, asBijection) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/NonEmptyStrings.scala b/modules/example/src/smithy4s/example/NonEmptyStrings.scala index c6fd574ea..faf0c4f4d 100644 --- a/modules/example/src/smithy4s/example/NonEmptyStrings.scala +++ b/modules/example/src/smithy4s/example/NonEmptyStrings.scala @@ -14,4 +14,4 @@ object NonEmptyStrings extends Newtype[NonEmptyList[String]] { val hints: Hints = Hints.empty val underlyingSchema: Schema[NonEmptyList[String]] = list(string).refined[NonEmptyList[String]](smithy4s.example.NonEmptyListFormat()).withId(id).addHints(hints) implicit val schema: Schema[NonEmptyStrings] = bijection(underlyingSchema, asBijection) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/Numeric.scala b/modules/example/src/smithy4s/example/Numeric.scala index 435edf32c..03ae36e73 100644 --- a/modules/example/src/smithy4s/example/Numeric.scala +++ b/modules/example/src/smithy4s/example/Numeric.scala @@ -30,4 +30,4 @@ object Numeric extends ShapeTag.Companion[Numeric] { ){ Numeric.apply }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/ObjectKey.scala b/modules/example/src/smithy4s/example/ObjectKey.scala index a83037a42..2a89563ef 100644 --- a/modules/example/src/smithy4s/example/ObjectKey.scala +++ b/modules/example/src/smithy4s/example/ObjectKey.scala @@ -15,4 +15,4 @@ object ObjectKey extends Newtype[UUID] { ) val underlyingSchema: Schema[UUID] = uuid.withId(id).addHints(hints) implicit val schema: Schema[ObjectKey] = bijection(underlyingSchema, asBijection) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/ObjectService.scala b/modules/example/src/smithy4s/example/ObjectService.scala index bc261edd0..6e7b33d98 100644 --- a/modules/example/src/smithy4s/example/ObjectService.scala +++ b/modules/example/src/smithy4s/example/ObjectService.scala @@ -191,3 +191,4 @@ object ObjectServiceOperation { } } } + diff --git a/modules/example/src/smithy4s/example/ObjectSize.scala b/modules/example/src/smithy4s/example/ObjectSize.scala index 1bab494ed..ffc7a0abb 100644 --- a/modules/example/src/smithy4s/example/ObjectSize.scala +++ b/modules/example/src/smithy4s/example/ObjectSize.scala @@ -14,4 +14,4 @@ object ObjectSize extends Newtype[Int] { ) val underlyingSchema: Schema[Int] = int.withId(id).addHints(hints) implicit val schema: Schema[ObjectSize] = bijection(underlyingSchema, asBijection) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/OrderNumber.scala b/modules/example/src/smithy4s/example/OrderNumber.scala index 744c7d18e..9ae26da6a 100644 --- a/modules/example/src/smithy4s/example/OrderNumber.scala +++ b/modules/example/src/smithy4s/example/OrderNumber.scala @@ -14,4 +14,4 @@ object OrderNumber extends Newtype[Int] { ) val underlyingSchema: Schema[Int] = int.withId(id).addHints(hints) implicit val schema: Schema[OrderNumber] = bijection(underlyingSchema, asBijection) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/OrderType.scala b/modules/example/src/smithy4s/example/OrderType.scala index 004f84269..309864424 100644 --- a/modules/example/src/smithy4s/example/OrderType.scala +++ b/modules/example/src/smithy4s/example/OrderType.scala @@ -60,4 +60,4 @@ object OrderType extends ShapeTag.Companion[OrderType] { case c: InStoreOrder => InStoreOrder.alt(c) case PreviewCase => PreviewCaseAltWithValue }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/PersonAge.scala b/modules/example/src/smithy4s/example/PersonAge.scala index 09aa6037b..d8a39e1f9 100644 --- a/modules/example/src/smithy4s/example/PersonAge.scala +++ b/modules/example/src/smithy4s/example/PersonAge.scala @@ -15,4 +15,4 @@ object PersonAge extends Newtype[smithy4s.example.refined.Age] { ) val underlyingSchema: Schema[smithy4s.example.refined.Age] = int.refined[smithy4s.example.refined.Age](smithy4s.example.AgeFormat()).withId(id).addHints(hints) implicit val schema: Schema[PersonAge] = bijection(underlyingSchema, asBijection) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/PersonContactInfo.scala b/modules/example/src/smithy4s/example/PersonContactInfo.scala new file mode 100644 index 000000000..648f70aca --- /dev/null +++ b/modules/example/src/smithy4s/example/PersonContactInfo.scala @@ -0,0 +1,44 @@ +package smithy4s.example + +import smithy4s.Hints +import smithy4s.Schema +import smithy4s.ShapeId +import smithy4s.ShapeTag +import smithy4s.interopcats.SchemaVisitorHash +import smithy4s.schema.Schema.bijection +import smithy4s.schema.Schema.union + +sealed trait PersonContactInfo extends scala.Product with scala.Serializable { + @inline final def widen: PersonContactInfo = this +} +object PersonContactInfo extends ShapeTag.Companion[PersonContactInfo] { + val id: ShapeId = ShapeId("smithy4s.example", "PersonContactInfo") + + val hints: Hints = Hints( + smithy4s.example.Hash(), + ) + + final case class EmailCase(email: PersonEmail) extends PersonContactInfo + final case class PhoneCase(phone: PersonPhoneNumber) extends PersonContactInfo + + object EmailCase { + val hints: Hints = Hints.empty + val schema: Schema[EmailCase] = bijection(PersonEmail.schema.addHints(hints), EmailCase(_), _.email) + val alt = schema.oneOf[PersonContactInfo]("email") + } + object PhoneCase { + val hints: Hints = Hints.empty + val schema: Schema[PhoneCase] = bijection(PersonPhoneNumber.schema.addHints(hints), PhoneCase(_), _.phone) + val alt = schema.oneOf[PersonContactInfo]("phone") + } + + implicit val schema: Schema[PersonContactInfo] = union( + EmailCase.alt, + PhoneCase.alt, + ){ + case c: EmailCase => EmailCase.alt(c) + case c: PhoneCase => PhoneCase.alt(c) + }.withId(id).addHints(hints) + + implicit val personContactInfoHash: cats.Hash[PersonContactInfo] = SchemaVisitorHash.fromSchema(schema) +} diff --git a/modules/example/src/smithy4s/example/PersonEmail.scala b/modules/example/src/smithy4s/example/PersonEmail.scala new file mode 100644 index 000000000..4492afc46 --- /dev/null +++ b/modules/example/src/smithy4s/example/PersonEmail.scala @@ -0,0 +1,20 @@ +package smithy4s.example + +import smithy4s.Hints +import smithy4s.Newtype +import smithy4s.Schema +import smithy4s.ShapeId +import smithy4s.interopcats.SchemaVisitorHash +import smithy4s.schema.Schema.bijection +import smithy4s.schema.Schema.string + +object PersonEmail extends Newtype[String] { + val id: ShapeId = ShapeId("smithy4s.example", "PersonEmail") + val hints: Hints = Hints( + smithy4s.example.Hash(), + ) + val underlyingSchema: Schema[String] = string.withId(id).addHints(hints) + implicit val schema: Schema[PersonEmail] = bijection(underlyingSchema, asBijection) + + implicit val personEmailHash: cats.Hash[PersonEmail] = SchemaVisitorHash.fromSchema(schema) +} diff --git a/modules/example/src/smithy4s/example/PersonPhoneNumber.scala b/modules/example/src/smithy4s/example/PersonPhoneNumber.scala new file mode 100644 index 000000000..e0b05f7b1 --- /dev/null +++ b/modules/example/src/smithy4s/example/PersonPhoneNumber.scala @@ -0,0 +1,20 @@ +package smithy4s.example + +import smithy4s.Hints +import smithy4s.Newtype +import smithy4s.Schema +import smithy4s.ShapeId +import smithy4s.interopcats.SchemaVisitorHash +import smithy4s.schema.Schema.bijection +import smithy4s.schema.Schema.string + +object PersonPhoneNumber extends Newtype[String] { + val id: ShapeId = ShapeId("smithy4s.example", "PersonPhoneNumber") + val hints: Hints = Hints( + smithy4s.example.Hash(), + ) + val underlyingSchema: Schema[String] = string.withId(id).addHints(hints) + implicit val schema: Schema[PersonPhoneNumber] = bijection(underlyingSchema, asBijection) + + implicit val personPhoneNumberHash: cats.Hash[PersonPhoneNumber] = SchemaVisitorHash.fromSchema(schema) +} diff --git a/modules/example/src/smithy4s/example/Podcast.scala b/modules/example/src/smithy4s/example/Podcast.scala index 42577ae83..4bad5fba8 100644 --- a/modules/example/src/smithy4s/example/Podcast.scala +++ b/modules/example/src/smithy4s/example/Podcast.scala @@ -58,4 +58,4 @@ object Podcast extends ShapeTag.Companion[Podcast] { case c: Video => Video.alt(c) case c: Audio => Audio.alt(c) }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/PodcastCommon.scala b/modules/example/src/smithy4s/example/PodcastCommon.scala index 5d6b5e26b..87846c863 100644 --- a/modules/example/src/smithy4s/example/PodcastCommon.scala +++ b/modules/example/src/smithy4s/example/PodcastCommon.scala @@ -5,4 +5,4 @@ trait PodcastCommon { def title: Option[String] def url: Option[String] def durationMillis: Option[Long] -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/PutObjectInput.scala b/modules/example/src/smithy4s/example/PutObjectInput.scala index 8cfdfefc1..65a1e325d 100644 --- a/modules/example/src/smithy4s/example/PutObjectInput.scala +++ b/modules/example/src/smithy4s/example/PutObjectInput.scala @@ -25,4 +25,4 @@ object PutObjectInput extends ShapeTag.Companion[PutObjectInput] { ){ PutObjectInput.apply }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/PutStreamedObjectInput.scala b/modules/example/src/smithy4s/example/PutStreamedObjectInput.scala index 40773af07..afbbcfcd9 100644 --- a/modules/example/src/smithy4s/example/PutStreamedObjectInput.scala +++ b/modules/example/src/smithy4s/example/PutStreamedObjectInput.scala @@ -18,4 +18,4 @@ object PutStreamedObjectInput extends ShapeTag.Companion[PutStreamedObjectInput] ){ PutStreamedObjectInput.apply }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/ServerError.scala b/modules/example/src/smithy4s/example/ServerError.scala index 16d9c934f..aea681702 100644 --- a/modules/example/src/smithy4s/example/ServerError.scala +++ b/modules/example/src/smithy4s/example/ServerError.scala @@ -22,4 +22,4 @@ object ServerError extends ShapeTag.Companion[ServerError] { ){ ServerError.apply }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/ServerErrorCustomMessage.scala b/modules/example/src/smithy4s/example/ServerErrorCustomMessage.scala index e7d921fae..f938be750 100644 --- a/modules/example/src/smithy4s/example/ServerErrorCustomMessage.scala +++ b/modules/example/src/smithy4s/example/ServerErrorCustomMessage.scala @@ -22,4 +22,4 @@ object ServerErrorCustomMessage extends ShapeTag.Companion[ServerErrorCustomMess ){ ServerErrorCustomMessage.apply }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/SomeIndexSeq.scala b/modules/example/src/smithy4s/example/SomeIndexSeq.scala index eefbd9d5b..f9ee5a74d 100644 --- a/modules/example/src/smithy4s/example/SomeIndexSeq.scala +++ b/modules/example/src/smithy4s/example/SomeIndexSeq.scala @@ -13,4 +13,4 @@ object SomeIndexSeq extends Newtype[IndexedSeq[String]] { val hints: Hints = Hints.empty val underlyingSchema: Schema[IndexedSeq[String]] = indexedSeq(string).withId(id).addHints(hints) implicit val schema: Schema[SomeIndexSeq] = bijection(underlyingSchema, asBijection) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/SomeValue.scala b/modules/example/src/smithy4s/example/SomeValue.scala index de22a0bf4..aca68e01a 100644 --- a/modules/example/src/smithy4s/example/SomeValue.scala +++ b/modules/example/src/smithy4s/example/SomeValue.scala @@ -12,4 +12,4 @@ object SomeValue extends Newtype[String] { val hints: Hints = Hints.empty val underlyingSchema: Schema[String] = string.withId(id).addHints(hints) implicit val schema: Schema[SomeValue] = bijection(underlyingSchema, asBijection) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/SomeVector.scala b/modules/example/src/smithy4s/example/SomeVector.scala index 1f456f53a..52ab427fb 100644 --- a/modules/example/src/smithy4s/example/SomeVector.scala +++ b/modules/example/src/smithy4s/example/SomeVector.scala @@ -13,4 +13,4 @@ object SomeVector extends Newtype[Vector[String]] { val hints: Hints = Hints.empty val underlyingSchema: Schema[Vector[String]] = vector(string).withId(id).addHints(hints) implicit val schema: Schema[SomeVector] = bijection(underlyingSchema, asBijection) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/StreamedBlob.scala b/modules/example/src/smithy4s/example/StreamedBlob.scala index 109d04e83..292eead7a 100644 --- a/modules/example/src/smithy4s/example/StreamedBlob.scala +++ b/modules/example/src/smithy4s/example/StreamedBlob.scala @@ -14,4 +14,4 @@ object StreamedBlob extends Newtype[Byte] { ) val underlyingSchema: Schema[Byte] = byte.withId(id).addHints(hints) implicit val schema: Schema[StreamedBlob] = bijection(underlyingSchema, asBijection) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/StreamedObjects.scala b/modules/example/src/smithy4s/example/StreamedObjects.scala index 1d1a2f9cb..08dec01f5 100644 --- a/modules/example/src/smithy4s/example/StreamedObjects.scala +++ b/modules/example/src/smithy4s/example/StreamedObjects.scala @@ -95,3 +95,4 @@ object StreamedObjectsOperation { def wrap(input: GetStreamedObjectInput) = GetStreamedObject(input) } } + diff --git a/modules/example/src/smithy4s/example/StringList.scala b/modules/example/src/smithy4s/example/StringList.scala index a1ea25fc0..001a99391 100644 --- a/modules/example/src/smithy4s/example/StringList.scala +++ b/modules/example/src/smithy4s/example/StringList.scala @@ -13,4 +13,4 @@ object StringList extends Newtype[List[String]] { val hints: Hints = Hints.empty val underlyingSchema: Schema[List[String]] = list(string).withId(id).addHints(hints) implicit val schema: Schema[StringList] = bijection(underlyingSchema, asBijection) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/Strings.scala b/modules/example/src/smithy4s/example/Strings.scala index b64160600..0651c5fed 100644 --- a/modules/example/src/smithy4s/example/Strings.scala +++ b/modules/example/src/smithy4s/example/Strings.scala @@ -16,4 +16,4 @@ object Strings extends Newtype[List[String]] { ) val underlyingSchema: Schema[List[String]] = list(string).withId(id).addHints(hints) implicit val schema: Schema[Strings] = bijection(underlyingSchema, asBijection) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/StructureWithRefinedMember.scala b/modules/example/src/smithy4s/example/StructureWithRefinedMember.scala index d249fe64f..e80a370f1 100644 --- a/modules/example/src/smithy4s/example/StructureWithRefinedMember.scala +++ b/modules/example/src/smithy4s/example/StructureWithRefinedMember.scala @@ -19,4 +19,4 @@ object StructureWithRefinedMember extends ShapeTag.Companion[StructureWithRefine ){ StructureWithRefinedMember.apply }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/StructureWithRefinedTypes.scala b/modules/example/src/smithy4s/example/StructureWithRefinedTypes.scala index 10a827acb..48d8ada46 100644 --- a/modules/example/src/smithy4s/example/StructureWithRefinedTypes.scala +++ b/modules/example/src/smithy4s/example/StructureWithRefinedTypes.scala @@ -23,4 +23,4 @@ object StructureWithRefinedTypes extends ShapeTag.Companion[StructureWithRefined ){ StructureWithRefinedTypes.apply }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/SwitchState.scala b/modules/example/src/smithy4s/example/SwitchState.scala index db805450e..a8496cdb3 100644 --- a/modules/example/src/smithy4s/example/SwitchState.scala +++ b/modules/example/src/smithy4s/example/SwitchState.scala @@ -29,4 +29,4 @@ object SwitchState extends Enumeration[SwitchState] with ShapeTag.Companion[Swit OFF, ) implicit val schema: Schema[SwitchState] = enumeration(values).withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/TestAdt.scala b/modules/example/src/smithy4s/example/TestAdt.scala index d2cf7ac72..cc4702ee2 100644 --- a/modules/example/src/smithy4s/example/TestAdt.scala +++ b/modules/example/src/smithy4s/example/TestAdt.scala @@ -63,4 +63,4 @@ object TestAdt extends ShapeTag.Companion[TestAdt] { case c: AdtOne => AdtOne.alt(c) case c: AdtTwo => AdtTwo.alt(c) }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/TestEmptyMixin.scala b/modules/example/src/smithy4s/example/TestEmptyMixin.scala index 5ef661733..5d7d3cbbb 100644 --- a/modules/example/src/smithy4s/example/TestEmptyMixin.scala +++ b/modules/example/src/smithy4s/example/TestEmptyMixin.scala @@ -18,4 +18,4 @@ object TestEmptyMixin extends ShapeTag.Companion[TestEmptyMixin] { ){ TestEmptyMixin.apply }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/TestMixinAdt.scala b/modules/example/src/smithy4s/example/TestMixinAdt.scala index 30e2bb76f..1a009afd3 100644 --- a/modules/example/src/smithy4s/example/TestMixinAdt.scala +++ b/modules/example/src/smithy4s/example/TestMixinAdt.scala @@ -39,4 +39,4 @@ object TestMixinAdt extends ShapeTag.Companion[TestMixinAdt] { ){ case c: TestAdtMemberWithMixin => TestAdtMemberWithMixin.alt(c) }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/TestString.scala b/modules/example/src/smithy4s/example/TestString.scala index 4a3c77566..b8ae88840 100644 --- a/modules/example/src/smithy4s/example/TestString.scala +++ b/modules/example/src/smithy4s/example/TestString.scala @@ -14,4 +14,4 @@ object TestString extends Newtype[String] { ) val underlyingSchema: Schema[String] = string.withId(id).addHints(hints) implicit val schema: Schema[TestString] = bijection(underlyingSchema, asBijection) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/TestTrait.scala b/modules/example/src/smithy4s/example/TestTrait.scala index b998459db..baec878d8 100644 --- a/modules/example/src/smithy4s/example/TestTrait.scala +++ b/modules/example/src/smithy4s/example/TestTrait.scala @@ -24,4 +24,4 @@ object TestTrait extends ShapeTag.Companion[TestTrait] { ){ TestTrait.apply }.withId(id).addHints(hints)) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/UnionWithRefinedTypes.scala b/modules/example/src/smithy4s/example/UnionWithRefinedTypes.scala index 3f0eab23b..10e13a48e 100644 --- a/modules/example/src/smithy4s/example/UnionWithRefinedTypes.scala +++ b/modules/example/src/smithy4s/example/UnionWithRefinedTypes.scala @@ -36,4 +36,4 @@ object UnionWithRefinedTypes extends ShapeTag.Companion[UnionWithRefinedTypes] { case c: AgeCase => AgeCase.alt(c) case c: DogNameCase => DogNameCase.alt(c) }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/UnwrappedFancyList.scala b/modules/example/src/smithy4s/example/UnwrappedFancyList.scala index 4693e952a..340a8344b 100644 --- a/modules/example/src/smithy4s/example/UnwrappedFancyList.scala +++ b/modules/example/src/smithy4s/example/UnwrappedFancyList.scala @@ -13,4 +13,4 @@ object UnwrappedFancyList extends Newtype[smithy4s.example.refined.FancyList] { val hints: Hints = Hints.empty val underlyingSchema: Schema[smithy4s.example.refined.FancyList] = list(string).refined[smithy4s.example.refined.FancyList](smithy4s.example.FancyListFormat()).withId(id).addHints(hints) implicit val schema: Schema[UnwrappedFancyList] = bijection(underlyingSchema, asBijection) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/collision/ListInput.scala b/modules/example/src/smithy4s/example/collision/ListInput.scala index faba8ae03..16603fc46 100644 --- a/modules/example/src/smithy4s/example/collision/ListInput.scala +++ b/modules/example/src/smithy4s/example/collision/ListInput.scala @@ -19,4 +19,4 @@ object ListInput extends ShapeTag.Companion[ListInput] { ){ ListInput.apply }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/collision/MapInput.scala b/modules/example/src/smithy4s/example/collision/MapInput.scala index 0d49e7f7b..e62d4af20 100644 --- a/modules/example/src/smithy4s/example/collision/MapInput.scala +++ b/modules/example/src/smithy4s/example/collision/MapInput.scala @@ -19,4 +19,4 @@ object MapInput extends ShapeTag.Companion[MapInput] { ){ MapInput.apply }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/collision/MyList.scala b/modules/example/src/smithy4s/example/collision/MyList.scala index e10f48249..1322faf9b 100644 --- a/modules/example/src/smithy4s/example/collision/MyList.scala +++ b/modules/example/src/smithy4s/example/collision/MyList.scala @@ -13,4 +13,4 @@ object MyList extends Newtype[List[String]] { val hints: Hints = Hints.empty val underlyingSchema: Schema[List[String]] = list(string).withId(id).addHints(hints) implicit val schema: Schema[MyList] = bijection(underlyingSchema, asBijection) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/collision/MyMap.scala b/modules/example/src/smithy4s/example/collision/MyMap.scala index e0116c6d2..bd9879b5e 100644 --- a/modules/example/src/smithy4s/example/collision/MyMap.scala +++ b/modules/example/src/smithy4s/example/collision/MyMap.scala @@ -13,4 +13,4 @@ object MyMap extends Newtype[Map[String, String]] { val hints: Hints = Hints.empty val underlyingSchema: Schema[Map[String, String]] = map(string, string).withId(id).addHints(hints) implicit val schema: Schema[MyMap] = bijection(underlyingSchema, asBijection) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/collision/MySet.scala b/modules/example/src/smithy4s/example/collision/MySet.scala index a09dbb90a..cfed3e3f9 100644 --- a/modules/example/src/smithy4s/example/collision/MySet.scala +++ b/modules/example/src/smithy4s/example/collision/MySet.scala @@ -15,4 +15,4 @@ object MySet extends Newtype[Set[String]] { ) val underlyingSchema: Schema[Set[String]] = set(string).withId(id).addHints(hints) implicit val schema: Schema[MySet] = bijection(underlyingSchema, asBijection) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/collision/OptionInput.scala b/modules/example/src/smithy4s/example/collision/OptionInput.scala index 9745411f4..3881ecc2e 100644 --- a/modules/example/src/smithy4s/example/collision/OptionInput.scala +++ b/modules/example/src/smithy4s/example/collision/OptionInput.scala @@ -20,4 +20,4 @@ object OptionInput extends ShapeTag.Companion[OptionInput] { ){ OptionInput.apply }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/collision/ReservedNameService.scala b/modules/example/src/smithy4s/example/collision/ReservedNameService.scala index 267f428ac..ea462f492 100644 --- a/modules/example/src/smithy4s/example/collision/ReservedNameService.scala +++ b/modules/example/src/smithy4s/example/collision/ReservedNameService.scala @@ -139,3 +139,4 @@ object ReservedNameServiceOperation { def wrap(input: OptionInput) = _Option(input) } } + diff --git a/modules/example/src/smithy4s/example/collision/SetInput.scala b/modules/example/src/smithy4s/example/collision/SetInput.scala index 598d78dbd..5d433e525 100644 --- a/modules/example/src/smithy4s/example/collision/SetInput.scala +++ b/modules/example/src/smithy4s/example/collision/SetInput.scala @@ -19,4 +19,4 @@ object SetInput extends ShapeTag.Companion[SetInput] { ){ SetInput.apply }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/common/BrandList.scala b/modules/example/src/smithy4s/example/common/BrandList.scala index 403b049d2..596379cf4 100644 --- a/modules/example/src/smithy4s/example/common/BrandList.scala +++ b/modules/example/src/smithy4s/example/common/BrandList.scala @@ -13,4 +13,4 @@ object BrandList extends Newtype[List[String]] { val hints: Hints = Hints.empty val underlyingSchema: Schema[List[String]] = list(string).withId(id).addHints(hints) implicit val schema: Schema[BrandList] = bijection(underlyingSchema, asBijection) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/error/NotFoundError.scala b/modules/example/src/smithy4s/example/error/NotFoundError.scala index 14c1d4331..44090013c 100644 --- a/modules/example/src/smithy4s/example/error/NotFoundError.scala +++ b/modules/example/src/smithy4s/example/error/NotFoundError.scala @@ -22,4 +22,4 @@ object NotFoundError extends ShapeTag.Companion[NotFoundError] { ){ NotFoundError.apply }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/imp/ImportService.scala b/modules/example/src/smithy4s/example/imp/ImportService.scala index 317e5c728..b7f835587 100644 --- a/modules/example/src/smithy4s/example/imp/ImportService.scala +++ b/modules/example/src/smithy4s/example/imp/ImportService.scala @@ -122,3 +122,4 @@ object ImportServiceOperation { } } } + diff --git a/modules/example/src/smithy4s/example/import_test/OpOutput.scala b/modules/example/src/smithy4s/example/import_test/OpOutput.scala index eefd5edba..4c0552a52 100644 --- a/modules/example/src/smithy4s/example/import_test/OpOutput.scala +++ b/modules/example/src/smithy4s/example/import_test/OpOutput.scala @@ -18,4 +18,4 @@ object OpOutput extends ShapeTag.Companion[OpOutput] { ){ OpOutput.apply }.withId(id).addHints(hints) -} \ No newline at end of file +} diff --git a/modules/example/src/smithy4s/example/package.scala b/modules/example/src/smithy4s/example/package.scala index 20cc35dc6..79bc4f63c 100644 --- a/modules/example/src/smithy4s/example/package.scala +++ b/modules/example/src/smithy4s/example/package.scala @@ -32,6 +32,7 @@ package object example { type ArbitraryData = smithy4s.example.ArbitraryData.Type type DogName = smithy4s.example.DogName.Type type SomeVector = smithy4s.example.SomeVector.Type + type PersonPhoneNumber = smithy4s.example.PersonPhoneNumber.Type type FancyList = smithy4s.example.FancyList.Type type DefaultStringMap = smithy4s.example.DefaultStringMap.Type @deprecated @@ -40,6 +41,7 @@ package object example { @deprecated type DeprecatedString = smithy4s.example.DeprecatedString.Type type ObjectSize = smithy4s.example.ObjectSize.Type + type PersonEmail = smithy4s.example.PersonEmail.Type type NonEmptyCandies = smithy4s.example.NonEmptyCandies.Type type SomeIndexSeq = smithy4s.example.SomeIndexSeq.Type type StringList = smithy4s.example.StringList.Type diff --git a/modules/protocol/resources/META-INF/services/software.amazon.smithy.model.traits.TraitService b/modules/protocol/resources/META-INF/services/software.amazon.smithy.model.traits.TraitService index dc3a1bea5..a99588cc9 100644 --- a/modules/protocol/resources/META-INF/services/software.amazon.smithy.model.traits.TraitService +++ b/modules/protocol/resources/META-INF/services/software.amazon.smithy.model.traits.TraitService @@ -6,3 +6,4 @@ smithy4s.meta.ErrorMessageTrait$Provider smithy4s.meta.RefinementTrait$Provider smithy4s.meta.UnwrapTrait$Provider smithy4s.meta.AdtTrait$Provider +smithy4s.meta.TypeclassTrait$Provider diff --git a/modules/protocol/resources/META-INF/smithy/smithy4s.meta.smithy b/modules/protocol/resources/META-INF/smithy/smithy4s.meta.smithy index 493a3ccb1..e189628fb 100644 --- a/modules/protocol/resources/META-INF/smithy/smithy4s.meta.smithy +++ b/modules/protocol/resources/META-INF/smithy/smithy4s.meta.smithy @@ -117,3 +117,30 @@ string Import /// by default. Adding this trait will cause the collection to become unwrapped. @trait(selector: ":is(simpleType, list, map, set)") structure unwrap {} + +/// Placing this trait on another trait marks the target trait as a +/// typeclass. This means that shapes which are marked with the target +/// trait will have an instance of the typeclass made available in the +/// generated object companion. +/// +/// For example, +/// +/// @typeclass(targetType: "cats.Show", interpreter: "my.show.Interpreter") +/// @trait +/// structure show {} +/// +/// @show +/// structure Person { +/// name: String +/// } +/// +/// This example would lead to generated code where the Person +/// case class has a `cats.Show` instance available in its companion +/// object. +@trait(selector: "* [trait|trait]") +structure typeclass { + @required + targetType: Classpath, + @required + interpreter: Classpath +} diff --git a/modules/protocol/src/smithy4s/meta/TypeclassTrait.java b/modules/protocol/src/smithy4s/meta/TypeclassTrait.java new file mode 100644 index 000000000..3c4737d27 --- /dev/null +++ b/modules/protocol/src/smithy4s/meta/TypeclassTrait.java @@ -0,0 +1,117 @@ +/* + * Copyright 2021-2022 Disney Streaming + * + * Licensed under the Tomorrow Open Source Technology License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://disneystreaming.github.io/TOST-1.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package smithy4s.meta; + +import software.amazon.smithy.model.SourceException; +import software.amazon.smithy.model.node.Node; +import software.amazon.smithy.model.node.ObjectNode; +import software.amazon.smithy.model.shapes.ShapeId; +import software.amazon.smithy.model.traits.AbstractTrait; +import software.amazon.smithy.model.traits.AbstractTraitBuilder; +import software.amazon.smithy.model.traits.TraitService; +import software.amazon.smithy.utils.SmithyBuilder; +import software.amazon.smithy.utils.ToSmithyBuilder; +import java.util.Optional; + +public final class TypeclassTrait extends AbstractTrait implements ToSmithyBuilder { + + public static final ShapeId ID = ShapeId.from("smithy4s.meta#typeclass"); + + private final String targetType; + private final String interpreter; + + private TypeclassTrait(TypeclassTrait.Builder builder) { + super(ID, builder.getSourceLocation()); + this.targetType = builder.targetType; + this.interpreter = builder.interpreter; + + if (targetType == null) { + throw new SourceException("A targetType must be provided.", getSourceLocation()); + } + + if (interpreter == null) { + throw new SourceException("An interpreter must be provided.", getSourceLocation()); + } + } + + public String getTargetType() { + return this.targetType; + } + + public String getInterpreter() { + return this.interpreter; + } + + @Override + protected Node createNode() { + ObjectNode.Builder builder = Node.objectNodeBuilder(); + builder.withMember("targetType", getTargetType()); + builder.withMember("interpreter", getInterpreter()); + return builder.build(); + } + + @Override + public SmithyBuilder toBuilder() { + return builder().targetType(targetType).interpreter(interpreter).sourceLocation(getSourceLocation()); + } + + /** + * @return Returns a new TypeclassTrait builder. + */ + public static TypeclassTrait.Builder builder() { + return new Builder(); + } + + public static final class Builder extends AbstractTraitBuilder { + + private String targetType; + private String interpreter; + + public TypeclassTrait.Builder targetType(String targetType) { + this.targetType = targetType; + return this; + } + + public TypeclassTrait.Builder interpreter(String interpreter) { + this.interpreter = interpreter; + return this; + } + + @Override + public TypeclassTrait build() { + return new TypeclassTrait(this); + } + } + + public static final class Provider implements TraitService { + + @Override + public ShapeId getShapeId() { + return ID; + } + + @Override + public TypeclassTrait createTrait(ShapeId target, Node value) { + ObjectNode objectNode = value.expectObjectNode(); + String targetType = objectNode.getMember("targetType").map(node -> node.expectStringNode().getValue()) + .orElse(null); + String interpreter = objectNode.getMember("interpreter").map(node -> node.expectStringNode().getValue()) + .orElse(null); + return builder().sourceLocation(value).targetType(targetType).interpreter(interpreter).build(); + } + } +} diff --git a/project/build.properties b/project/build.properties new file mode 100644 index 000000000..46e43a97e --- /dev/null +++ b/project/build.properties @@ -0,0 +1 @@ +sbt.version=1.8.2 diff --git a/sampleSpecs/typeclass.smithy b/sampleSpecs/typeclass.smithy new file mode 100644 index 000000000..6a9991cb2 --- /dev/null +++ b/sampleSpecs/typeclass.smithy @@ -0,0 +1,39 @@ +$version: "2" + +namespace smithy4s.example + +use smithy4s.meta#typeclass + +// NOTE: normally you would likely not need to add instances of hash or other typeclasses +// to all of your types. Here I am doing it just to test different rendering cases. +// In reality, you don't need an `hash` instance for the members of a struct in order +// to have an `hash` instance for the struct itself. This is because the interpreter provided +// will use the schema to derive the instance rather than delegating to the instances on +// the target types of the members directly. + +@trait +@typeclass(targetType: "cats.Hash", interpreter: "smithy4s.interopcats.SchemaVisitorHash") +structure hash {} + +@hash +structure MovieTheater { + name: String +} + +@hash +union PersonContactInfo { + email: PersonEmail + phone: PersonPhoneNumber +} + +@hash +enum NetworkConnectionType { + ETHERNET + WIFI +} + +@hash +string PersonEmail + +@hash +string PersonPhoneNumber