From f636f36affb5070cae0a6b9c9d15259a5d2ec66e Mon Sep 17 00:00:00 2001 From: Jeff Lewis Date: Thu, 10 Aug 2023 16:19:36 -0600 Subject: [PATCH 1/3] Add Projections and Visitors to Unions --- CHANGELOG.md | 6 + .../com/amazonaws/dynamodb/DynamoDB.scala | 29 ++- .../smithy4s/example/CheckedOrUnchecked.scala | 29 ++- .../example/CheckedOrUnchecked2.scala | 29 ++- .../smithy4s/example/DeprecatedUnion.scala | 39 ++++- .../example/ErrorHandlingService.scala | 47 +++-- .../ErrorHandlingServiceExtraErrors.scala | 47 +++-- .../src/generated/smithy4s/example/Foo.scala | 47 +++-- .../src/generated/smithy4s/example/Food.scala | 29 ++- .../smithy4s/example/ForecastResult.scala | 33 +++- .../generated/smithy4s/example/KVStore.scala | 78 +++++++-- .../smithy4s/example/NameCollision.scala | 20 ++- .../smithy4s/example/ObjectService.scala | 49 ++++-- .../smithy4s/example/OpticsUnion.scala | 22 ++- .../smithy4s/example/OrderType.scala | 33 +++- .../smithy4s/example/PersonContactInfo.scala | 33 +++- .../smithy4s/example/PizzaAdminService.scala | 165 +++++++++++++----- .../generated/smithy4s/example/Podcast.scala | 21 ++- .../generated/smithy4s/example/TestAdt.scala | 21 ++- .../smithy4s/example/TestBiggerUnion.scala | 29 ++- .../smithy4s/example/TestIdRefUnion.scala | 29 ++- .../smithy4s/example/TestMixinAdt.scala | 16 +- .../example/UnionWithRefinedTypes.scala | 29 ++- .../smithy4s/example/UntaggedUnion.scala | 29 ++- .../generated/smithy4s/example/Weather.scala | 20 ++- .../guides/auth/HelloWorldAuthService.scala | 40 ++++- .../example/hello/HelloWorldService.scala | 29 ++- .../smithy4s/example/imp/ImportService.scala | 20 ++- .../smithy4s/example/test/HelloService.scala | 29 ++- .../smithy4s/VisitorAndProjectionSpec.scala | 56 ++++++ .../codegen/internals/LineSegment.scala | 8 + .../codegen/internals/PartialBlock.scala | 7 +- .../smithy4s/codegen/internals/Renderer.scala | 111 +++++++++--- modules/docs/markdown/04-codegen/02-unions.md | 64 +++++++ 34 files changed, 1027 insertions(+), 266 deletions(-) create mode 100644 modules/bootstrapped/test/src/smithy4s/VisitorAndProjectionSpec.scala diff --git a/CHANGELOG.md b/CHANGELOG.md index 726b5287e..17e4bb681 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,12 @@ Introduces alternative code generation for enums and intEnums when they are mark See https://github.com/disneystreaming/smithy4s/pull/1137 +### Union Projections and Visitors + +Added convenient methods for working with unions including projectors for each union alternative and a visitor in union companion objects that can be passed to each union's new `accept` method. + +See https://github.com/disneystreaming/smithy4s/pull/1144 + # 0.17.14 * Only transform AWS shapes named after standard shapes in [#1127](https://github.com/disneystreaming/smithy4s/pull/1127) diff --git a/modules/bootstrapped/src/generated/com/amazonaws/dynamodb/DynamoDB.scala b/modules/bootstrapped/src/generated/com/amazonaws/dynamodb/DynamoDB.scala index 5a502ff38..61a638f34 100644 --- a/modules/bootstrapped/src/generated/com/amazonaws/dynamodb/DynamoDB.scala +++ b/modules/bootstrapped/src/generated/com/amazonaws/dynamodb/DynamoDB.scala @@ -162,14 +162,24 @@ object DynamoDBOperation { case ListTablesError.InvalidEndpointExceptionCase(e) => e } } - sealed trait ListTablesError extends scala.Product with scala.Serializable { + sealed trait ListTablesError extends scala.Product with scala.Serializable { self => @inline final def widen: ListTablesError = this def $ordinal: Int + + object project { + def internalServerError: Option[InternalServerError] = ListTablesError.InternalServerErrorCase.alt.project.lift(self).map(_.internalServerError) + def invalidEndpointException: Option[InvalidEndpointException] = ListTablesError.InvalidEndpointExceptionCase.alt.project.lift(self).map(_.invalidEndpointException) + } + + def accept[A](visitor: ListTablesError.Visitor[A]): A = this match { + case value: ListTablesError.InternalServerErrorCase => visitor.internalServerError(value.internalServerError) + case value: ListTablesError.InvalidEndpointExceptionCase => visitor.invalidEndpointException(value.invalidEndpointException) + } } object ListTablesError extends ShapeTag.Companion[ListTablesError] { - def internalServerError(internalServerError:InternalServerError): ListTablesError = InternalServerErrorCase(internalServerError) - def invalidEndpointException(invalidEndpointException:InvalidEndpointException): ListTablesError = InvalidEndpointExceptionCase(invalidEndpointException) + def internalServerError(internalServerError: InternalServerError): ListTablesError = InternalServerErrorCase(internalServerError) + def invalidEndpointException(invalidEndpointException: InvalidEndpointException): ListTablesError = InvalidEndpointExceptionCase(invalidEndpointException) val id: ShapeId = ShapeId("com.amazonaws.dynamodb", "ListTablesError") @@ -180,18 +190,23 @@ object DynamoDBOperation { object InternalServerErrorCase { val hints: Hints = Hints.empty - val schema: Schema[InternalServerErrorCase] = bijection(InternalServerError.schema.addHints(hints), InternalServerErrorCase(_), _.internalServerError) + val schema: Schema[ListTablesError.InternalServerErrorCase] = bijection(InternalServerError.schema.addHints(hints), ListTablesError.InternalServerErrorCase(_), _.internalServerError) val alt = schema.oneOf[ListTablesError]("InternalServerError") } object InvalidEndpointExceptionCase { val hints: Hints = Hints.empty - val schema: Schema[InvalidEndpointExceptionCase] = bijection(InvalidEndpointException.schema.addHints(hints), InvalidEndpointExceptionCase(_), _.invalidEndpointException) + val schema: Schema[ListTablesError.InvalidEndpointExceptionCase] = bijection(InvalidEndpointException.schema.addHints(hints), ListTablesError.InvalidEndpointExceptionCase(_), _.invalidEndpointException) val alt = schema.oneOf[ListTablesError]("InvalidEndpointException") } + trait Visitor[A] { + def internalServerError(value: InternalServerError): A + def invalidEndpointException(value: InvalidEndpointException): A + } + implicit val schema: UnionSchema[ListTablesError] = union( - InternalServerErrorCase.alt, - InvalidEndpointExceptionCase.alt, + ListTablesError.InternalServerErrorCase.alt, + ListTablesError.InvalidEndpointExceptionCase.alt, ){ _.$ordinal } diff --git a/modules/bootstrapped/src/generated/smithy4s/example/CheckedOrUnchecked.scala b/modules/bootstrapped/src/generated/smithy4s/example/CheckedOrUnchecked.scala index 4c3391d02..a0922ec51 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/CheckedOrUnchecked.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/CheckedOrUnchecked.scala @@ -8,14 +8,24 @@ import smithy4s.schema.Schema.bijection import smithy4s.schema.Schema.string import smithy4s.schema.Schema.union -sealed trait CheckedOrUnchecked extends scala.Product with scala.Serializable { +sealed trait CheckedOrUnchecked extends scala.Product with scala.Serializable { self => @inline final def widen: CheckedOrUnchecked = this def $ordinal: Int + + object project { + def checked: Option[String] = CheckedOrUnchecked.CheckedCase.alt.project.lift(self).map(_.checked) + def raw: Option[String] = CheckedOrUnchecked.RawCase.alt.project.lift(self).map(_.raw) + } + + def accept[A](visitor: CheckedOrUnchecked.Visitor[A]): A = this match { + case value: CheckedOrUnchecked.CheckedCase => visitor.checked(value.checked) + case value: CheckedOrUnchecked.RawCase => visitor.raw(value.raw) + } } object CheckedOrUnchecked extends ShapeTag.Companion[CheckedOrUnchecked] { - def checked(checked:String): CheckedOrUnchecked = CheckedCase(checked) - def raw(raw:String): CheckedOrUnchecked = RawCase(raw) + def checked(checked: String): CheckedOrUnchecked = CheckedCase(checked) + def raw(raw: String): CheckedOrUnchecked = RawCase(raw) val id: ShapeId = ShapeId("smithy4s.example", "CheckedOrUnchecked") @@ -26,18 +36,23 @@ object CheckedOrUnchecked extends ShapeTag.Companion[CheckedOrUnchecked] { object CheckedCase { val hints: Hints = Hints.empty - val schema: Schema[CheckedCase] = bijection(string.addHints(hints).validated(smithy.api.Pattern(s"^\\w+$$")), CheckedCase(_), _.checked) + val schema: Schema[CheckedOrUnchecked.CheckedCase] = bijection(string.addHints(hints).validated(smithy.api.Pattern(s"^\\w+$$")), CheckedOrUnchecked.CheckedCase(_), _.checked) val alt = schema.oneOf[CheckedOrUnchecked]("checked") } object RawCase { val hints: Hints = Hints.empty - val schema: Schema[RawCase] = bijection(string.addHints(hints), RawCase(_), _.raw) + val schema: Schema[CheckedOrUnchecked.RawCase] = bijection(string.addHints(hints), CheckedOrUnchecked.RawCase(_), _.raw) val alt = schema.oneOf[CheckedOrUnchecked]("raw") } + trait Visitor[A] { + def checked(value: String): A + def raw(value: String): A + } + implicit val schema: Schema[CheckedOrUnchecked] = union( - CheckedCase.alt, - RawCase.alt, + CheckedOrUnchecked.CheckedCase.alt, + CheckedOrUnchecked.RawCase.alt, ){ _.$ordinal }.withId(id).addHints(hints) diff --git a/modules/bootstrapped/src/generated/smithy4s/example/CheckedOrUnchecked2.scala b/modules/bootstrapped/src/generated/smithy4s/example/CheckedOrUnchecked2.scala index af5f8f669..f32a4cf69 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/CheckedOrUnchecked2.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/CheckedOrUnchecked2.scala @@ -8,14 +8,24 @@ import smithy4s.schema.Schema.bijection import smithy4s.schema.Schema.string import smithy4s.schema.Schema.union -sealed trait CheckedOrUnchecked2 extends scala.Product with scala.Serializable { +sealed trait CheckedOrUnchecked2 extends scala.Product with scala.Serializable { self => @inline final def widen: CheckedOrUnchecked2 = this def $ordinal: Int + + object project { + def checked: Option[String] = CheckedOrUnchecked2.CheckedCase.alt.project.lift(self).map(_.checked) + def raw: Option[String] = CheckedOrUnchecked2.RawCase.alt.project.lift(self).map(_.raw) + } + + def accept[A](visitor: CheckedOrUnchecked2.Visitor[A]): A = this match { + case value: CheckedOrUnchecked2.CheckedCase => visitor.checked(value.checked) + case value: CheckedOrUnchecked2.RawCase => visitor.raw(value.raw) + } } object CheckedOrUnchecked2 extends ShapeTag.Companion[CheckedOrUnchecked2] { - def checked(checked:String): CheckedOrUnchecked2 = CheckedCase(checked) - def raw(raw:String): CheckedOrUnchecked2 = RawCase(raw) + def checked(checked: String): CheckedOrUnchecked2 = CheckedCase(checked) + def raw(raw: String): CheckedOrUnchecked2 = RawCase(raw) val id: ShapeId = ShapeId("smithy4s.example", "CheckedOrUnchecked2") @@ -28,18 +38,23 @@ object CheckedOrUnchecked2 extends ShapeTag.Companion[CheckedOrUnchecked2] { object CheckedCase { val hints: Hints = Hints.empty - val schema: Schema[CheckedCase] = bijection(string.addHints(hints).validated(smithy.api.Pattern(s"^\\w+$$")), CheckedCase(_), _.checked) + val schema: Schema[CheckedOrUnchecked2.CheckedCase] = bijection(string.addHints(hints).validated(smithy.api.Pattern(s"^\\w+$$")), CheckedOrUnchecked2.CheckedCase(_), _.checked) val alt = schema.oneOf[CheckedOrUnchecked2]("checked") } object RawCase { val hints: Hints = Hints.empty - val schema: Schema[RawCase] = bijection(string.addHints(hints), RawCase(_), _.raw) + val schema: Schema[CheckedOrUnchecked2.RawCase] = bijection(string.addHints(hints), CheckedOrUnchecked2.RawCase(_), _.raw) val alt = schema.oneOf[CheckedOrUnchecked2]("raw") } + trait Visitor[A] { + def checked(value: String): A + def raw(value: String): A + } + implicit val schema: Schema[CheckedOrUnchecked2] = union( - CheckedCase.alt, - RawCase.alt, + CheckedOrUnchecked2.CheckedCase.alt, + CheckedOrUnchecked2.RawCase.alt, ){ _.$ordinal }.withId(id).addHints(hints) diff --git a/modules/bootstrapped/src/generated/smithy4s/example/DeprecatedUnion.scala b/modules/bootstrapped/src/generated/smithy4s/example/DeprecatedUnion.scala index 32e70dda1..01350e246 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/DeprecatedUnion.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/DeprecatedUnion.scala @@ -10,15 +10,29 @@ import smithy4s.schema.Schema.string import smithy4s.schema.Schema.union @deprecated(message = "A compelling reason", since = "0.0.1") -sealed trait DeprecatedUnion extends scala.Product with scala.Serializable { +sealed trait DeprecatedUnion extends scala.Product with scala.Serializable { self => @inline final def widen: DeprecatedUnion = this def $ordinal: Int + + object project { + def s: Option[String] = DeprecatedUnion.SCase.alt.project.lift(self).map(_.s) + def s_V2: Option[String] = DeprecatedUnion.S_V2Case.alt.project.lift(self).map(_.s_V2) + def p: Option[DeprecatedUnion.DeprecatedUnionProductCase] = DeprecatedUnion.DeprecatedUnionProductCase.alt.project.lift(self) + def p2: Option[DeprecatedUnion.UnionProductCaseDeprecatedAtCallSite] = DeprecatedUnion.UnionProductCaseDeprecatedAtCallSite.alt.project.lift(self) + } + + def accept[A](visitor: DeprecatedUnion.Visitor[A]): A = this match { + case value: DeprecatedUnion.SCase => visitor.s(value.s) + case value: DeprecatedUnion.S_V2Case => visitor.s_V2(value.s_V2) + case value: DeprecatedUnion.DeprecatedUnionProductCase => visitor.p(value) + case value: DeprecatedUnion.UnionProductCaseDeprecatedAtCallSite => visitor.p2(value) + } } object DeprecatedUnion extends ShapeTag.Companion[DeprecatedUnion] { @deprecated(message = "N/A", since = "N/A") - def s(s:String): DeprecatedUnion = SCase(s) - def s_V2(s_V2:String): DeprecatedUnion = S_V2Case(s_V2) + def s(s: String): DeprecatedUnion = SCase(s) + def s_V2(s_V2: String): DeprecatedUnion = S_V2Case(s_V2) def deprecatedUnionProductCase():DeprecatedUnionProductCase = DeprecatedUnionProductCase() @deprecated(message = "N/A", since = "N/A") def unionProductCaseDeprecatedAtCallSite():UnionProductCaseDeprecatedAtCallSite = UnionProductCaseDeprecatedAtCallSite() @@ -67,20 +81,27 @@ object DeprecatedUnion extends ShapeTag.Companion[DeprecatedUnion] { val hints: Hints = Hints( smithy.api.Deprecated(message = None, since = None), ) - val schema: Schema[SCase] = bijection(string.addHints(hints), SCase(_), _.s) + val schema: Schema[DeprecatedUnion.SCase] = bijection(string.addHints(hints), DeprecatedUnion.SCase(_), _.s) val alt = schema.oneOf[DeprecatedUnion]("s") } object S_V2Case { val hints: Hints = Hints.empty - val schema: Schema[S_V2Case] = bijection(string.addHints(hints), S_V2Case(_), _.s_V2) + val schema: Schema[DeprecatedUnion.S_V2Case] = bijection(string.addHints(hints), DeprecatedUnion.S_V2Case(_), _.s_V2) val alt = schema.oneOf[DeprecatedUnion]("s_V2") } + trait Visitor[A] { + def s(value: String): A + def s_V2(value: String): A + def p(value: DeprecatedUnion.DeprecatedUnionProductCase): A + def p2(value: DeprecatedUnion.UnionProductCaseDeprecatedAtCallSite): A + } + implicit val schema: Schema[DeprecatedUnion] = union( - SCase.alt, - S_V2Case.alt, - DeprecatedUnionProductCase.alt, - UnionProductCaseDeprecatedAtCallSite.alt, + DeprecatedUnion.SCase.alt, + DeprecatedUnion.S_V2Case.alt, + DeprecatedUnion.DeprecatedUnionProductCase.alt, + DeprecatedUnion.UnionProductCaseDeprecatedAtCallSite.alt, ){ _.$ordinal }.withId(id).addHints(hints) diff --git a/modules/bootstrapped/src/generated/smithy4s/example/ErrorHandlingService.scala b/modules/bootstrapped/src/generated/smithy4s/example/ErrorHandlingService.scala index f8a80540d..78f33fcb6 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/ErrorHandlingService.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/ErrorHandlingService.scala @@ -103,16 +103,30 @@ object ErrorHandlingServiceOperation { case ErrorHandlingOperationError.EHFallbackServerErrorCase(e) => e } } - sealed trait ErrorHandlingOperationError extends scala.Product with scala.Serializable { + sealed trait ErrorHandlingOperationError extends scala.Product with scala.Serializable { self => @inline final def widen: ErrorHandlingOperationError = this def $ordinal: Int + + object project { + def eHFallbackClientError: Option[EHFallbackClientError] = ErrorHandlingOperationError.EHFallbackClientErrorCase.alt.project.lift(self).map(_.eHFallbackClientError) + def eHServiceUnavailable: Option[EHServiceUnavailable] = ErrorHandlingOperationError.EHServiceUnavailableCase.alt.project.lift(self).map(_.eHServiceUnavailable) + def eHNotFound: Option[EHNotFound] = ErrorHandlingOperationError.EHNotFoundCase.alt.project.lift(self).map(_.eHNotFound) + def eHFallbackServerError: Option[EHFallbackServerError] = ErrorHandlingOperationError.EHFallbackServerErrorCase.alt.project.lift(self).map(_.eHFallbackServerError) + } + + def accept[A](visitor: ErrorHandlingOperationError.Visitor[A]): A = this match { + case value: ErrorHandlingOperationError.EHFallbackClientErrorCase => visitor.eHFallbackClientError(value.eHFallbackClientError) + case value: ErrorHandlingOperationError.EHServiceUnavailableCase => visitor.eHServiceUnavailable(value.eHServiceUnavailable) + case value: ErrorHandlingOperationError.EHNotFoundCase => visitor.eHNotFound(value.eHNotFound) + case value: ErrorHandlingOperationError.EHFallbackServerErrorCase => visitor.eHFallbackServerError(value.eHFallbackServerError) + } } object ErrorHandlingOperationError extends ShapeTag.Companion[ErrorHandlingOperationError] { - def eHFallbackClientError(eHFallbackClientError:EHFallbackClientError): ErrorHandlingOperationError = EHFallbackClientErrorCase(eHFallbackClientError) - def eHServiceUnavailable(eHServiceUnavailable:EHServiceUnavailable): ErrorHandlingOperationError = EHServiceUnavailableCase(eHServiceUnavailable) - def eHNotFound(eHNotFound:EHNotFound): ErrorHandlingOperationError = EHNotFoundCase(eHNotFound) - def eHFallbackServerError(eHFallbackServerError:EHFallbackServerError): ErrorHandlingOperationError = EHFallbackServerErrorCase(eHFallbackServerError) + def eHFallbackClientError(eHFallbackClientError: EHFallbackClientError): ErrorHandlingOperationError = EHFallbackClientErrorCase(eHFallbackClientError) + def eHServiceUnavailable(eHServiceUnavailable: EHServiceUnavailable): ErrorHandlingOperationError = EHServiceUnavailableCase(eHServiceUnavailable) + def eHNotFound(eHNotFound: EHNotFound): ErrorHandlingOperationError = EHNotFoundCase(eHNotFound) + def eHFallbackServerError(eHFallbackServerError: EHFallbackServerError): ErrorHandlingOperationError = EHFallbackServerErrorCase(eHFallbackServerError) val id: ShapeId = ShapeId("smithy4s.example", "ErrorHandlingOperationError") @@ -125,30 +139,37 @@ object ErrorHandlingServiceOperation { object EHFallbackClientErrorCase { val hints: Hints = Hints.empty - val schema: Schema[EHFallbackClientErrorCase] = bijection(EHFallbackClientError.schema.addHints(hints), EHFallbackClientErrorCase(_), _.eHFallbackClientError) + val schema: Schema[ErrorHandlingOperationError.EHFallbackClientErrorCase] = bijection(EHFallbackClientError.schema.addHints(hints), ErrorHandlingOperationError.EHFallbackClientErrorCase(_), _.eHFallbackClientError) val alt = schema.oneOf[ErrorHandlingOperationError]("EHFallbackClientError") } object EHServiceUnavailableCase { val hints: Hints = Hints.empty - val schema: Schema[EHServiceUnavailableCase] = bijection(EHServiceUnavailable.schema.addHints(hints), EHServiceUnavailableCase(_), _.eHServiceUnavailable) + val schema: Schema[ErrorHandlingOperationError.EHServiceUnavailableCase] = bijection(EHServiceUnavailable.schema.addHints(hints), ErrorHandlingOperationError.EHServiceUnavailableCase(_), _.eHServiceUnavailable) val alt = schema.oneOf[ErrorHandlingOperationError]("EHServiceUnavailable") } object EHNotFoundCase { val hints: Hints = Hints.empty - val schema: Schema[EHNotFoundCase] = bijection(EHNotFound.schema.addHints(hints), EHNotFoundCase(_), _.eHNotFound) + val schema: Schema[ErrorHandlingOperationError.EHNotFoundCase] = bijection(EHNotFound.schema.addHints(hints), ErrorHandlingOperationError.EHNotFoundCase(_), _.eHNotFound) val alt = schema.oneOf[ErrorHandlingOperationError]("EHNotFound") } object EHFallbackServerErrorCase { val hints: Hints = Hints.empty - val schema: Schema[EHFallbackServerErrorCase] = bijection(EHFallbackServerError.schema.addHints(hints), EHFallbackServerErrorCase(_), _.eHFallbackServerError) + val schema: Schema[ErrorHandlingOperationError.EHFallbackServerErrorCase] = bijection(EHFallbackServerError.schema.addHints(hints), ErrorHandlingOperationError.EHFallbackServerErrorCase(_), _.eHFallbackServerError) val alt = schema.oneOf[ErrorHandlingOperationError]("EHFallbackServerError") } + trait Visitor[A] { + def eHFallbackClientError(value: EHFallbackClientError): A + def eHServiceUnavailable(value: EHServiceUnavailable): A + def eHNotFound(value: EHNotFound): A + def eHFallbackServerError(value: EHFallbackServerError): A + } + implicit val schema: UnionSchema[ErrorHandlingOperationError] = union( - EHFallbackClientErrorCase.alt, - EHServiceUnavailableCase.alt, - EHNotFoundCase.alt, - EHFallbackServerErrorCase.alt, + ErrorHandlingOperationError.EHFallbackClientErrorCase.alt, + ErrorHandlingOperationError.EHServiceUnavailableCase.alt, + ErrorHandlingOperationError.EHNotFoundCase.alt, + ErrorHandlingOperationError.EHFallbackServerErrorCase.alt, ){ _.$ordinal } diff --git a/modules/bootstrapped/src/generated/smithy4s/example/ErrorHandlingServiceExtraErrors.scala b/modules/bootstrapped/src/generated/smithy4s/example/ErrorHandlingServiceExtraErrors.scala index 70e1643ba..affa50108 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/ErrorHandlingServiceExtraErrors.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/ErrorHandlingServiceExtraErrors.scala @@ -104,16 +104,30 @@ object ErrorHandlingServiceExtraErrorsOperation { case ExtraErrorOperationError.RandomOtherServerErrorWithCodeCase(e) => e } } - sealed trait ExtraErrorOperationError extends scala.Product with scala.Serializable { + sealed trait ExtraErrorOperationError extends scala.Product with scala.Serializable { self => @inline final def widen: ExtraErrorOperationError = this def $ordinal: Int + + object project { + def randomOtherClientError: Option[RandomOtherClientError] = ExtraErrorOperationError.RandomOtherClientErrorCase.alt.project.lift(self).map(_.randomOtherClientError) + def randomOtherServerError: Option[RandomOtherServerError] = ExtraErrorOperationError.RandomOtherServerErrorCase.alt.project.lift(self).map(_.randomOtherServerError) + def randomOtherClientErrorWithCode: Option[RandomOtherClientErrorWithCode] = ExtraErrorOperationError.RandomOtherClientErrorWithCodeCase.alt.project.lift(self).map(_.randomOtherClientErrorWithCode) + def randomOtherServerErrorWithCode: Option[RandomOtherServerErrorWithCode] = ExtraErrorOperationError.RandomOtherServerErrorWithCodeCase.alt.project.lift(self).map(_.randomOtherServerErrorWithCode) + } + + def accept[A](visitor: ExtraErrorOperationError.Visitor[A]): A = this match { + case value: ExtraErrorOperationError.RandomOtherClientErrorCase => visitor.randomOtherClientError(value.randomOtherClientError) + case value: ExtraErrorOperationError.RandomOtherServerErrorCase => visitor.randomOtherServerError(value.randomOtherServerError) + case value: ExtraErrorOperationError.RandomOtherClientErrorWithCodeCase => visitor.randomOtherClientErrorWithCode(value.randomOtherClientErrorWithCode) + case value: ExtraErrorOperationError.RandomOtherServerErrorWithCodeCase => visitor.randomOtherServerErrorWithCode(value.randomOtherServerErrorWithCode) + } } object ExtraErrorOperationError extends ShapeTag.Companion[ExtraErrorOperationError] { - def randomOtherClientError(randomOtherClientError:RandomOtherClientError): ExtraErrorOperationError = RandomOtherClientErrorCase(randomOtherClientError) - def randomOtherServerError(randomOtherServerError:RandomOtherServerError): ExtraErrorOperationError = RandomOtherServerErrorCase(randomOtherServerError) - def randomOtherClientErrorWithCode(randomOtherClientErrorWithCode:RandomOtherClientErrorWithCode): ExtraErrorOperationError = RandomOtherClientErrorWithCodeCase(randomOtherClientErrorWithCode) - def randomOtherServerErrorWithCode(randomOtherServerErrorWithCode:RandomOtherServerErrorWithCode): ExtraErrorOperationError = RandomOtherServerErrorWithCodeCase(randomOtherServerErrorWithCode) + def randomOtherClientError(randomOtherClientError: RandomOtherClientError): ExtraErrorOperationError = RandomOtherClientErrorCase(randomOtherClientError) + def randomOtherServerError(randomOtherServerError: RandomOtherServerError): ExtraErrorOperationError = RandomOtherServerErrorCase(randomOtherServerError) + def randomOtherClientErrorWithCode(randomOtherClientErrorWithCode: RandomOtherClientErrorWithCode): ExtraErrorOperationError = RandomOtherClientErrorWithCodeCase(randomOtherClientErrorWithCode) + def randomOtherServerErrorWithCode(randomOtherServerErrorWithCode: RandomOtherServerErrorWithCode): ExtraErrorOperationError = RandomOtherServerErrorWithCodeCase(randomOtherServerErrorWithCode) val id: ShapeId = ShapeId("smithy4s.example", "ExtraErrorOperationError") @@ -126,30 +140,37 @@ object ErrorHandlingServiceExtraErrorsOperation { object RandomOtherClientErrorCase { val hints: Hints = Hints.empty - val schema: Schema[RandomOtherClientErrorCase] = bijection(RandomOtherClientError.schema.addHints(hints), RandomOtherClientErrorCase(_), _.randomOtherClientError) + val schema: Schema[ExtraErrorOperationError.RandomOtherClientErrorCase] = bijection(RandomOtherClientError.schema.addHints(hints), ExtraErrorOperationError.RandomOtherClientErrorCase(_), _.randomOtherClientError) val alt = schema.oneOf[ExtraErrorOperationError]("RandomOtherClientError") } object RandomOtherServerErrorCase { val hints: Hints = Hints.empty - val schema: Schema[RandomOtherServerErrorCase] = bijection(RandomOtherServerError.schema.addHints(hints), RandomOtherServerErrorCase(_), _.randomOtherServerError) + val schema: Schema[ExtraErrorOperationError.RandomOtherServerErrorCase] = bijection(RandomOtherServerError.schema.addHints(hints), ExtraErrorOperationError.RandomOtherServerErrorCase(_), _.randomOtherServerError) val alt = schema.oneOf[ExtraErrorOperationError]("RandomOtherServerError") } object RandomOtherClientErrorWithCodeCase { val hints: Hints = Hints.empty - val schema: Schema[RandomOtherClientErrorWithCodeCase] = bijection(RandomOtherClientErrorWithCode.schema.addHints(hints), RandomOtherClientErrorWithCodeCase(_), _.randomOtherClientErrorWithCode) + val schema: Schema[ExtraErrorOperationError.RandomOtherClientErrorWithCodeCase] = bijection(RandomOtherClientErrorWithCode.schema.addHints(hints), ExtraErrorOperationError.RandomOtherClientErrorWithCodeCase(_), _.randomOtherClientErrorWithCode) val alt = schema.oneOf[ExtraErrorOperationError]("RandomOtherClientErrorWithCode") } object RandomOtherServerErrorWithCodeCase { val hints: Hints = Hints.empty - val schema: Schema[RandomOtherServerErrorWithCodeCase] = bijection(RandomOtherServerErrorWithCode.schema.addHints(hints), RandomOtherServerErrorWithCodeCase(_), _.randomOtherServerErrorWithCode) + val schema: Schema[ExtraErrorOperationError.RandomOtherServerErrorWithCodeCase] = bijection(RandomOtherServerErrorWithCode.schema.addHints(hints), ExtraErrorOperationError.RandomOtherServerErrorWithCodeCase(_), _.randomOtherServerErrorWithCode) val alt = schema.oneOf[ExtraErrorOperationError]("RandomOtherServerErrorWithCode") } + trait Visitor[A] { + def randomOtherClientError(value: RandomOtherClientError): A + def randomOtherServerError(value: RandomOtherServerError): A + def randomOtherClientErrorWithCode(value: RandomOtherClientErrorWithCode): A + def randomOtherServerErrorWithCode(value: RandomOtherServerErrorWithCode): A + } + implicit val schema: UnionSchema[ExtraErrorOperationError] = union( - RandomOtherClientErrorCase.alt, - RandomOtherServerErrorCase.alt, - RandomOtherClientErrorWithCodeCase.alt, - RandomOtherServerErrorWithCodeCase.alt, + ExtraErrorOperationError.RandomOtherClientErrorCase.alt, + ExtraErrorOperationError.RandomOtherServerErrorCase.alt, + ExtraErrorOperationError.RandomOtherClientErrorWithCodeCase.alt, + ExtraErrorOperationError.RandomOtherServerErrorWithCodeCase.alt, ){ _.$ordinal } diff --git a/modules/bootstrapped/src/generated/smithy4s/example/Foo.scala b/modules/bootstrapped/src/generated/smithy4s/example/Foo.scala index 95c5c4bc4..fabb89c25 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/Foo.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/Foo.scala @@ -14,19 +14,33 @@ import smithy4s.schema.Schema.union * int, bigInt and bDec are useful number constructs * The string case is there because. */ -sealed trait Foo extends scala.Product with scala.Serializable { +sealed trait Foo extends scala.Product with scala.Serializable { self => @inline final def widen: Foo = this def $ordinal: Int + + object project { + def int: Option[Int] = Foo.IntCase.alt.project.lift(self).map(_.int) + def str: Option[String] = Foo.StrCase.alt.project.lift(self).map(_.str) + def bInt: Option[BigInt] = Foo.BIntCase.alt.project.lift(self).map(_.bInt) + def bDec: Option[BigDecimal] = Foo.BDecCase.alt.project.lift(self).map(_.bDec) + } + + def accept[A](visitor: Foo.Visitor[A]): A = this match { + case value: Foo.IntCase => visitor.int(value.int) + case value: Foo.StrCase => visitor.str(value.str) + case value: Foo.BIntCase => visitor.bInt(value.bInt) + case value: Foo.BDecCase => visitor.bDec(value.bDec) + } } object Foo extends ShapeTag.Companion[Foo] { - def int(int:Int): Foo = IntCase(int) + def int(int: Int): Foo = IntCase(int) /** this is a comment saying you should be careful for this case * you never know what lies ahead with Strings like this */ - def str(str:String): Foo = StrCase(str) - def bInt(bInt:BigInt): Foo = BIntCase(bInt) - def bDec(bDec:BigDecimal): Foo = BDecCase(bDec) + def str(str: String): Foo = StrCase(str) + def bInt(bInt: BigInt): Foo = BIntCase(bInt) + def bDec(bDec: BigDecimal): Foo = BDecCase(bDec) val id: ShapeId = ShapeId("smithy4s.example", "Foo") @@ -44,32 +58,39 @@ object Foo extends ShapeTag.Companion[Foo] { object IntCase { val hints: Hints = Hints.empty - val schema: Schema[IntCase] = bijection(smithy4s.schema.Schema.int.addHints(hints), IntCase(_), _.int) + val schema: Schema[Foo.IntCase] = bijection(smithy4s.schema.Schema.int.addHints(hints), Foo.IntCase(_), _.int) val alt = schema.oneOf[Foo]("int") } object StrCase { val hints: Hints = Hints( smithy.api.Documentation("this is a comment saying you should be careful for this case\nyou never know what lies ahead with Strings like this"), ) - val schema: Schema[StrCase] = bijection(string.addHints(hints), StrCase(_), _.str) + val schema: Schema[Foo.StrCase] = bijection(string.addHints(hints), Foo.StrCase(_), _.str) val alt = schema.oneOf[Foo]("str") } object BIntCase { val hints: Hints = Hints.empty - val schema: Schema[BIntCase] = bijection(bigint.addHints(hints), BIntCase(_), _.bInt) + val schema: Schema[Foo.BIntCase] = bijection(bigint.addHints(hints), Foo.BIntCase(_), _.bInt) val alt = schema.oneOf[Foo]("bInt") } object BDecCase { val hints: Hints = Hints.empty - val schema: Schema[BDecCase] = bijection(bigdecimal.addHints(hints), BDecCase(_), _.bDec) + val schema: Schema[Foo.BDecCase] = bijection(bigdecimal.addHints(hints), Foo.BDecCase(_), _.bDec) val alt = schema.oneOf[Foo]("bDec") } + trait Visitor[A] { + def int(value: Int): A + def str(value: String): A + def bInt(value: BigInt): A + def bDec(value: BigDecimal): A + } + implicit val schema: Schema[Foo] = union( - IntCase.alt, - StrCase.alt, - BIntCase.alt, - BDecCase.alt, + Foo.IntCase.alt, + Foo.StrCase.alt, + Foo.BIntCase.alt, + Foo.BDecCase.alt, ){ _.$ordinal }.withId(id).addHints(hints) diff --git a/modules/bootstrapped/src/generated/smithy4s/example/Food.scala b/modules/bootstrapped/src/generated/smithy4s/example/Food.scala index 6dcf7ffce..7b6cc7b47 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/Food.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/Food.scala @@ -7,14 +7,24 @@ import smithy4s.ShapeTag import smithy4s.schema.Schema.bijection import smithy4s.schema.Schema.union -sealed trait Food extends scala.Product with scala.Serializable { +sealed trait Food extends scala.Product with scala.Serializable { self => @inline final def widen: Food = this def $ordinal: Int + + object project { + def pizza: Option[Pizza] = Food.PizzaCase.alt.project.lift(self).map(_.pizza) + def salad: Option[Salad] = Food.SaladCase.alt.project.lift(self).map(_.salad) + } + + def accept[A](visitor: Food.Visitor[A]): A = this match { + case value: Food.PizzaCase => visitor.pizza(value.pizza) + case value: Food.SaladCase => visitor.salad(value.salad) + } } object Food extends ShapeTag.Companion[Food] { - def pizza(pizza:Pizza): Food = PizzaCase(pizza) - def salad(salad:Salad): Food = SaladCase(salad) + def pizza(pizza: Pizza): Food = PizzaCase(pizza) + def salad(salad: Salad): Food = SaladCase(salad) val id: ShapeId = ShapeId("smithy4s.example", "Food") @@ -25,18 +35,23 @@ object Food extends ShapeTag.Companion[Food] { object PizzaCase { val hints: Hints = Hints.empty - val schema: Schema[PizzaCase] = bijection(Pizza.schema.addHints(hints), PizzaCase(_), _.pizza) + val schema: Schema[Food.PizzaCase] = bijection(Pizza.schema.addHints(hints), Food.PizzaCase(_), _.pizza) val alt = schema.oneOf[Food]("pizza") } object SaladCase { val hints: Hints = Hints.empty - val schema: Schema[SaladCase] = bijection(Salad.schema.addHints(hints), SaladCase(_), _.salad) + val schema: Schema[Food.SaladCase] = bijection(Salad.schema.addHints(hints), Food.SaladCase(_), _.salad) val alt = schema.oneOf[Food]("salad") } + trait Visitor[A] { + def pizza(value: Pizza): A + def salad(value: Salad): A + } + implicit val schema: Schema[Food] = union( - PizzaCase.alt, - SaladCase.alt, + Food.PizzaCase.alt, + Food.SaladCase.alt, ){ _.$ordinal }.withId(id).addHints(hints) diff --git a/modules/bootstrapped/src/generated/smithy4s/example/ForecastResult.scala b/modules/bootstrapped/src/generated/smithy4s/example/ForecastResult.scala index 9baebc1e3..7e8bf5c0c 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/ForecastResult.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/ForecastResult.scala @@ -8,22 +8,32 @@ import smithy4s.optics.Prism import smithy4s.schema.Schema.bijection import smithy4s.schema.Schema.union -sealed trait ForecastResult extends scala.Product with scala.Serializable { +sealed trait ForecastResult extends scala.Product with scala.Serializable { self => @inline final def widen: ForecastResult = this def $ordinal: Int + + object project { + def rain: Option[ChanceOfRain] = ForecastResult.RainCase.alt.project.lift(self).map(_.rain) + def sun: Option[UVIndex] = ForecastResult.SunCase.alt.project.lift(self).map(_.sun) + } + + def accept[A](visitor: ForecastResult.Visitor[A]): A = this match { + case value: ForecastResult.RainCase => visitor.rain(value.rain) + case value: ForecastResult.SunCase => visitor.sun(value.sun) + } } object ForecastResult extends ShapeTag.Companion[ForecastResult] { - def rain(rain:ChanceOfRain): ForecastResult = RainCase(rain) - def sun(sun:UVIndex): ForecastResult = SunCase(sun) + def rain(rain: ChanceOfRain): ForecastResult = RainCase(rain) + def sun(sun: UVIndex): ForecastResult = SunCase(sun) val id: ShapeId = ShapeId("smithy4s.example", "ForecastResult") val hints: Hints = Hints.empty object optics { - val rain: Prism[ForecastResult, ChanceOfRain] = Prism.partial[ForecastResult, ChanceOfRain]{ case RainCase(t) => t }(RainCase.apply) - val sun: Prism[ForecastResult, UVIndex] = Prism.partial[ForecastResult, UVIndex]{ case SunCase(t) => t }(SunCase.apply) + val rain: Prism[ForecastResult, ChanceOfRain] = Prism.partial[ForecastResult, ChanceOfRain]{ case ForecastResult.RainCase(t) => t }(ForecastResult.RainCase.apply) + val sun: Prism[ForecastResult, UVIndex] = Prism.partial[ForecastResult, UVIndex]{ case ForecastResult.SunCase(t) => t }(ForecastResult.SunCase.apply) } final case class RainCase(rain: ChanceOfRain) extends ForecastResult { final def $ordinal: Int = 0 } @@ -31,18 +41,23 @@ object ForecastResult extends ShapeTag.Companion[ForecastResult] { object RainCase { val hints: Hints = Hints.empty - val schema: Schema[RainCase] = bijection(ChanceOfRain.schema.addHints(hints), RainCase(_), _.rain) + val schema: Schema[ForecastResult.RainCase] = bijection(ChanceOfRain.schema.addHints(hints), ForecastResult.RainCase(_), _.rain) val alt = schema.oneOf[ForecastResult]("rain") } object SunCase { val hints: Hints = Hints.empty - val schema: Schema[SunCase] = bijection(UVIndex.schema.addHints(hints), SunCase(_), _.sun) + val schema: Schema[ForecastResult.SunCase] = bijection(UVIndex.schema.addHints(hints), ForecastResult.SunCase(_), _.sun) val alt = schema.oneOf[ForecastResult]("sun") } + trait Visitor[A] { + def rain(value: ChanceOfRain): A + def sun(value: UVIndex): A + } + implicit val schema: Schema[ForecastResult] = union( - RainCase.alt, - SunCase.alt, + ForecastResult.RainCase.alt, + ForecastResult.SunCase.alt, ){ _.$ordinal }.withId(id).addHints(hints) diff --git a/modules/bootstrapped/src/generated/smithy4s/example/KVStore.scala b/modules/bootstrapped/src/generated/smithy4s/example/KVStore.scala index 394f42c8c..a3d70e5e3 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/KVStore.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/KVStore.scala @@ -112,14 +112,24 @@ object KVStoreOperation { case GetError.KeyNotFoundErrorCase(e) => e } } - sealed trait GetError extends scala.Product with scala.Serializable { + sealed trait GetError extends scala.Product with scala.Serializable { self => @inline final def widen: GetError = this def $ordinal: Int + + object project { + def unauthorizedError: Option[UnauthorizedError] = GetError.UnauthorizedErrorCase.alt.project.lift(self).map(_.unauthorizedError) + def keyNotFoundError: Option[KeyNotFoundError] = GetError.KeyNotFoundErrorCase.alt.project.lift(self).map(_.keyNotFoundError) + } + + def accept[A](visitor: GetError.Visitor[A]): A = this match { + case value: GetError.UnauthorizedErrorCase => visitor.unauthorizedError(value.unauthorizedError) + case value: GetError.KeyNotFoundErrorCase => visitor.keyNotFoundError(value.keyNotFoundError) + } } object GetError extends ShapeTag.Companion[GetError] { - def unauthorizedError(unauthorizedError:UnauthorizedError): GetError = UnauthorizedErrorCase(unauthorizedError) - def keyNotFoundError(keyNotFoundError:KeyNotFoundError): GetError = KeyNotFoundErrorCase(keyNotFoundError) + def unauthorizedError(unauthorizedError: UnauthorizedError): GetError = UnauthorizedErrorCase(unauthorizedError) + def keyNotFoundError(keyNotFoundError: KeyNotFoundError): GetError = KeyNotFoundErrorCase(keyNotFoundError) val id: ShapeId = ShapeId("smithy4s.example", "GetError") @@ -130,18 +140,23 @@ object KVStoreOperation { object UnauthorizedErrorCase { val hints: Hints = Hints.empty - val schema: Schema[UnauthorizedErrorCase] = bijection(UnauthorizedError.schema.addHints(hints), UnauthorizedErrorCase(_), _.unauthorizedError) + val schema: Schema[GetError.UnauthorizedErrorCase] = bijection(UnauthorizedError.schema.addHints(hints), GetError.UnauthorizedErrorCase(_), _.unauthorizedError) val alt = schema.oneOf[GetError]("UnauthorizedError") } object KeyNotFoundErrorCase { val hints: Hints = Hints.empty - val schema: Schema[KeyNotFoundErrorCase] = bijection(KeyNotFoundError.schema.addHints(hints), KeyNotFoundErrorCase(_), _.keyNotFoundError) + val schema: Schema[GetError.KeyNotFoundErrorCase] = bijection(KeyNotFoundError.schema.addHints(hints), GetError.KeyNotFoundErrorCase(_), _.keyNotFoundError) val alt = schema.oneOf[GetError]("KeyNotFoundError") } + trait Visitor[A] { + def unauthorizedError(value: UnauthorizedError): A + def keyNotFoundError(value: KeyNotFoundError): A + } + implicit val schema: UnionSchema[GetError] = union( - UnauthorizedErrorCase.alt, - KeyNotFoundErrorCase.alt, + GetError.UnauthorizedErrorCase.alt, + GetError.KeyNotFoundErrorCase.alt, ){ _.$ordinal } @@ -169,13 +184,21 @@ object KVStoreOperation { case PutError.UnauthorizedErrorCase(e) => e } } - sealed trait PutError extends scala.Product with scala.Serializable { + sealed trait PutError extends scala.Product with scala.Serializable { self => @inline final def widen: PutError = this def $ordinal: Int + + object project { + def unauthorizedError: Option[UnauthorizedError] = PutError.UnauthorizedErrorCase.alt.project.lift(self).map(_.unauthorizedError) + } + + def accept[A](visitor: PutError.Visitor[A]): A = this match { + case value: PutError.UnauthorizedErrorCase => visitor.unauthorizedError(value.unauthorizedError) + } } object PutError extends ShapeTag.Companion[PutError] { - def unauthorizedError(unauthorizedError:UnauthorizedError): PutError = UnauthorizedErrorCase(unauthorizedError) + def unauthorizedError(unauthorizedError: UnauthorizedError): PutError = UnauthorizedErrorCase(unauthorizedError) val id: ShapeId = ShapeId("smithy4s.example", "PutError") @@ -185,12 +208,16 @@ object KVStoreOperation { object UnauthorizedErrorCase { val hints: Hints = Hints.empty - val schema: Schema[UnauthorizedErrorCase] = bijection(UnauthorizedError.schema.addHints(hints), UnauthorizedErrorCase(_), _.unauthorizedError) + val schema: Schema[PutError.UnauthorizedErrorCase] = bijection(UnauthorizedError.schema.addHints(hints), PutError.UnauthorizedErrorCase(_), _.unauthorizedError) val alt = schema.oneOf[PutError]("UnauthorizedError") } + trait Visitor[A] { + def unauthorizedError(value: UnauthorizedError): A + } + implicit val schema: UnionSchema[PutError] = union( - UnauthorizedErrorCase.alt, + PutError.UnauthorizedErrorCase.alt, ){ _.$ordinal } @@ -220,14 +247,24 @@ object KVStoreOperation { case DeleteError.KeyNotFoundErrorCase(e) => e } } - sealed trait DeleteError extends scala.Product with scala.Serializable { + sealed trait DeleteError extends scala.Product with scala.Serializable { self => @inline final def widen: DeleteError = this def $ordinal: Int + + object project { + def unauthorizedError: Option[UnauthorizedError] = DeleteError.UnauthorizedErrorCase.alt.project.lift(self).map(_.unauthorizedError) + def keyNotFoundError: Option[KeyNotFoundError] = DeleteError.KeyNotFoundErrorCase.alt.project.lift(self).map(_.keyNotFoundError) + } + + def accept[A](visitor: DeleteError.Visitor[A]): A = this match { + case value: DeleteError.UnauthorizedErrorCase => visitor.unauthorizedError(value.unauthorizedError) + case value: DeleteError.KeyNotFoundErrorCase => visitor.keyNotFoundError(value.keyNotFoundError) + } } object DeleteError extends ShapeTag.Companion[DeleteError] { - def unauthorizedError(unauthorizedError:UnauthorizedError): DeleteError = UnauthorizedErrorCase(unauthorizedError) - def keyNotFoundError(keyNotFoundError:KeyNotFoundError): DeleteError = KeyNotFoundErrorCase(keyNotFoundError) + def unauthorizedError(unauthorizedError: UnauthorizedError): DeleteError = UnauthorizedErrorCase(unauthorizedError) + def keyNotFoundError(keyNotFoundError: KeyNotFoundError): DeleteError = KeyNotFoundErrorCase(keyNotFoundError) val id: ShapeId = ShapeId("smithy4s.example", "DeleteError") @@ -238,18 +275,23 @@ object KVStoreOperation { object UnauthorizedErrorCase { val hints: Hints = Hints.empty - val schema: Schema[UnauthorizedErrorCase] = bijection(UnauthorizedError.schema.addHints(hints), UnauthorizedErrorCase(_), _.unauthorizedError) + val schema: Schema[DeleteError.UnauthorizedErrorCase] = bijection(UnauthorizedError.schema.addHints(hints), DeleteError.UnauthorizedErrorCase(_), _.unauthorizedError) val alt = schema.oneOf[DeleteError]("UnauthorizedError") } object KeyNotFoundErrorCase { val hints: Hints = Hints.empty - val schema: Schema[KeyNotFoundErrorCase] = bijection(KeyNotFoundError.schema.addHints(hints), KeyNotFoundErrorCase(_), _.keyNotFoundError) + val schema: Schema[DeleteError.KeyNotFoundErrorCase] = bijection(KeyNotFoundError.schema.addHints(hints), DeleteError.KeyNotFoundErrorCase(_), _.keyNotFoundError) val alt = schema.oneOf[DeleteError]("KeyNotFoundError") } + trait Visitor[A] { + def unauthorizedError(value: UnauthorizedError): A + def keyNotFoundError(value: KeyNotFoundError): A + } + implicit val schema: UnionSchema[DeleteError] = union( - UnauthorizedErrorCase.alt, - KeyNotFoundErrorCase.alt, + DeleteError.UnauthorizedErrorCase.alt, + DeleteError.KeyNotFoundErrorCase.alt, ){ _.$ordinal } diff --git a/modules/bootstrapped/src/generated/smithy4s/example/NameCollision.scala b/modules/bootstrapped/src/generated/smithy4s/example/NameCollision.scala index 02f83e08c..de57ea980 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/NameCollision.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/NameCollision.scala @@ -102,13 +102,21 @@ object NameCollisionOperation { case MyOpError.MyOpErrorCase(e) => e } } - sealed trait MyOpError extends scala.Product with scala.Serializable { + sealed trait MyOpError extends scala.Product with scala.Serializable { self => @inline final def widen: MyOpError = this def $ordinal: Int + + object project { + def myOpError: Option[smithy4s.example.MyOpError] = MyOpError.MyOpErrorCase.alt.project.lift(self).map(_.myOpError) + } + + def accept[A](visitor: MyOpError.Visitor[A]): A = this match { + case value: MyOpError.MyOpErrorCase => visitor.myOpError(value.myOpError) + } } object MyOpError extends ShapeTag.Companion[MyOpError] { - def myOpError(myOpError:smithy4s.example.MyOpError): MyOpError = MyOpErrorCase(myOpError) + def myOpError(myOpError: smithy4s.example.MyOpError): MyOpError = MyOpErrorCase(myOpError) val id: ShapeId = ShapeId("smithy4s.example", "MyOpError") @@ -118,12 +126,16 @@ object NameCollisionOperation { object MyOpErrorCase { val hints: Hints = Hints.empty - val schema: Schema[MyOpErrorCase] = bijection(smithy4s.example.MyOpError.schema.addHints(hints), MyOpErrorCase(_), _.myOpError) + val schema: Schema[MyOpError.MyOpErrorCase] = bijection(smithy4s.example.MyOpError.schema.addHints(hints), MyOpError.MyOpErrorCase(_), _.myOpError) val alt = schema.oneOf[MyOpError]("MyOpError") } + trait Visitor[A] { + def myOpError(value: smithy4s.example.MyOpError): A + } + implicit val schema: UnionSchema[MyOpError] = union( - MyOpErrorCase.alt, + MyOpError.MyOpErrorCase.alt, ){ _.$ordinal } diff --git a/modules/bootstrapped/src/generated/smithy4s/example/ObjectService.scala b/modules/bootstrapped/src/generated/smithy4s/example/ObjectService.scala index da92c835a..31ba35aba 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/ObjectService.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/ObjectService.scala @@ -118,14 +118,24 @@ object ObjectServiceOperation { case PutObjectError.NoMoreSpaceCase(e) => e } } - sealed trait PutObjectError extends scala.Product with scala.Serializable { + sealed trait PutObjectError extends scala.Product with scala.Serializable { self => @inline final def widen: PutObjectError = this def $ordinal: Int + + object project { + def serverError: Option[ServerError] = PutObjectError.ServerErrorCase.alt.project.lift(self).map(_.serverError) + def noMoreSpace: Option[NoMoreSpace] = PutObjectError.NoMoreSpaceCase.alt.project.lift(self).map(_.noMoreSpace) + } + + def accept[A](visitor: PutObjectError.Visitor[A]): A = this match { + case value: PutObjectError.ServerErrorCase => visitor.serverError(value.serverError) + case value: PutObjectError.NoMoreSpaceCase => visitor.noMoreSpace(value.noMoreSpace) + } } object PutObjectError extends ShapeTag.Companion[PutObjectError] { - def serverError(serverError:ServerError): PutObjectError = ServerErrorCase(serverError) - def noMoreSpace(noMoreSpace:NoMoreSpace): PutObjectError = NoMoreSpaceCase(noMoreSpace) + def serverError(serverError: ServerError): PutObjectError = ServerErrorCase(serverError) + def noMoreSpace(noMoreSpace: NoMoreSpace): PutObjectError = NoMoreSpaceCase(noMoreSpace) val id: ShapeId = ShapeId("smithy4s.example", "PutObjectError") @@ -136,18 +146,23 @@ object ObjectServiceOperation { object ServerErrorCase { val hints: Hints = Hints.empty - val schema: Schema[ServerErrorCase] = bijection(ServerError.schema.addHints(hints), ServerErrorCase(_), _.serverError) + val schema: Schema[PutObjectError.ServerErrorCase] = bijection(ServerError.schema.addHints(hints), PutObjectError.ServerErrorCase(_), _.serverError) val alt = schema.oneOf[PutObjectError]("ServerError") } object NoMoreSpaceCase { val hints: Hints = Hints.empty - val schema: Schema[NoMoreSpaceCase] = bijection(NoMoreSpace.schema.addHints(hints), NoMoreSpaceCase(_), _.noMoreSpace) + val schema: Schema[PutObjectError.NoMoreSpaceCase] = bijection(NoMoreSpace.schema.addHints(hints), PutObjectError.NoMoreSpaceCase(_), _.noMoreSpace) val alt = schema.oneOf[PutObjectError]("NoMoreSpace") } + trait Visitor[A] { + def serverError(value: ServerError): A + def noMoreSpace(value: NoMoreSpace): A + } + implicit val schema: UnionSchema[PutObjectError] = union( - ServerErrorCase.alt, - NoMoreSpaceCase.alt, + PutObjectError.ServerErrorCase.alt, + PutObjectError.NoMoreSpaceCase.alt, ){ _.$ordinal } @@ -178,13 +193,21 @@ object ObjectServiceOperation { case GetObjectError.ServerErrorCase(e) => e } } - sealed trait GetObjectError extends scala.Product with scala.Serializable { + sealed trait GetObjectError extends scala.Product with scala.Serializable { self => @inline final def widen: GetObjectError = this def $ordinal: Int + + object project { + def serverError: Option[ServerError] = GetObjectError.ServerErrorCase.alt.project.lift(self).map(_.serverError) + } + + def accept[A](visitor: GetObjectError.Visitor[A]): A = this match { + case value: GetObjectError.ServerErrorCase => visitor.serverError(value.serverError) + } } object GetObjectError extends ShapeTag.Companion[GetObjectError] { - def serverError(serverError:ServerError): GetObjectError = ServerErrorCase(serverError) + def serverError(serverError: ServerError): GetObjectError = ServerErrorCase(serverError) val id: ShapeId = ShapeId("smithy4s.example", "GetObjectError") @@ -194,12 +217,16 @@ object ObjectServiceOperation { object ServerErrorCase { val hints: Hints = Hints.empty - val schema: Schema[ServerErrorCase] = bijection(ServerError.schema.addHints(hints), ServerErrorCase(_), _.serverError) + val schema: Schema[GetObjectError.ServerErrorCase] = bijection(ServerError.schema.addHints(hints), GetObjectError.ServerErrorCase(_), _.serverError) val alt = schema.oneOf[GetObjectError]("ServerError") } + trait Visitor[A] { + def serverError(value: ServerError): A + } + implicit val schema: UnionSchema[GetObjectError] = union( - ServerErrorCase.alt, + GetObjectError.ServerErrorCase.alt, ){ _.$ordinal } diff --git a/modules/bootstrapped/src/generated/smithy4s/example/OpticsUnion.scala b/modules/bootstrapped/src/generated/smithy4s/example/OpticsUnion.scala index 9a35ca6fb..f8d5164cb 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/OpticsUnion.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/OpticsUnion.scala @@ -8,32 +8,44 @@ import smithy4s.optics.Prism import smithy4s.schema.Schema.bijection import smithy4s.schema.Schema.union -sealed trait OpticsUnion extends scala.Product with scala.Serializable { +sealed trait OpticsUnion extends scala.Product with scala.Serializable { self => @inline final def widen: OpticsUnion = this def $ordinal: Int + + object project { + def one: Option[OpticsStructure] = OpticsUnion.OneCase.alt.project.lift(self).map(_.one) + } + + def accept[A](visitor: OpticsUnion.Visitor[A]): A = this match { + case value: OpticsUnion.OneCase => visitor.one(value.one) + } } object OpticsUnion extends ShapeTag.Companion[OpticsUnion] { - def one(one:OpticsStructure): OpticsUnion = OneCase(one) + def one(one: OpticsStructure): OpticsUnion = OneCase(one) val id: ShapeId = ShapeId("smithy4s.example", "OpticsUnion") val hints: Hints = Hints.empty object optics { - val one: Prism[OpticsUnion, OpticsStructure] = Prism.partial[OpticsUnion, OpticsStructure]{ case OneCase(t) => t }(OneCase.apply) + val one: Prism[OpticsUnion, OpticsStructure] = Prism.partial[OpticsUnion, OpticsStructure]{ case OpticsUnion.OneCase(t) => t }(OpticsUnion.OneCase.apply) } final case class OneCase(one: OpticsStructure) extends OpticsUnion { final def $ordinal: Int = 0 } object OneCase { val hints: Hints = Hints.empty - val schema: Schema[OneCase] = bijection(OpticsStructure.schema.addHints(hints), OneCase(_), _.one) + val schema: Schema[OpticsUnion.OneCase] = bijection(OpticsStructure.schema.addHints(hints), OpticsUnion.OneCase(_), _.one) val alt = schema.oneOf[OpticsUnion]("one") } + trait Visitor[A] { + def one(value: OpticsStructure): A + } + implicit val schema: Schema[OpticsUnion] = union( - OneCase.alt, + OpticsUnion.OneCase.alt, ){ _.$ordinal }.withId(id).addHints(hints) diff --git a/modules/bootstrapped/src/generated/smithy4s/example/OrderType.scala b/modules/bootstrapped/src/generated/smithy4s/example/OrderType.scala index 7b81c7902..af1cebf60 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/OrderType.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/OrderType.scala @@ -1,5 +1,6 @@ package smithy4s.example +import OrderType.PreviewCaseAlt import smithy4s.Hints import smithy4s.Schema import smithy4s.ShapeId @@ -12,16 +13,28 @@ import smithy4s.schema.Schema.union /** Our order types have different ways to identify a product * Except for preview orders, these don't have an ID */ -sealed trait OrderType extends scala.Product with scala.Serializable { +sealed trait OrderType extends scala.Product with scala.Serializable { self => @inline final def widen: OrderType = this def $ordinal: Int + + object project { + def online: Option[OrderNumber] = OrderType.OnlineCase.alt.project.lift(self).map(_.online) + def inStore: Option[OrderType.InStoreOrder] = OrderType.InStoreOrder.alt.project.lift(self) + def preview: Option[OrderType.PreviewCase.type] = PreviewCaseAlt.project.lift(self) + } + + def accept[A](visitor: OrderType.Visitor[A]): A = this match { + case value: OrderType.OnlineCase => visitor.online(value.online) + case value: OrderType.InStoreOrder => visitor.inStore(value) + case value: OrderType.PreviewCase.type => visitor.preview(value) + } } object OrderType extends ShapeTag.Companion[OrderType] { - def online(online:OrderNumber): OrderType = OnlineCase(online) + def online(online: OrderNumber): OrderType = OnlineCase(online) /** For an InStoreOrder a location ID isn't needed */ def inStoreOrder(id: OrderNumber, locationId: Option[String] = None):InStoreOrder = InStoreOrder(id, locationId) - def preview(): OrderType = PreviewCase + def preview(): OrderType = OrderType.PreviewCase val id: ShapeId = ShapeId("smithy4s.example", "OrderType") @@ -51,17 +64,23 @@ object OrderType extends ShapeTag.Companion[OrderType] { val alt = schema.oneOf[OrderType]("inStore") } case object PreviewCase extends OrderType { final def $ordinal: Int = 2 } - private val PreviewCaseAlt = Schema.constant(PreviewCase).oneOf[OrderType]("preview").addHints(hints) + private val PreviewCaseAlt = Schema.constant(OrderType.PreviewCase).oneOf[OrderType]("preview").addHints(hints) object OnlineCase { val hints: Hints = Hints.empty - val schema: Schema[OnlineCase] = bijection(OrderNumber.schema.addHints(hints), OnlineCase(_), _.online) + val schema: Schema[OrderType.OnlineCase] = bijection(OrderNumber.schema.addHints(hints), OrderType.OnlineCase(_), _.online) val alt = schema.oneOf[OrderType]("online") } + trait Visitor[A] { + def online(value: OrderNumber): A + def inStore(value: OrderType.InStoreOrder): A + def preview(value: OrderType.PreviewCase.type): A + } + implicit val schema: Schema[OrderType] = union( - OnlineCase.alt, - InStoreOrder.alt, + OrderType.OnlineCase.alt, + OrderType.InStoreOrder.alt, PreviewCaseAlt, ){ _.$ordinal diff --git a/modules/bootstrapped/src/generated/smithy4s/example/PersonContactInfo.scala b/modules/bootstrapped/src/generated/smithy4s/example/PersonContactInfo.scala index cc50e46b2..1bb73cecb 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/PersonContactInfo.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/PersonContactInfo.scala @@ -9,14 +9,24 @@ import smithy4s.optics.Prism import smithy4s.schema.Schema.bijection import smithy4s.schema.Schema.union -sealed trait PersonContactInfo extends scala.Product with scala.Serializable { +sealed trait PersonContactInfo extends scala.Product with scala.Serializable { self => @inline final def widen: PersonContactInfo = this def $ordinal: Int + + object project { + def email: Option[PersonEmail] = PersonContactInfo.EmailCase.alt.project.lift(self).map(_.email) + def phone: Option[PersonPhoneNumber] = PersonContactInfo.PhoneCase.alt.project.lift(self).map(_.phone) + } + + def accept[A](visitor: PersonContactInfo.Visitor[A]): A = this match { + case value: PersonContactInfo.EmailCase => visitor.email(value.email) + case value: PersonContactInfo.PhoneCase => visitor.phone(value.phone) + } } object PersonContactInfo extends ShapeTag.Companion[PersonContactInfo] { - def email(email:PersonEmail): PersonContactInfo = EmailCase(email) - def phone(phone:PersonPhoneNumber): PersonContactInfo = PhoneCase(phone) + def email(email: PersonEmail): PersonContactInfo = EmailCase(email) + def phone(phone: PersonPhoneNumber): PersonContactInfo = PhoneCase(phone) val id: ShapeId = ShapeId("smithy4s.example", "PersonContactInfo") @@ -25,8 +35,8 @@ object PersonContactInfo extends ShapeTag.Companion[PersonContactInfo] { ) object optics { - val email: Prism[PersonContactInfo, PersonEmail] = Prism.partial[PersonContactInfo, PersonEmail]{ case EmailCase(t) => t }(EmailCase.apply) - val phone: Prism[PersonContactInfo, PersonPhoneNumber] = Prism.partial[PersonContactInfo, PersonPhoneNumber]{ case PhoneCase(t) => t }(PhoneCase.apply) + val email: Prism[PersonContactInfo, PersonEmail] = Prism.partial[PersonContactInfo, PersonEmail]{ case PersonContactInfo.EmailCase(t) => t }(PersonContactInfo.EmailCase.apply) + val phone: Prism[PersonContactInfo, PersonPhoneNumber] = Prism.partial[PersonContactInfo, PersonPhoneNumber]{ case PersonContactInfo.PhoneCase(t) => t }(PersonContactInfo.PhoneCase.apply) } final case class EmailCase(email: PersonEmail) extends PersonContactInfo { final def $ordinal: Int = 0 } @@ -34,18 +44,23 @@ object PersonContactInfo extends ShapeTag.Companion[PersonContactInfo] { object EmailCase { val hints: Hints = Hints.empty - val schema: Schema[EmailCase] = bijection(PersonEmail.schema.addHints(hints), EmailCase(_), _.email) + val schema: Schema[PersonContactInfo.EmailCase] = bijection(PersonEmail.schema.addHints(hints), PersonContactInfo.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 schema: Schema[PersonContactInfo.PhoneCase] = bijection(PersonPhoneNumber.schema.addHints(hints), PersonContactInfo.PhoneCase(_), _.phone) val alt = schema.oneOf[PersonContactInfo]("phone") } + trait Visitor[A] { + def email(value: PersonEmail): A + def phone(value: PersonPhoneNumber): A + } + implicit val schema: Schema[PersonContactInfo] = union( - EmailCase.alt, - PhoneCase.alt, + PersonContactInfo.EmailCase.alt, + PersonContactInfo.PhoneCase.alt, ){ _.$ordinal }.withId(id).addHints(hints) diff --git a/modules/bootstrapped/src/generated/smithy4s/example/PizzaAdminService.scala b/modules/bootstrapped/src/generated/smithy4s/example/PizzaAdminService.scala index 3c31dd202..f8b6e891a 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/PizzaAdminService.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/PizzaAdminService.scala @@ -160,15 +160,27 @@ object PizzaAdminServiceOperation { case AddMenuItemError.GenericClientErrorCase(e) => e } } - sealed trait AddMenuItemError extends scala.Product with scala.Serializable { + sealed trait AddMenuItemError extends scala.Product with scala.Serializable { self => @inline final def widen: AddMenuItemError = this def $ordinal: Int + + object project { + def priceError: Option[PriceError] = AddMenuItemError.PriceErrorCase.alt.project.lift(self).map(_.priceError) + def genericServerError: Option[GenericServerError] = AddMenuItemError.GenericServerErrorCase.alt.project.lift(self).map(_.genericServerError) + def genericClientError: Option[GenericClientError] = AddMenuItemError.GenericClientErrorCase.alt.project.lift(self).map(_.genericClientError) + } + + def accept[A](visitor: AddMenuItemError.Visitor[A]): A = this match { + case value: AddMenuItemError.PriceErrorCase => visitor.priceError(value.priceError) + case value: AddMenuItemError.GenericServerErrorCase => visitor.genericServerError(value.genericServerError) + case value: AddMenuItemError.GenericClientErrorCase => visitor.genericClientError(value.genericClientError) + } } object AddMenuItemError extends ShapeTag.Companion[AddMenuItemError] { - def priceError(priceError:PriceError): AddMenuItemError = PriceErrorCase(priceError) - def genericServerError(genericServerError:GenericServerError): AddMenuItemError = GenericServerErrorCase(genericServerError) - def genericClientError(genericClientError:GenericClientError): AddMenuItemError = GenericClientErrorCase(genericClientError) + def priceError(priceError: PriceError): AddMenuItemError = PriceErrorCase(priceError) + def genericServerError(genericServerError: GenericServerError): AddMenuItemError = GenericServerErrorCase(genericServerError) + def genericClientError(genericClientError: GenericClientError): AddMenuItemError = GenericClientErrorCase(genericClientError) val id: ShapeId = ShapeId("smithy4s.example", "AddMenuItemError") @@ -180,24 +192,30 @@ object PizzaAdminServiceOperation { object PriceErrorCase { val hints: Hints = Hints.empty - val schema: Schema[PriceErrorCase] = bijection(PriceError.schema.addHints(hints), PriceErrorCase(_), _.priceError) + val schema: Schema[AddMenuItemError.PriceErrorCase] = bijection(PriceError.schema.addHints(hints), AddMenuItemError.PriceErrorCase(_), _.priceError) val alt = schema.oneOf[AddMenuItemError]("PriceError") } object GenericServerErrorCase { val hints: Hints = Hints.empty - val schema: Schema[GenericServerErrorCase] = bijection(GenericServerError.schema.addHints(hints), GenericServerErrorCase(_), _.genericServerError) + val schema: Schema[AddMenuItemError.GenericServerErrorCase] = bijection(GenericServerError.schema.addHints(hints), AddMenuItemError.GenericServerErrorCase(_), _.genericServerError) val alt = schema.oneOf[AddMenuItemError]("GenericServerError") } object GenericClientErrorCase { val hints: Hints = Hints.empty - val schema: Schema[GenericClientErrorCase] = bijection(GenericClientError.schema.addHints(hints), GenericClientErrorCase(_), _.genericClientError) + val schema: Schema[AddMenuItemError.GenericClientErrorCase] = bijection(GenericClientError.schema.addHints(hints), AddMenuItemError.GenericClientErrorCase(_), _.genericClientError) val alt = schema.oneOf[AddMenuItemError]("GenericClientError") } + trait Visitor[A] { + def priceError(value: PriceError): A + def genericServerError(value: GenericServerError): A + def genericClientError(value: GenericClientError): A + } + implicit val schema: UnionSchema[AddMenuItemError] = union( - PriceErrorCase.alt, - GenericServerErrorCase.alt, - GenericClientErrorCase.alt, + AddMenuItemError.PriceErrorCase.alt, + AddMenuItemError.GenericServerErrorCase.alt, + AddMenuItemError.GenericClientErrorCase.alt, ){ _.$ordinal } @@ -234,16 +252,30 @@ object PizzaAdminServiceOperation { case GetMenuError.NotFoundErrorCase(e) => e } } - sealed trait GetMenuError extends scala.Product with scala.Serializable { + sealed trait GetMenuError extends scala.Product with scala.Serializable { self => @inline final def widen: GetMenuError = this def $ordinal: Int + + object project { + def genericClientError: Option[GenericClientError] = GetMenuError.GenericClientErrorCase.alt.project.lift(self).map(_.genericClientError) + def fallbackError2: Option[FallbackError2] = GetMenuError.FallbackError2Case.alt.project.lift(self).map(_.fallbackError2) + def fallbackError: Option[FallbackError] = GetMenuError.FallbackErrorCase.alt.project.lift(self).map(_.fallbackError) + def notFoundError: Option[NotFoundError] = GetMenuError.NotFoundErrorCase.alt.project.lift(self).map(_.notFoundError) + } + + def accept[A](visitor: GetMenuError.Visitor[A]): A = this match { + case value: GetMenuError.GenericClientErrorCase => visitor.genericClientError(value.genericClientError) + case value: GetMenuError.FallbackError2Case => visitor.fallbackError2(value.fallbackError2) + case value: GetMenuError.FallbackErrorCase => visitor.fallbackError(value.fallbackError) + case value: GetMenuError.NotFoundErrorCase => visitor.notFoundError(value.notFoundError) + } } object GetMenuError extends ShapeTag.Companion[GetMenuError] { - def genericClientError(genericClientError:GenericClientError): GetMenuError = GenericClientErrorCase(genericClientError) - def fallbackError2(fallbackError2:FallbackError2): GetMenuError = FallbackError2Case(fallbackError2) - def fallbackError(fallbackError:FallbackError): GetMenuError = FallbackErrorCase(fallbackError) - def notFoundError(notFoundError:NotFoundError): GetMenuError = NotFoundErrorCase(notFoundError) + def genericClientError(genericClientError: GenericClientError): GetMenuError = GenericClientErrorCase(genericClientError) + def fallbackError2(fallbackError2: FallbackError2): GetMenuError = FallbackError2Case(fallbackError2) + def fallbackError(fallbackError: FallbackError): GetMenuError = FallbackErrorCase(fallbackError) + def notFoundError(notFoundError: NotFoundError): GetMenuError = NotFoundErrorCase(notFoundError) val id: ShapeId = ShapeId("smithy4s.example", "GetMenuError") @@ -256,30 +288,37 @@ object PizzaAdminServiceOperation { object GenericClientErrorCase { val hints: Hints = Hints.empty - val schema: Schema[GenericClientErrorCase] = bijection(GenericClientError.schema.addHints(hints), GenericClientErrorCase(_), _.genericClientError) + val schema: Schema[GetMenuError.GenericClientErrorCase] = bijection(GenericClientError.schema.addHints(hints), GetMenuError.GenericClientErrorCase(_), _.genericClientError) val alt = schema.oneOf[GetMenuError]("GenericClientError") } object FallbackError2Case { val hints: Hints = Hints.empty - val schema: Schema[FallbackError2Case] = bijection(FallbackError2.schema.addHints(hints), FallbackError2Case(_), _.fallbackError2) + val schema: Schema[GetMenuError.FallbackError2Case] = bijection(FallbackError2.schema.addHints(hints), GetMenuError.FallbackError2Case(_), _.fallbackError2) val alt = schema.oneOf[GetMenuError]("FallbackError2") } object FallbackErrorCase { val hints: Hints = Hints.empty - val schema: Schema[FallbackErrorCase] = bijection(FallbackError.schema.addHints(hints), FallbackErrorCase(_), _.fallbackError) + val schema: Schema[GetMenuError.FallbackErrorCase] = bijection(FallbackError.schema.addHints(hints), GetMenuError.FallbackErrorCase(_), _.fallbackError) val alt = schema.oneOf[GetMenuError]("FallbackError") } object NotFoundErrorCase { val hints: Hints = Hints.empty - val schema: Schema[NotFoundErrorCase] = bijection(NotFoundError.schema.addHints(hints), NotFoundErrorCase(_), _.notFoundError) + val schema: Schema[GetMenuError.NotFoundErrorCase] = bijection(NotFoundError.schema.addHints(hints), GetMenuError.NotFoundErrorCase(_), _.notFoundError) val alt = schema.oneOf[GetMenuError]("NotFoundError") } + trait Visitor[A] { + def genericClientError(value: GenericClientError): A + def fallbackError2(value: FallbackError2): A + def fallbackError(value: FallbackError): A + def notFoundError(value: NotFoundError): A + } + implicit val schema: UnionSchema[GetMenuError] = union( - GenericClientErrorCase.alt, - FallbackError2Case.alt, - FallbackErrorCase.alt, - NotFoundErrorCase.alt, + GetMenuError.GenericClientErrorCase.alt, + GetMenuError.FallbackError2Case.alt, + GetMenuError.FallbackErrorCase.alt, + GetMenuError.NotFoundErrorCase.alt, ){ _.$ordinal } @@ -329,13 +368,21 @@ object PizzaAdminServiceOperation { case HealthError.UnknownServerErrorCase(e) => e } } - sealed trait HealthError extends scala.Product with scala.Serializable { + sealed trait HealthError extends scala.Product with scala.Serializable { self => @inline final def widen: HealthError = this def $ordinal: Int + + object project { + def unknownServerError: Option[UnknownServerError] = HealthError.UnknownServerErrorCase.alt.project.lift(self).map(_.unknownServerError) + } + + def accept[A](visitor: HealthError.Visitor[A]): A = this match { + case value: HealthError.UnknownServerErrorCase => visitor.unknownServerError(value.unknownServerError) + } } object HealthError extends ShapeTag.Companion[HealthError] { - def unknownServerError(unknownServerError:UnknownServerError): HealthError = UnknownServerErrorCase(unknownServerError) + def unknownServerError(unknownServerError: UnknownServerError): HealthError = UnknownServerErrorCase(unknownServerError) val id: ShapeId = ShapeId("smithy4s.example", "HealthError") @@ -345,12 +392,16 @@ object PizzaAdminServiceOperation { object UnknownServerErrorCase { val hints: Hints = Hints.empty - val schema: Schema[UnknownServerErrorCase] = bijection(UnknownServerError.schema.addHints(hints), UnknownServerErrorCase(_), _.unknownServerError) + val schema: Schema[HealthError.UnknownServerErrorCase] = bijection(UnknownServerError.schema.addHints(hints), HealthError.UnknownServerErrorCase(_), _.unknownServerError) val alt = schema.oneOf[HealthError]("UnknownServerError") } + trait Visitor[A] { + def unknownServerError(value: UnknownServerError): A + } + implicit val schema: UnionSchema[HealthError] = union( - UnknownServerErrorCase.alt, + HealthError.UnknownServerErrorCase.alt, ){ _.$ordinal } @@ -415,13 +466,21 @@ object PizzaAdminServiceOperation { case GetEnumError.UnknownServerErrorCase(e) => e } } - sealed trait GetEnumError extends scala.Product with scala.Serializable { + sealed trait GetEnumError extends scala.Product with scala.Serializable { self => @inline final def widen: GetEnumError = this def $ordinal: Int + + object project { + def unknownServerError: Option[UnknownServerError] = GetEnumError.UnknownServerErrorCase.alt.project.lift(self).map(_.unknownServerError) + } + + def accept[A](visitor: GetEnumError.Visitor[A]): A = this match { + case value: GetEnumError.UnknownServerErrorCase => visitor.unknownServerError(value.unknownServerError) + } } object GetEnumError extends ShapeTag.Companion[GetEnumError] { - def unknownServerError(unknownServerError:UnknownServerError): GetEnumError = UnknownServerErrorCase(unknownServerError) + def unknownServerError(unknownServerError: UnknownServerError): GetEnumError = UnknownServerErrorCase(unknownServerError) val id: ShapeId = ShapeId("smithy4s.example", "GetEnumError") @@ -431,12 +490,16 @@ object PizzaAdminServiceOperation { object UnknownServerErrorCase { val hints: Hints = Hints.empty - val schema: Schema[UnknownServerErrorCase] = bijection(UnknownServerError.schema.addHints(hints), UnknownServerErrorCase(_), _.unknownServerError) + val schema: Schema[GetEnumError.UnknownServerErrorCase] = bijection(UnknownServerError.schema.addHints(hints), GetEnumError.UnknownServerErrorCase(_), _.unknownServerError) val alt = schema.oneOf[GetEnumError]("UnknownServerError") } + trait Visitor[A] { + def unknownServerError(value: UnknownServerError): A + } + implicit val schema: UnionSchema[GetEnumError] = union( - UnknownServerErrorCase.alt, + GetEnumError.UnknownServerErrorCase.alt, ){ _.$ordinal } @@ -467,13 +530,21 @@ object PizzaAdminServiceOperation { case GetIntEnumError.UnknownServerErrorCase(e) => e } } - sealed trait GetIntEnumError extends scala.Product with scala.Serializable { + sealed trait GetIntEnumError extends scala.Product with scala.Serializable { self => @inline final def widen: GetIntEnumError = this def $ordinal: Int + + object project { + def unknownServerError: Option[UnknownServerError] = GetIntEnumError.UnknownServerErrorCase.alt.project.lift(self).map(_.unknownServerError) + } + + def accept[A](visitor: GetIntEnumError.Visitor[A]): A = this match { + case value: GetIntEnumError.UnknownServerErrorCase => visitor.unknownServerError(value.unknownServerError) + } } object GetIntEnumError extends ShapeTag.Companion[GetIntEnumError] { - def unknownServerError(unknownServerError:UnknownServerError): GetIntEnumError = UnknownServerErrorCase(unknownServerError) + def unknownServerError(unknownServerError: UnknownServerError): GetIntEnumError = UnknownServerErrorCase(unknownServerError) val id: ShapeId = ShapeId("smithy4s.example", "GetIntEnumError") @@ -483,12 +554,16 @@ object PizzaAdminServiceOperation { object UnknownServerErrorCase { val hints: Hints = Hints.empty - val schema: Schema[UnknownServerErrorCase] = bijection(UnknownServerError.schema.addHints(hints), UnknownServerErrorCase(_), _.unknownServerError) + val schema: Schema[GetIntEnumError.UnknownServerErrorCase] = bijection(UnknownServerError.schema.addHints(hints), GetIntEnumError.UnknownServerErrorCase(_), _.unknownServerError) val alt = schema.oneOf[GetIntEnumError]("UnknownServerError") } + trait Visitor[A] { + def unknownServerError(value: UnknownServerError): A + } + implicit val schema: UnionSchema[GetIntEnumError] = union( - UnknownServerErrorCase.alt, + GetIntEnumError.UnknownServerErrorCase.alt, ){ _.$ordinal } @@ -519,13 +594,21 @@ object PizzaAdminServiceOperation { case CustomCodeError.UnknownServerErrorCase(e) => e } } - sealed trait CustomCodeError extends scala.Product with scala.Serializable { + sealed trait CustomCodeError extends scala.Product with scala.Serializable { self => @inline final def widen: CustomCodeError = this def $ordinal: Int + + object project { + def unknownServerError: Option[UnknownServerError] = CustomCodeError.UnknownServerErrorCase.alt.project.lift(self).map(_.unknownServerError) + } + + def accept[A](visitor: CustomCodeError.Visitor[A]): A = this match { + case value: CustomCodeError.UnknownServerErrorCase => visitor.unknownServerError(value.unknownServerError) + } } object CustomCodeError extends ShapeTag.Companion[CustomCodeError] { - def unknownServerError(unknownServerError:UnknownServerError): CustomCodeError = UnknownServerErrorCase(unknownServerError) + def unknownServerError(unknownServerError: UnknownServerError): CustomCodeError = UnknownServerErrorCase(unknownServerError) val id: ShapeId = ShapeId("smithy4s.example", "CustomCodeError") @@ -535,12 +618,16 @@ object PizzaAdminServiceOperation { object UnknownServerErrorCase { val hints: Hints = Hints.empty - val schema: Schema[UnknownServerErrorCase] = bijection(UnknownServerError.schema.addHints(hints), UnknownServerErrorCase(_), _.unknownServerError) + val schema: Schema[CustomCodeError.UnknownServerErrorCase] = bijection(UnknownServerError.schema.addHints(hints), CustomCodeError.UnknownServerErrorCase(_), _.unknownServerError) val alt = schema.oneOf[CustomCodeError]("UnknownServerError") } + trait Visitor[A] { + def unknownServerError(value: UnknownServerError): A + } + implicit val schema: UnionSchema[CustomCodeError] = union( - UnknownServerErrorCase.alt, + CustomCodeError.UnknownServerErrorCase.alt, ){ _.$ordinal } diff --git a/modules/bootstrapped/src/generated/smithy4s/example/Podcast.scala b/modules/bootstrapped/src/generated/smithy4s/example/Podcast.scala index 8e00c103c..f479394d8 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/Podcast.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/Podcast.scala @@ -11,9 +11,19 @@ import smithy4s.schema.Schema.string import smithy4s.schema.Schema.struct import smithy4s.schema.Schema.union -sealed trait Podcast extends PodcastCommon with scala.Product with scala.Serializable { +sealed trait Podcast extends PodcastCommon with scala.Product with scala.Serializable { self => @inline final def widen: Podcast = this def $ordinal: Int + + object project { + def video: Option[Podcast.Video] = Podcast.Video.alt.project.lift(self) + def audio: Option[Podcast.Audio] = Podcast.Audio.alt.project.lift(self) + } + + def accept[A](visitor: Podcast.Visitor[A]): A = this match { + case value: Podcast.Video => visitor.video(value) + case value: Podcast.Audio => visitor.audio(value) + } } object Podcast extends ShapeTag.Companion[Podcast] { @@ -79,9 +89,14 @@ object Podcast extends ShapeTag.Companion[Podcast] { } + trait Visitor[A] { + def video(value: Podcast.Video): A + def audio(value: Podcast.Audio): A + } + implicit val schema: Schema[Podcast] = union( - Video.alt, - Audio.alt, + Podcast.Video.alt, + Podcast.Audio.alt, ){ _.$ordinal }.withId(id).addHints(hints) diff --git a/modules/bootstrapped/src/generated/smithy4s/example/TestAdt.scala b/modules/bootstrapped/src/generated/smithy4s/example/TestAdt.scala index 82b4fc7ce..17a69cc79 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/TestAdt.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/TestAdt.scala @@ -13,9 +13,19 @@ import smithy4s.schema.Schema.string import smithy4s.schema.Schema.struct import smithy4s.schema.Schema.union -sealed trait TestAdt extends AdtMixinOne with AdtMixinTwo with scala.Product with scala.Serializable { +sealed trait TestAdt extends AdtMixinOne with AdtMixinTwo with scala.Product with scala.Serializable { self => @inline final def widen: TestAdt = this def $ordinal: Int + + object project { + def one: Option[TestAdt.AdtOne] = TestAdt.AdtOne.alt.project.lift(self) + def two: Option[TestAdt.AdtTwo] = TestAdt.AdtTwo.alt.project.lift(self) + } + + def accept[A](visitor: TestAdt.Visitor[A]): A = this match { + case value: TestAdt.AdtOne => visitor.one(value) + case value: TestAdt.AdtTwo => visitor.two(value) + } } object TestAdt extends ShapeTag.Companion[TestAdt] { @@ -65,9 +75,14 @@ object TestAdt extends ShapeTag.Companion[TestAdt] { } + trait Visitor[A] { + def one(value: TestAdt.AdtOne): A + def two(value: TestAdt.AdtTwo): A + } + implicit val schema: Schema[TestAdt] = union( - AdtOne.alt, - AdtTwo.alt, + TestAdt.AdtOne.alt, + TestAdt.AdtTwo.alt, ){ _.$ordinal }.withId(id).addHints(hints) diff --git a/modules/bootstrapped/src/generated/smithy4s/example/TestBiggerUnion.scala b/modules/bootstrapped/src/generated/smithy4s/example/TestBiggerUnion.scala index ffe0f6740..c3afb5062 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/TestBiggerUnion.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/TestBiggerUnion.scala @@ -7,14 +7,24 @@ import smithy4s.ShapeTag import smithy4s.schema.Schema.bijection import smithy4s.schema.Schema.union -sealed trait TestBiggerUnion extends scala.Product with scala.Serializable { +sealed trait TestBiggerUnion extends scala.Product with scala.Serializable { self => @inline final def widen: TestBiggerUnion = this def $ordinal: Int + + object project { + def one: Option[One] = TestBiggerUnion.OneCase.alt.project.lift(self).map(_.one) + def two: Option[Two] = TestBiggerUnion.TwoCase.alt.project.lift(self).map(_.two) + } + + def accept[A](visitor: TestBiggerUnion.Visitor[A]): A = this match { + case value: TestBiggerUnion.OneCase => visitor.one(value.one) + case value: TestBiggerUnion.TwoCase => visitor.two(value.two) + } } object TestBiggerUnion extends ShapeTag.Companion[TestBiggerUnion] { - def one(one:One): TestBiggerUnion = OneCase(one) - def two(two:Two): TestBiggerUnion = TwoCase(two) + def one(one: One): TestBiggerUnion = OneCase(one) + def two(two: Two): TestBiggerUnion = TwoCase(two) val id: ShapeId = ShapeId("smithy4s.example", "TestBiggerUnion") @@ -27,18 +37,23 @@ object TestBiggerUnion extends ShapeTag.Companion[TestBiggerUnion] { object OneCase { val hints: Hints = Hints.empty - val schema: Schema[OneCase] = bijection(One.schema.addHints(hints), OneCase(_), _.one) + val schema: Schema[TestBiggerUnion.OneCase] = bijection(One.schema.addHints(hints), TestBiggerUnion.OneCase(_), _.one) val alt = schema.oneOf[TestBiggerUnion]("one") } object TwoCase { val hints: Hints = Hints.empty - val schema: Schema[TwoCase] = bijection(Two.schema.addHints(hints), TwoCase(_), _.two) + val schema: Schema[TestBiggerUnion.TwoCase] = bijection(Two.schema.addHints(hints), TestBiggerUnion.TwoCase(_), _.two) val alt = schema.oneOf[TestBiggerUnion]("two") } + trait Visitor[A] { + def one(value: One): A + def two(value: Two): A + } + implicit val schema: Schema[TestBiggerUnion] = union( - OneCase.alt, - TwoCase.alt, + TestBiggerUnion.OneCase.alt, + TestBiggerUnion.TwoCase.alt, ){ _.$ordinal }.withId(id).addHints(hints) diff --git a/modules/bootstrapped/src/generated/smithy4s/example/TestIdRefUnion.scala b/modules/bootstrapped/src/generated/smithy4s/example/TestIdRefUnion.scala index 3814cb036..d015bf151 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/TestIdRefUnion.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/TestIdRefUnion.scala @@ -8,14 +8,24 @@ import smithy4s.schema.Schema.bijection import smithy4s.schema.Schema.string import smithy4s.schema.Schema.union -sealed trait TestIdRefUnion extends scala.Product with scala.Serializable { +sealed trait TestIdRefUnion extends scala.Product with scala.Serializable { self => @inline final def widen: TestIdRefUnion = this def $ordinal: Int + + object project { + def test: Option[ShapeId] = TestIdRefUnion.TestCase.alt.project.lift(self).map(_.test) + def testTwo: Option[TestIdRefTwo] = TestIdRefUnion.TestTwoCase.alt.project.lift(self).map(_.testTwo) + } + + def accept[A](visitor: TestIdRefUnion.Visitor[A]): A = this match { + case value: TestIdRefUnion.TestCase => visitor.test(value.test) + case value: TestIdRefUnion.TestTwoCase => visitor.testTwo(value.testTwo) + } } object TestIdRefUnion extends ShapeTag.Companion[TestIdRefUnion] { - def test(test:ShapeId): TestIdRefUnion = TestCase(test) - def testTwo(testTwo:TestIdRefTwo): TestIdRefUnion = TestTwoCase(testTwo) + def test(test: ShapeId): TestIdRefUnion = TestCase(test) + def testTwo(testTwo: TestIdRefTwo): TestIdRefUnion = TestTwoCase(testTwo) val id: ShapeId = ShapeId("smithy4s.example", "TestIdRefUnion") @@ -26,18 +36,23 @@ object TestIdRefUnion extends ShapeTag.Companion[TestIdRefUnion] { object TestCase { val hints: Hints = Hints.empty - val schema: Schema[TestCase] = bijection(string.refined[ShapeId](smithy.api.IdRef(selector = "*", failWhenMissing = None, errorMessage = None)).addHints(hints), TestCase(_), _.test) + val schema: Schema[TestIdRefUnion.TestCase] = bijection(string.refined[ShapeId](smithy.api.IdRef(selector = "*", failWhenMissing = None, errorMessage = None)).addHints(hints), TestIdRefUnion.TestCase(_), _.test) val alt = schema.oneOf[TestIdRefUnion]("test") } object TestTwoCase { val hints: Hints = Hints.empty - val schema: Schema[TestTwoCase] = bijection(TestIdRefTwo.schema.addHints(hints), TestTwoCase(_), _.testTwo) + val schema: Schema[TestIdRefUnion.TestTwoCase] = bijection(TestIdRefTwo.schema.addHints(hints), TestIdRefUnion.TestTwoCase(_), _.testTwo) val alt = schema.oneOf[TestIdRefUnion]("testTwo") } + trait Visitor[A] { + def test(value: ShapeId): A + def testTwo(value: TestIdRefTwo): A + } + implicit val schema: Schema[TestIdRefUnion] = union( - TestCase.alt, - TestTwoCase.alt, + TestIdRefUnion.TestCase.alt, + TestIdRefUnion.TestTwoCase.alt, ){ _.$ordinal }.withId(id).addHints(hints) diff --git a/modules/bootstrapped/src/generated/smithy4s/example/TestMixinAdt.scala b/modules/bootstrapped/src/generated/smithy4s/example/TestMixinAdt.scala index 3431fdbe3..4e9463c40 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/TestMixinAdt.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/TestMixinAdt.scala @@ -9,9 +9,17 @@ import smithy4s.schema.Schema.string import smithy4s.schema.Schema.struct import smithy4s.schema.Schema.union -sealed trait TestMixinAdt extends scala.Product with scala.Serializable { +sealed trait TestMixinAdt extends scala.Product with scala.Serializable { self => @inline final def widen: TestMixinAdt = this def $ordinal: Int + + object project { + def test: Option[TestMixinAdt.TestAdtMemberWithMixin] = TestMixinAdt.TestAdtMemberWithMixin.alt.project.lift(self) + } + + def accept[A](visitor: TestMixinAdt.Visitor[A]): A = this match { + case value: TestMixinAdt.TestAdtMemberWithMixin => visitor.test(value) + } } object TestMixinAdt extends ShapeTag.Companion[TestMixinAdt] { @@ -40,8 +48,12 @@ object TestMixinAdt extends ShapeTag.Companion[TestMixinAdt] { } + trait Visitor[A] { + def test(value: TestMixinAdt.TestAdtMemberWithMixin): A + } + implicit val schema: Schema[TestMixinAdt] = union( - TestAdtMemberWithMixin.alt, + TestMixinAdt.TestAdtMemberWithMixin.alt, ){ _.$ordinal }.withId(id).addHints(hints) diff --git a/modules/bootstrapped/src/generated/smithy4s/example/UnionWithRefinedTypes.scala b/modules/bootstrapped/src/generated/smithy4s/example/UnionWithRefinedTypes.scala index 2b0f4548d..7be0dddf1 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/UnionWithRefinedTypes.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/UnionWithRefinedTypes.scala @@ -7,14 +7,24 @@ import smithy4s.ShapeTag import smithy4s.schema.Schema.bijection import smithy4s.schema.Schema.union -sealed trait UnionWithRefinedTypes extends scala.Product with scala.Serializable { +sealed trait UnionWithRefinedTypes extends scala.Product with scala.Serializable { self => @inline final def widen: UnionWithRefinedTypes = this def $ordinal: Int + + object project { + def age: Option[Age] = UnionWithRefinedTypes.AgeCase.alt.project.lift(self).map(_.age) + def dogName: Option[smithy4s.refined.Name] = UnionWithRefinedTypes.DogNameCase.alt.project.lift(self).map(_.dogName) + } + + def accept[A](visitor: UnionWithRefinedTypes.Visitor[A]): A = this match { + case value: UnionWithRefinedTypes.AgeCase => visitor.age(value.age) + case value: UnionWithRefinedTypes.DogNameCase => visitor.dogName(value.dogName) + } } object UnionWithRefinedTypes extends ShapeTag.Companion[UnionWithRefinedTypes] { - def age(age:Age): UnionWithRefinedTypes = AgeCase(age) - def dogName(dogName:smithy4s.refined.Name): UnionWithRefinedTypes = DogNameCase(dogName) + def age(age: Age): UnionWithRefinedTypes = AgeCase(age) + def dogName(dogName: smithy4s.refined.Name): UnionWithRefinedTypes = DogNameCase(dogName) val id: ShapeId = ShapeId("smithy4s.example", "UnionWithRefinedTypes") @@ -25,18 +35,23 @@ object UnionWithRefinedTypes extends ShapeTag.Companion[UnionWithRefinedTypes] { object AgeCase { val hints: Hints = Hints.empty - val schema: Schema[AgeCase] = bijection(Age.schema.addHints(hints), AgeCase(_), _.age) + val schema: Schema[UnionWithRefinedTypes.AgeCase] = bijection(Age.schema.addHints(hints), UnionWithRefinedTypes.AgeCase(_), _.age) val alt = schema.oneOf[UnionWithRefinedTypes]("age") } object DogNameCase { val hints: Hints = Hints.empty - val schema: Schema[DogNameCase] = bijection(DogName.underlyingSchema.addHints(hints), DogNameCase(_), _.dogName) + val schema: Schema[UnionWithRefinedTypes.DogNameCase] = bijection(DogName.underlyingSchema.addHints(hints), UnionWithRefinedTypes.DogNameCase(_), _.dogName) val alt = schema.oneOf[UnionWithRefinedTypes]("dogName") } + trait Visitor[A] { + def age(value: Age): A + def dogName(value: smithy4s.refined.Name): A + } + implicit val schema: Schema[UnionWithRefinedTypes] = union( - AgeCase.alt, - DogNameCase.alt, + UnionWithRefinedTypes.AgeCase.alt, + UnionWithRefinedTypes.DogNameCase.alt, ){ _.$ordinal }.withId(id).addHints(hints) diff --git a/modules/bootstrapped/src/generated/smithy4s/example/UntaggedUnion.scala b/modules/bootstrapped/src/generated/smithy4s/example/UntaggedUnion.scala index 895cd5ac4..00d6a9727 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/UntaggedUnion.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/UntaggedUnion.scala @@ -7,14 +7,24 @@ import smithy4s.ShapeTag import smithy4s.schema.Schema.bijection import smithy4s.schema.Schema.union -sealed trait UntaggedUnion extends scala.Product with scala.Serializable { +sealed trait UntaggedUnion extends scala.Product with scala.Serializable { self => @inline final def widen: UntaggedUnion = this def $ordinal: Int + + object project { + def three: Option[Three] = UntaggedUnion.ThreeCase.alt.project.lift(self).map(_.three) + def four: Option[Four] = UntaggedUnion.FourCase.alt.project.lift(self).map(_.four) + } + + def accept[A](visitor: UntaggedUnion.Visitor[A]): A = this match { + case value: UntaggedUnion.ThreeCase => visitor.three(value.three) + case value: UntaggedUnion.FourCase => visitor.four(value.four) + } } object UntaggedUnion extends ShapeTag.Companion[UntaggedUnion] { - def three(three:Three): UntaggedUnion = ThreeCase(three) - def four(four:Four): UntaggedUnion = FourCase(four) + def three(three: Three): UntaggedUnion = ThreeCase(three) + def four(four: Four): UntaggedUnion = FourCase(four) val id: ShapeId = ShapeId("smithy4s.example", "UntaggedUnion") @@ -27,18 +37,23 @@ object UntaggedUnion extends ShapeTag.Companion[UntaggedUnion] { object ThreeCase { val hints: Hints = Hints.empty - val schema: Schema[ThreeCase] = bijection(Three.schema.addHints(hints), ThreeCase(_), _.three) + val schema: Schema[UntaggedUnion.ThreeCase] = bijection(Three.schema.addHints(hints), UntaggedUnion.ThreeCase(_), _.three) val alt = schema.oneOf[UntaggedUnion]("three") } object FourCase { val hints: Hints = Hints.empty - val schema: Schema[FourCase] = bijection(Four.schema.addHints(hints), FourCase(_), _.four) + val schema: Schema[UntaggedUnion.FourCase] = bijection(Four.schema.addHints(hints), UntaggedUnion.FourCase(_), _.four) val alt = schema.oneOf[UntaggedUnion]("four") } + trait Visitor[A] { + def three(value: Three): A + def four(value: Four): A + } + implicit val schema: Schema[UntaggedUnion] = union( - ThreeCase.alt, - FourCase.alt, + UntaggedUnion.ThreeCase.alt, + UntaggedUnion.FourCase.alt, ){ _.$ordinal }.withId(id).addHints(hints) diff --git a/modules/bootstrapped/src/generated/smithy4s/example/Weather.scala b/modules/bootstrapped/src/generated/smithy4s/example/Weather.scala index 55adccd22..17af071b2 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/Weather.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/Weather.scala @@ -134,13 +134,21 @@ object WeatherOperation { case GetCityError.NoSuchResourceCase(e) => e } } - sealed trait GetCityError extends scala.Product with scala.Serializable { + sealed trait GetCityError extends scala.Product with scala.Serializable { self => @inline final def widen: GetCityError = this def $ordinal: Int + + object project { + def noSuchResource: Option[NoSuchResource] = GetCityError.NoSuchResourceCase.alt.project.lift(self).map(_.noSuchResource) + } + + def accept[A](visitor: GetCityError.Visitor[A]): A = this match { + case value: GetCityError.NoSuchResourceCase => visitor.noSuchResource(value.noSuchResource) + } } object GetCityError extends ShapeTag.Companion[GetCityError] { - def noSuchResource(noSuchResource:NoSuchResource): GetCityError = NoSuchResourceCase(noSuchResource) + def noSuchResource(noSuchResource: NoSuchResource): GetCityError = NoSuchResourceCase(noSuchResource) val id: ShapeId = ShapeId("smithy4s.example", "GetCityError") @@ -150,12 +158,16 @@ object WeatherOperation { object NoSuchResourceCase { val hints: Hints = Hints.empty - val schema: Schema[NoSuchResourceCase] = bijection(NoSuchResource.schema.addHints(hints), NoSuchResourceCase(_), _.noSuchResource) + val schema: Schema[GetCityError.NoSuchResourceCase] = bijection(NoSuchResource.schema.addHints(hints), GetCityError.NoSuchResourceCase(_), _.noSuchResource) val alt = schema.oneOf[GetCityError]("NoSuchResource") } + trait Visitor[A] { + def noSuchResource(value: NoSuchResource): A + } + implicit val schema: UnionSchema[GetCityError] = union( - NoSuchResourceCase.alt, + GetCityError.NoSuchResourceCase.alt, ){ _.$ordinal } diff --git a/modules/bootstrapped/src/generated/smithy4s/example/guides/auth/HelloWorldAuthService.scala b/modules/bootstrapped/src/generated/smithy4s/example/guides/auth/HelloWorldAuthService.scala index bd5e54b7e..2a9aebe83 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/guides/auth/HelloWorldAuthService.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/guides/auth/HelloWorldAuthService.scala @@ -111,13 +111,21 @@ object HelloWorldAuthServiceOperation { case SayWorldError.NotAuthorizedErrorCase(e) => e } } - sealed trait SayWorldError extends scala.Product with scala.Serializable { + sealed trait SayWorldError extends scala.Product with scala.Serializable { self => @inline final def widen: SayWorldError = this def $ordinal: Int + + object project { + def notAuthorizedError: Option[NotAuthorizedError] = SayWorldError.NotAuthorizedErrorCase.alt.project.lift(self).map(_.notAuthorizedError) + } + + def accept[A](visitor: SayWorldError.Visitor[A]): A = this match { + case value: SayWorldError.NotAuthorizedErrorCase => visitor.notAuthorizedError(value.notAuthorizedError) + } } object SayWorldError extends ShapeTag.Companion[SayWorldError] { - def notAuthorizedError(notAuthorizedError:NotAuthorizedError): SayWorldError = NotAuthorizedErrorCase(notAuthorizedError) + def notAuthorizedError(notAuthorizedError: NotAuthorizedError): SayWorldError = NotAuthorizedErrorCase(notAuthorizedError) val id: ShapeId = ShapeId("smithy4s.example.guides.auth", "SayWorldError") @@ -127,12 +135,16 @@ object HelloWorldAuthServiceOperation { object NotAuthorizedErrorCase { val hints: Hints = Hints.empty - val schema: Schema[NotAuthorizedErrorCase] = bijection(NotAuthorizedError.schema.addHints(hints), NotAuthorizedErrorCase(_), _.notAuthorizedError) + val schema: Schema[SayWorldError.NotAuthorizedErrorCase] = bijection(NotAuthorizedError.schema.addHints(hints), SayWorldError.NotAuthorizedErrorCase(_), _.notAuthorizedError) val alt = schema.oneOf[SayWorldError]("NotAuthorizedError") } + trait Visitor[A] { + def notAuthorizedError(value: NotAuthorizedError): A + } + implicit val schema: UnionSchema[SayWorldError] = union( - NotAuthorizedErrorCase.alt, + SayWorldError.NotAuthorizedErrorCase.alt, ){ _.$ordinal } @@ -165,13 +177,21 @@ object HelloWorldAuthServiceOperation { case HealthCheckError.NotAuthorizedErrorCase(e) => e } } - sealed trait HealthCheckError extends scala.Product with scala.Serializable { + sealed trait HealthCheckError extends scala.Product with scala.Serializable { self => @inline final def widen: HealthCheckError = this def $ordinal: Int + + object project { + def notAuthorizedError: Option[NotAuthorizedError] = HealthCheckError.NotAuthorizedErrorCase.alt.project.lift(self).map(_.notAuthorizedError) + } + + def accept[A](visitor: HealthCheckError.Visitor[A]): A = this match { + case value: HealthCheckError.NotAuthorizedErrorCase => visitor.notAuthorizedError(value.notAuthorizedError) + } } object HealthCheckError extends ShapeTag.Companion[HealthCheckError] { - def notAuthorizedError(notAuthorizedError:NotAuthorizedError): HealthCheckError = NotAuthorizedErrorCase(notAuthorizedError) + def notAuthorizedError(notAuthorizedError: NotAuthorizedError): HealthCheckError = NotAuthorizedErrorCase(notAuthorizedError) val id: ShapeId = ShapeId("smithy4s.example.guides.auth", "HealthCheckError") @@ -181,12 +201,16 @@ object HelloWorldAuthServiceOperation { object NotAuthorizedErrorCase { val hints: Hints = Hints.empty - val schema: Schema[NotAuthorizedErrorCase] = bijection(NotAuthorizedError.schema.addHints(hints), NotAuthorizedErrorCase(_), _.notAuthorizedError) + val schema: Schema[HealthCheckError.NotAuthorizedErrorCase] = bijection(NotAuthorizedError.schema.addHints(hints), HealthCheckError.NotAuthorizedErrorCase(_), _.notAuthorizedError) val alt = schema.oneOf[HealthCheckError]("NotAuthorizedError") } + trait Visitor[A] { + def notAuthorizedError(value: NotAuthorizedError): A + } + implicit val schema: UnionSchema[HealthCheckError] = union( - NotAuthorizedErrorCase.alt, + HealthCheckError.NotAuthorizedErrorCase.alt, ){ _.$ordinal } diff --git a/modules/bootstrapped/src/generated/smithy4s/example/hello/HelloWorldService.scala b/modules/bootstrapped/src/generated/smithy4s/example/hello/HelloWorldService.scala index 1cfcd6c3e..3a28b49c1 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/hello/HelloWorldService.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/hello/HelloWorldService.scala @@ -105,14 +105,24 @@ object HelloWorldServiceOperation { case HelloError.SpecificServerErrorCase(e) => e } } - sealed trait HelloError extends scala.Product with scala.Serializable { + sealed trait HelloError extends scala.Product with scala.Serializable { self => @inline final def widen: HelloError = this def $ordinal: Int + + object project { + def genericServerError: Option[GenericServerError] = HelloError.GenericServerErrorCase.alt.project.lift(self).map(_.genericServerError) + def specificServerError: Option[SpecificServerError] = HelloError.SpecificServerErrorCase.alt.project.lift(self).map(_.specificServerError) + } + + def accept[A](visitor: HelloError.Visitor[A]): A = this match { + case value: HelloError.GenericServerErrorCase => visitor.genericServerError(value.genericServerError) + case value: HelloError.SpecificServerErrorCase => visitor.specificServerError(value.specificServerError) + } } object HelloError extends ShapeTag.Companion[HelloError] { - def genericServerError(genericServerError:GenericServerError): HelloError = GenericServerErrorCase(genericServerError) - def specificServerError(specificServerError:SpecificServerError): HelloError = SpecificServerErrorCase(specificServerError) + def genericServerError(genericServerError: GenericServerError): HelloError = GenericServerErrorCase(genericServerError) + def specificServerError(specificServerError: SpecificServerError): HelloError = SpecificServerErrorCase(specificServerError) val id: ShapeId = ShapeId("smithy4s.example.hello", "HelloError") @@ -123,18 +133,23 @@ object HelloWorldServiceOperation { object GenericServerErrorCase { val hints: Hints = Hints.empty - val schema: Schema[GenericServerErrorCase] = bijection(GenericServerError.schema.addHints(hints), GenericServerErrorCase(_), _.genericServerError) + val schema: Schema[HelloError.GenericServerErrorCase] = bijection(GenericServerError.schema.addHints(hints), HelloError.GenericServerErrorCase(_), _.genericServerError) val alt = schema.oneOf[HelloError]("GenericServerError") } object SpecificServerErrorCase { val hints: Hints = Hints.empty - val schema: Schema[SpecificServerErrorCase] = bijection(SpecificServerError.schema.addHints(hints), SpecificServerErrorCase(_), _.specificServerError) + val schema: Schema[HelloError.SpecificServerErrorCase] = bijection(SpecificServerError.schema.addHints(hints), HelloError.SpecificServerErrorCase(_), _.specificServerError) val alt = schema.oneOf[HelloError]("SpecificServerError") } + trait Visitor[A] { + def genericServerError(value: GenericServerError): A + def specificServerError(value: SpecificServerError): A + } + implicit val schema: UnionSchema[HelloError] = union( - GenericServerErrorCase.alt, - SpecificServerErrorCase.alt, + HelloError.GenericServerErrorCase.alt, + HelloError.SpecificServerErrorCase.alt, ){ _.$ordinal } diff --git a/modules/bootstrapped/src/generated/smithy4s/example/imp/ImportService.scala b/modules/bootstrapped/src/generated/smithy4s/example/imp/ImportService.scala index 4f7302ac5..e803523a4 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/imp/ImportService.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/imp/ImportService.scala @@ -105,13 +105,21 @@ object ImportServiceOperation { case ImportOperationError.NotFoundErrorCase(e) => e } } - sealed trait ImportOperationError extends scala.Product with scala.Serializable { + sealed trait ImportOperationError extends scala.Product with scala.Serializable { self => @inline final def widen: ImportOperationError = this def $ordinal: Int + + object project { + def notFoundError: Option[NotFoundError] = ImportOperationError.NotFoundErrorCase.alt.project.lift(self).map(_.notFoundError) + } + + def accept[A](visitor: ImportOperationError.Visitor[A]): A = this match { + case value: ImportOperationError.NotFoundErrorCase => visitor.notFoundError(value.notFoundError) + } } object ImportOperationError extends ShapeTag.Companion[ImportOperationError] { - def notFoundError(notFoundError:NotFoundError): ImportOperationError = NotFoundErrorCase(notFoundError) + def notFoundError(notFoundError: NotFoundError): ImportOperationError = NotFoundErrorCase(notFoundError) val id: ShapeId = ShapeId("smithy4s.example.imp", "ImportOperationError") @@ -121,12 +129,16 @@ object ImportServiceOperation { object NotFoundErrorCase { val hints: Hints = Hints.empty - val schema: Schema[NotFoundErrorCase] = bijection(NotFoundError.schema.addHints(hints), NotFoundErrorCase(_), _.notFoundError) + val schema: Schema[ImportOperationError.NotFoundErrorCase] = bijection(NotFoundError.schema.addHints(hints), ImportOperationError.NotFoundErrorCase(_), _.notFoundError) val alt = schema.oneOf[ImportOperationError]("NotFoundError") } + trait Visitor[A] { + def notFoundError(value: NotFoundError): A + } + implicit val schema: UnionSchema[ImportOperationError] = union( - NotFoundErrorCase.alt, + ImportOperationError.NotFoundErrorCase.alt, ){ _.$ordinal } diff --git a/modules/bootstrapped/src/generated/smithy4s/example/test/HelloService.scala b/modules/bootstrapped/src/generated/smithy4s/example/test/HelloService.scala index c49d2590b..9d46a2516 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/test/HelloService.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/test/HelloService.scala @@ -114,14 +114,24 @@ object HelloServiceOperation { case SayHelloError.ComplexErrorCase(e) => e } } - sealed trait SayHelloError extends scala.Product with scala.Serializable { + sealed trait SayHelloError extends scala.Product with scala.Serializable { self => @inline final def widen: SayHelloError = this def $ordinal: Int + + object project { + def simpleError: Option[SimpleError] = SayHelloError.SimpleErrorCase.alt.project.lift(self).map(_.simpleError) + def complexError: Option[ComplexError] = SayHelloError.ComplexErrorCase.alt.project.lift(self).map(_.complexError) + } + + def accept[A](visitor: SayHelloError.Visitor[A]): A = this match { + case value: SayHelloError.SimpleErrorCase => visitor.simpleError(value.simpleError) + case value: SayHelloError.ComplexErrorCase => visitor.complexError(value.complexError) + } } object SayHelloError extends ShapeTag.Companion[SayHelloError] { - def simpleError(simpleError:SimpleError): SayHelloError = SimpleErrorCase(simpleError) - def complexError(complexError:ComplexError): SayHelloError = ComplexErrorCase(complexError) + def simpleError(simpleError: SimpleError): SayHelloError = SimpleErrorCase(simpleError) + def complexError(complexError: ComplexError): SayHelloError = ComplexErrorCase(complexError) val id: ShapeId = ShapeId("smithy4s.example.test", "SayHelloError") @@ -132,18 +142,23 @@ object HelloServiceOperation { object SimpleErrorCase { val hints: Hints = Hints.empty - val schema: Schema[SimpleErrorCase] = bijection(SimpleError.schema.addHints(hints), SimpleErrorCase(_), _.simpleError) + val schema: Schema[SayHelloError.SimpleErrorCase] = bijection(SimpleError.schema.addHints(hints), SayHelloError.SimpleErrorCase(_), _.simpleError) val alt = schema.oneOf[SayHelloError]("SimpleError") } object ComplexErrorCase { val hints: Hints = Hints.empty - val schema: Schema[ComplexErrorCase] = bijection(ComplexError.schema.addHints(hints), ComplexErrorCase(_), _.complexError) + val schema: Schema[SayHelloError.ComplexErrorCase] = bijection(ComplexError.schema.addHints(hints), SayHelloError.ComplexErrorCase(_), _.complexError) val alt = schema.oneOf[SayHelloError]("ComplexError") } + trait Visitor[A] { + def simpleError(value: SimpleError): A + def complexError(value: ComplexError): A + } + implicit val schema: UnionSchema[SayHelloError] = union( - SimpleErrorCase.alt, - ComplexErrorCase.alt, + SayHelloError.SimpleErrorCase.alt, + SayHelloError.ComplexErrorCase.alt, ){ _.$ordinal } diff --git a/modules/bootstrapped/test/src/smithy4s/VisitorAndProjectionSpec.scala b/modules/bootstrapped/test/src/smithy4s/VisitorAndProjectionSpec.scala new file mode 100644 index 000000000..8ff7b51d6 --- /dev/null +++ b/modules/bootstrapped/test/src/smithy4s/VisitorAndProjectionSpec.scala @@ -0,0 +1,56 @@ +package smithy4s + +import munit._ +import smithy4s.example._ + +final class VisitorAndProjectionSpec extends FunSuite { + + test("visitor") { + val visitor = new OrderType.Visitor[String] { + def online(value: OrderNumber): String = s"ONLINE ${value.value}" + def inStore(value: OrderType.InStoreOrder): String = s"IN STORE $value" + def preview(value: OrderType.PreviewCase.type): String = "PREVIEW" + } + assertEquals( + OrderType.OnlineCase(OrderNumber(123)).accept(visitor), + "ONLINE 123" + ) + assertEquals( + OrderType.InStoreOrder(OrderNumber(2)).accept(visitor), + "IN STORE InStoreOrder(2,None)" + ) + assertEquals( + OrderType.PreviewCase.accept(visitor), + "PREVIEW" + ) + } + + test("projections") { + val one = OrderType.OnlineCase(OrderNumber(123)) + val two = OrderType.InStoreOrder(OrderNumber(2)) + val three = OrderType.PreviewCase + + assertEquals( + one.widen.project.online, + Option(one.online) + ) + assertEquals( + two.widen.project.inStore, + Option(two) + ) + assertEquals( + three.widen.project.preview, + Option(three) + ) + + assertEquals( + two.widen.project.online, + None + ) + assertEquals( + three.widen.project.online, + None + ) + } + +} diff --git a/modules/codegen/src/smithy4s/codegen/internals/LineSegment.scala b/modules/codegen/src/smithy4s/codegen/internals/LineSegment.scala index 6b1f0be7f..95e6258c8 100644 --- a/modules/codegen/src/smithy4s/codegen/internals/LineSegment.scala +++ b/modules/codegen/src/smithy4s/codegen/internals/LineSegment.scala @@ -50,6 +50,14 @@ private[codegen] object LineSegment { ) extends LineSegment { self => + def nameDef: NameDef = NameDef(name) + + def down(name: String): NameRef = this.copy( + rawPkg = rawPkg :+ this.name, + name = name, + typeParams = List.empty + ) + def pkg: List[String] = rawPkg.map(CollisionAvoidance.protectKeyword(_)) def asValue: String = s"${(pkg :+ name).mkString(".")}" diff --git a/modules/codegen/src/smithy4s/codegen/internals/PartialBlock.scala b/modules/codegen/src/smithy4s/codegen/internals/PartialBlock.scala index 6ddffb391..d73595196 100644 --- a/modules/codegen/src/smithy4s/codegen/internals/PartialBlock.scala +++ b/modules/codegen/src/smithy4s/codegen/internals/PartialBlock.scala @@ -19,14 +19,17 @@ package smithy4s.codegen.internals import cats.syntax.all._ import smithy4s.codegen.internals.LineSegment.Literal -private[internals] class PartialBlock(l: Line) { +private[internals] class PartialBlock(l: Line, sameLine: Line = Line.empty) { def apply[A](inner: A)(implicit A: ToLines[A]): Lines = { A.render(inner) .transformLines(lines => - (l + Literal(" {")) :: indent(lines) ::: List(Line("}")) + (l + Literal(" {") + sameLine) :: indent(lines) ::: List(Line("}")) ) } + def withSameLineValue(value: Line): PartialBlock = + new PartialBlock(l, value) + def apply(inner: LinesWithValue*): Lines = apply(inner.toList.foldMap(_.render)) diff --git a/modules/codegen/src/smithy4s/codegen/internals/Renderer.scala b/modules/codegen/src/smithy4s/codegen/internals/Renderer.scala index 85a20e0eb..0c9151644 100644 --- a/modules/codegen/src/smithy4s/codegen/internals/Renderer.scala +++ b/modules/codegen/src/smithy4s/codegen/internals/Renderer.scala @@ -892,11 +892,47 @@ private[internals] class Renderer(compilationUnit: CompilationUnit) { self => ) } - private def caseName(alt: Alt): NameRef = alt.member match { - case UnionMember.ProductCase(product) => NameRef(product.name) - case UnionMember.TypeCase(_) | UnionMember.UnitCase => - NameRef(alt.name.dropWhile(_ == '_').capitalize + "Case") - } + private def caseName(unionName: NameRef, alt: Alt): NameRef = + alt.member match { + case UnionMember.ProductCase(product) => + unionName.down(product.name) + case UnionMember.TypeCase(_) | UnionMember.UnitCase => + unionName.down( + alt.name.dropWhile(_ == '_').capitalize + "Case" + ) + } + + private def caseNameForMatch(unionName: NameRef, alt: Alt): NameRef = + alt.member match { + case UnionMember.ProductCase(product) => + unionName.down(product.name) + case UnionMember.TypeCase(_) => + unionName.down(alt.name.dropWhile(_ == '_').capitalize + "Case") + case UnionMember.UnitCase => + unionName.down(alt.name.dropWhile(_ == '_').capitalize + "Case.type") + } + + private def caseNameType(unionName: NameRef, alt: Alt): Line = + alt.member match { + case UnionMember.ProductCase(product) => + line"${unionName.down(product.name)}" + case UnionMember.TypeCase(tpe) => line"$tpe" + case UnionMember.UnitCase => + line"${unionName.down(alt.name.dropWhile(_ == '_').capitalize + "Case.type")}" + } + + private def caseNameWithAlt(unionName: NameRef, alt: Alt): Line = + alt.member match { + case UnionMember.ProductCase(product) => + line"${unionName.down(product.name)}.alt" + case UnionMember.TypeCase(_) => + val n = unionName.down(alt.name.dropWhile(_ == '_').capitalize + "Case") + line"$n.alt" + case UnionMember.UnitCase => + val n = + unionName.down(alt.name.dropWhile(_ == '_').capitalize + "CaseAlt") + line"$n" + } private def renderPrisms( unionName: NameRef, @@ -914,10 +950,11 @@ private[internals] class Renderer(compilationUnit: CompilationUnit) { self => val (mat, tpe) = (p.nameDef, line"${p.name}") line"val ${alt.name}: $smithyPrism[$unionName, $tpe] = $smithyPrism.partial[$unionName, $tpe]{ case t: $mat => t }(identity)" case UnionMember.TypeCase(t) => - val (mat, tpe) = (caseName(alt), line"$t") + val (mat, tpe) = (caseName(unionName, alt), line"$t") line"val ${alt.name}: $smithyPrism[$unionName, $tpe] = $smithyPrism.partial[$unionName, $tpe]{ case $mat(t) => t }($mat.apply)" case UnionMember.UnitCase => - val (mat, tpe) = (caseName(alt), line"${caseName(alt)}") + val (mat, tpe) = + (caseName(unionName, alt), line"${caseName(unionName, alt)}") line"val ${alt.name}: $smithyPrism[$unionName, $tpe.type] = $smithyPrism.partial[$unionName, $tpe.type]{ case t: $mat.type => t }(identity)" } } @@ -962,7 +999,7 @@ private[internals] class Renderer(compilationUnit: CompilationUnit) { self => error: Boolean = false ): Lines = { def smartConstructor(alt: Alt): Lines = { - val cn = caseName(alt).name + val cn = caseName(name, alt).name val ident = NameDef(uncapitalise(alt.name)) val prefix = line"def $ident" val constructor = alt.member match { @@ -970,9 +1007,10 @@ private[internals] class Renderer(compilationUnit: CompilationUnit) { self => val args = renderArgs(product.fields) val values = product.fields.map(_.name).intercalate(", ") line"def ${uncapitalise(product.nameDef.name)}($args):${product.nameRef} = ${product.nameRef}($values)" - case UnionMember.UnitCase => line"$prefix(): $name = ${caseName(alt)}" + case UnionMember.UnitCase => + line"$prefix(): $name = ${caseName(name, alt)}" case UnionMember.TypeCase(tpe) => - line"$prefix($ident:$tpe): $name = $cn($ident)" + line"$prefix($ident: $tpe): $name = $cn($ident)" } lines( documentationAnnotation(alt.hints), @@ -980,7 +1018,7 @@ private[internals] class Renderer(compilationUnit: CompilationUnit) { self => constructor ) } - val caseNames = alts.map(caseName) + val caseNames = alts.map(caseName(name, _)) val caseNamesAndIsUnit = caseNames.zip(alts.map(_.member == UnionMember.UnitCase)) @@ -989,14 +1027,45 @@ private[internals] class Renderer(compilationUnit: CompilationUnit) { self => val mixinExtendsStatement = if (mixinExtends.segments.isEmpty) Line.empty else line"$mixinExtends with " + val projectors: Lines = obj(NameRef("project"))( + alts.map { alt => + val ident = NameDef(uncapitalise(alt.name)) + val maybeMap = alt.member match { + case UnionMember.TypeCase(_) => line".map(_.$ident)" + case _ => Line.empty + } + line"def $ident: Option[${caseNameType(name, alt)}] = ${caseNameWithAlt(name, alt)}.project.lift(self)$maybeMap" + } + ) + val visitor: Lines = block(line"trait Visitor[A]")( + alts.map { alt => + val ident = NameDef(uncapitalise(alt.name)) + line"def $ident(value: ${caseNameType(name, alt)}): A" + } + ) + val accept: Lines = + block(line"def accept[A](visitor: $name.Visitor[A]): A = this match")( + alts.map { alt => + val ident = NameDef(uncapitalise(alt.name)) + val innerValue = alt.member match { + case UnionMember.TypeCase(_) => line".$ident" + case _ => Line.empty + } + line"case value: ${caseNameForMatch(name, alt)} => visitor.$ident(value$innerValue)" + } + ) lines( documentationAnnotation(hints), deprecationAnnotation(hints), block( line"sealed trait ${NameDef(name.name)} extends ${mixinExtendsStatement}scala.Product with scala.Serializable" - )( + ).withSameLineValue(line" self =>")( line"@inline final def widen: $name = this", - line"def $$ordinal: Int" + line"def $$ordinal: Int", + newline, + projectors, + newline, + accept ), obj(name, line"${shapeTag(name)}")( newline, @@ -1009,24 +1078,24 @@ private[internals] class Renderer(compilationUnit: CompilationUnit) { self => renderPrisms(name, alts, hints), alts.zipWithIndex.map { case (a @ Alt(_, realName, UnionMember.UnitCase, altHints), index) => - val cn = caseName(a) + val cn = caseName(name, a) // format: off lines( documentationAnnotation(altHints), deprecationAnnotation(altHints), - line"case object $cn extends $name { final def $$ordinal: Int = $index }", - line"""private val ${cn}Alt = $Schema_.constant($cn)${renderConstraintValidation(altHints)}.oneOf[$name]("$realName").addHints(hints)""", + line"case object ${cn.nameDef} extends $name { final def $$ordinal: Int = $index }", + line"""private val ${cn.nameDef}Alt = $Schema_.constant($cn)${renderConstraintValidation(altHints)}.oneOf[$name]("$realName").addHints(hints)""", ) // format: on case ( a @ Alt(altName, _, UnionMember.TypeCase(tpe), altHints), index ) => - val cn = caseName(a) + val cn = caseName(name, a) lines( documentationAnnotation(altHints), deprecationAnnotation(altHints), - line"final case class $cn(${uncapitalise(altName)}: $tpe) extends $name { final def $$ordinal: Int = $index }" + line"final case class ${cn.nameDef}(${uncapitalise(altName)}: $tpe) extends $name { final def $$ordinal: Int = $index }" ) case ( Alt(_, realName, UnionMember.ProductCase(struct), altHints), @@ -1055,8 +1124,8 @@ private[internals] class Renderer(compilationUnit: CompilationUnit) { self => UnionMember.TypeCase(tpe), altHints ) => - val cn = caseName(a) - block(line"object $cn")( + val cn = caseName(name, a) + block(line"object ${cn.nameDef}")( renderHintsVal(altHints), // format: off line"val schema: $Schema_[$cn] = $bijection_(${tpe.schemaRef}.addHints(hints)${renderConstraintValidation(altHints)}, $cn(_), _.${uncapitalise(altName)})", @@ -1064,6 +1133,8 @@ private[internals] class Renderer(compilationUnit: CompilationUnit) { self => // format: on ) }, + newline, + visitor, newline, { val union = if (error) diff --git a/modules/docs/markdown/04-codegen/02-unions.md b/modules/docs/markdown/04-codegen/02-unions.md index 2155f82f5..8586a08b4 100644 --- a/modules/docs/markdown/04-codegen/02-unions.md +++ b/modules/docs/markdown/04-codegen/02-unions.md @@ -148,3 +148,67 @@ are encoded as such { "tpe": "first", "string": "smithy4s" } { "tpe": "second", "int": 42 } ``` + +## Union Projections and Visitors + +In order to make working with unions more ergonomic, smithy4s provides projection functions and generates visitors for all unions. + +#### Projection Functions + +Here we will see what a projection function looks like using a simple union example of `Pet`. + +```scala +sealed trait Pet { + object project { + def dog: Option[Dog] + def cat: Option[Cat] + } +} +object Pet { + case class DogCase(dog: Dog) extends Pet + case class CatCase(cat: Cat) extends Pet +} +``` + +These functions can then be used as follows: + +```scala +val myPet: Pet = Pet.DogCase(Dog(name = "Spot")) + +myPet.project.dog // Some(Dog(name = "Spot")) +myPet.project.cat // None +``` + +These projection functions make it so you can work with specific union alternatives without needing to do any pattern matching. + +#### Visitors + +Using the same pet example, we will now see what the visitors look like that smithy4s generates. + +```scala +sealed trait Pet { + def accept[A](visitor: Pet.Visitor[A]): A = // ... +} +object Pet { + case class DogCase(dog: Dog) extends Pet + case class CatCase(cat: Cat) extends Pet + + trait Visitor[A] { + def dog(dog: Dog): A + def cat(cat: Cat): A + } +} +``` + +Similar to the projection functions, the visitor allows us to handle the alternatives without a pattern match. For example: + +```scala +val myPet: Pet = Pet.DogCase(Dog(name = "Spot")) + +val visitor = new Pet.Visitor[String] { + def dog(dog: Dog): String = s"Dog named ${dog.name}" + def cat(cat: Cat): String = s"Cat named ${cat.name}" +} + +myPet.accept(visitor) // "Dog named Spot" +``` From f35e1fb98116638efcd4e904fb30ad39d950b766 Mon Sep 17 00:00:00 2001 From: Jeff Lewis Date: Thu, 10 Aug 2023 16:56:08 -0600 Subject: [PATCH 2/3] fix codegen tests --- .../internals/RendererConfigSpec.scala | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/modules/codegen/test/src/smithy4s/codegen/internals/RendererConfigSpec.scala b/modules/codegen/test/src/smithy4s/codegen/internals/RendererConfigSpec.scala index 49ec3212a..9354984c1 100644 --- a/modules/codegen/test/src/smithy4s/codegen/internals/RendererConfigSpec.scala +++ b/modules/codegen/test/src/smithy4s/codegen/internals/RendererConfigSpec.scala @@ -243,33 +243,45 @@ final class RendererConfigSpec extends munit.FunSuite { ) assertContainsSection(serviceCode, "sealed trait OperationError")( - """|sealed trait OperationError extends scala.Product with scala.Serializable { + """|sealed trait OperationError extends scala.Product with scala.Serializable { self => | @inline final def widen: OperationError = this | def $ordinal: Int + | object project { + | def badRequest: Option[BadRequest] = OperationError.BadRequestCase.alt.project.lift(self).map(_.badRequest) + | def internalServerError: Option[InternalServerError] = OperationError.InternalServerErrorCase.alt.project.lift(self).map(_.internalServerError) + | } + | def accept[A](visitor: OperationError.Visitor[A]): A = this match { + | case value: OperationError.BadRequestCase => visitor.badRequest(value.badRequest) + | case value: OperationError.InternalServerErrorCase => visitor.internalServerError(value.internalServerError) + | } |}""".stripMargin ) assertContainsSection(serviceCode, "object OperationError")( """|object OperationError extends ShapeTag.Companion[OperationError] { - | def badRequest(badRequest:BadRequest): OperationError = BadRequestCase(badRequest) - | def internalServerError(internalServerError:InternalServerError): OperationError = InternalServerErrorCase(internalServerError) + | def badRequest(badRequest: BadRequest): OperationError = BadRequestCase(badRequest) + | def internalServerError(internalServerError: InternalServerError): OperationError = InternalServerErrorCase(internalServerError) | val id: ShapeId = ShapeId("smithy4s.errors", "OperationError") | val hints: Hints = Hints.empty | final case class BadRequestCase(badRequest: BadRequest) extends OperationError { final def $ordinal: Int = 0 } | final case class InternalServerErrorCase(internalServerError: InternalServerError) extends OperationError { final def $ordinal: Int = 1 } | object BadRequestCase { | val hints: Hints = Hints.empty - | val schema: Schema[BadRequestCase] = bijection(BadRequest.schema.addHints(hints), BadRequestCase(_), _.badRequest) + | val schema: Schema[OperationError.BadRequestCase] = bijection(BadRequest.schema.addHints(hints), OperationError.BadRequestCase(_), _.badRequest) | val alt = schema.oneOf[OperationError]("BadRequest") | } | object InternalServerErrorCase { | val hints: Hints = Hints.empty - | val schema: Schema[InternalServerErrorCase] = bijection(InternalServerError.schema.addHints(hints), InternalServerErrorCase(_), _.internalServerError) + | val schema: Schema[OperationError.InternalServerErrorCase] = bijection(InternalServerError.schema.addHints(hints), OperationError.InternalServerErrorCase(_), _.internalServerError) | val alt = schema.oneOf[OperationError]("InternalServerError") | } + | trait Visitor[A] { + | def badRequest(value: BadRequest): A + | def internalServerError(value: InternalServerError): A + | } | implicit val schema: UnionSchema[OperationError] = union( - | BadRequestCase.alt, - | InternalServerErrorCase.alt, + | OperationError.BadRequestCase.alt, + | OperationError.InternalServerErrorCase.alt, | ){ | _.$ordinal | } From 9bcacd0c284b99d53c5e5fb243faa6cef52dea51 Mon Sep 17 00:00:00 2001 From: Jeff Lewis Date: Fri, 11 Aug 2023 11:24:17 -0600 Subject: [PATCH 3/3] add visitor default --- .../com/amazonaws/dynamodb/DynamoDB.scala | 8 ++++ .../smithy4s/example/CheckedOrUnchecked.scala | 8 ++++ .../example/CheckedOrUnchecked2.scala | 8 ++++ .../smithy4s/example/DeprecatedUnion.scala | 10 ++++ .../example/ErrorHandlingService.scala | 10 ++++ .../ErrorHandlingServiceExtraErrors.scala | 10 ++++ .../src/generated/smithy4s/example/Foo.scala | 10 ++++ .../src/generated/smithy4s/example/Food.scala | 8 ++++ .../smithy4s/example/ForecastResult.scala | 8 ++++ .../generated/smithy4s/example/KVStore.scala | 23 +++++++++ .../smithy4s/example/NameCollision.scala | 7 +++ .../smithy4s/example/ObjectService.scala | 15 ++++++ .../smithy4s/example/OpticsUnion.scala | 7 +++ .../smithy4s/example/OrderType.scala | 9 ++++ .../smithy4s/example/PersonContactInfo.scala | 8 ++++ .../smithy4s/example/PizzaAdminService.scala | 47 +++++++++++++++++++ .../generated/smithy4s/example/Podcast.scala | 8 ++++ .../generated/smithy4s/example/TestAdt.scala | 8 ++++ .../smithy4s/example/TestBiggerUnion.scala | 8 ++++ .../smithy4s/example/TestIdRefUnion.scala | 8 ++++ .../smithy4s/example/TestMixinAdt.scala | 7 +++ .../example/UnionWithRefinedTypes.scala | 8 ++++ .../smithy4s/example/UntaggedUnion.scala | 8 ++++ .../generated/smithy4s/example/Weather.scala | 7 +++ .../guides/auth/HelloWorldAuthService.scala | 14 ++++++ .../example/hello/HelloWorldService.scala | 8 ++++ .../smithy4s/example/imp/ImportService.scala | 7 +++ .../smithy4s/example/test/HelloService.scala | 8 ++++ .../smithy4s/VisitorAndProjectionSpec.scala | 18 +++++++ .../smithy4s/codegen/internals/Renderer.scala | 22 +++++++-- .../internals/RendererConfigSpec.scala | 7 +++ modules/docs/markdown/04-codegen/02-unions.md | 13 +++++ 32 files changed, 350 insertions(+), 5 deletions(-) diff --git a/modules/bootstrapped/src/generated/com/amazonaws/dynamodb/DynamoDB.scala b/modules/bootstrapped/src/generated/com/amazonaws/dynamodb/DynamoDB.scala index 61a638f34..0a2f767db 100644 --- a/modules/bootstrapped/src/generated/com/amazonaws/dynamodb/DynamoDB.scala +++ b/modules/bootstrapped/src/generated/com/amazonaws/dynamodb/DynamoDB.scala @@ -204,6 +204,14 @@ object DynamoDBOperation { def invalidEndpointException(value: InvalidEndpointException): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def internalServerError(value: InternalServerError): A = default + def invalidEndpointException(value: InvalidEndpointException): A = default + } + } + implicit val schema: UnionSchema[ListTablesError] = union( ListTablesError.InternalServerErrorCase.alt, ListTablesError.InvalidEndpointExceptionCase.alt, diff --git a/modules/bootstrapped/src/generated/smithy4s/example/CheckedOrUnchecked.scala b/modules/bootstrapped/src/generated/smithy4s/example/CheckedOrUnchecked.scala index a0922ec51..351e35c99 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/CheckedOrUnchecked.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/CheckedOrUnchecked.scala @@ -50,6 +50,14 @@ object CheckedOrUnchecked extends ShapeTag.Companion[CheckedOrUnchecked] { def raw(value: String): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def checked(value: String): A = default + def raw(value: String): A = default + } + } + implicit val schema: Schema[CheckedOrUnchecked] = union( CheckedOrUnchecked.CheckedCase.alt, CheckedOrUnchecked.RawCase.alt, diff --git a/modules/bootstrapped/src/generated/smithy4s/example/CheckedOrUnchecked2.scala b/modules/bootstrapped/src/generated/smithy4s/example/CheckedOrUnchecked2.scala index f32a4cf69..3e3d0d37e 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/CheckedOrUnchecked2.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/CheckedOrUnchecked2.scala @@ -52,6 +52,14 @@ object CheckedOrUnchecked2 extends ShapeTag.Companion[CheckedOrUnchecked2] { def raw(value: String): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def checked(value: String): A = default + def raw(value: String): A = default + } + } + implicit val schema: Schema[CheckedOrUnchecked2] = union( CheckedOrUnchecked2.CheckedCase.alt, CheckedOrUnchecked2.RawCase.alt, diff --git a/modules/bootstrapped/src/generated/smithy4s/example/DeprecatedUnion.scala b/modules/bootstrapped/src/generated/smithy4s/example/DeprecatedUnion.scala index 01350e246..f3c4efefa 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/DeprecatedUnion.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/DeprecatedUnion.scala @@ -97,6 +97,16 @@ object DeprecatedUnion extends ShapeTag.Companion[DeprecatedUnion] { def p2(value: DeprecatedUnion.UnionProductCaseDeprecatedAtCallSite): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def s(value: String): A = default + def s_V2(value: String): A = default + def p(value: DeprecatedUnion.DeprecatedUnionProductCase): A = default + def p2(value: DeprecatedUnion.UnionProductCaseDeprecatedAtCallSite): A = default + } + } + implicit val schema: Schema[DeprecatedUnion] = union( DeprecatedUnion.SCase.alt, DeprecatedUnion.S_V2Case.alt, diff --git a/modules/bootstrapped/src/generated/smithy4s/example/ErrorHandlingService.scala b/modules/bootstrapped/src/generated/smithy4s/example/ErrorHandlingService.scala index 78f33fcb6..ce1174f1c 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/ErrorHandlingService.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/ErrorHandlingService.scala @@ -165,6 +165,16 @@ object ErrorHandlingServiceOperation { def eHFallbackServerError(value: EHFallbackServerError): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def eHFallbackClientError(value: EHFallbackClientError): A = default + def eHServiceUnavailable(value: EHServiceUnavailable): A = default + def eHNotFound(value: EHNotFound): A = default + def eHFallbackServerError(value: EHFallbackServerError): A = default + } + } + implicit val schema: UnionSchema[ErrorHandlingOperationError] = union( ErrorHandlingOperationError.EHFallbackClientErrorCase.alt, ErrorHandlingOperationError.EHServiceUnavailableCase.alt, diff --git a/modules/bootstrapped/src/generated/smithy4s/example/ErrorHandlingServiceExtraErrors.scala b/modules/bootstrapped/src/generated/smithy4s/example/ErrorHandlingServiceExtraErrors.scala index affa50108..ffa88f783 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/ErrorHandlingServiceExtraErrors.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/ErrorHandlingServiceExtraErrors.scala @@ -166,6 +166,16 @@ object ErrorHandlingServiceExtraErrorsOperation { def randomOtherServerErrorWithCode(value: RandomOtherServerErrorWithCode): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def randomOtherClientError(value: RandomOtherClientError): A = default + def randomOtherServerError(value: RandomOtherServerError): A = default + def randomOtherClientErrorWithCode(value: RandomOtherClientErrorWithCode): A = default + def randomOtherServerErrorWithCode(value: RandomOtherServerErrorWithCode): A = default + } + } + implicit val schema: UnionSchema[ExtraErrorOperationError] = union( ExtraErrorOperationError.RandomOtherClientErrorCase.alt, ExtraErrorOperationError.RandomOtherServerErrorCase.alt, diff --git a/modules/bootstrapped/src/generated/smithy4s/example/Foo.scala b/modules/bootstrapped/src/generated/smithy4s/example/Foo.scala index fabb89c25..104e0468a 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/Foo.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/Foo.scala @@ -86,6 +86,16 @@ object Foo extends ShapeTag.Companion[Foo] { def bDec(value: BigDecimal): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def int(value: Int): A = default + def str(value: String): A = default + def bInt(value: BigInt): A = default + def bDec(value: BigDecimal): A = default + } + } + implicit val schema: Schema[Foo] = union( Foo.IntCase.alt, Foo.StrCase.alt, diff --git a/modules/bootstrapped/src/generated/smithy4s/example/Food.scala b/modules/bootstrapped/src/generated/smithy4s/example/Food.scala index 7b6cc7b47..b2fc3bf31 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/Food.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/Food.scala @@ -49,6 +49,14 @@ object Food extends ShapeTag.Companion[Food] { def salad(value: Salad): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def pizza(value: Pizza): A = default + def salad(value: Salad): A = default + } + } + implicit val schema: Schema[Food] = union( Food.PizzaCase.alt, Food.SaladCase.alt, diff --git a/modules/bootstrapped/src/generated/smithy4s/example/ForecastResult.scala b/modules/bootstrapped/src/generated/smithy4s/example/ForecastResult.scala index 7e8bf5c0c..2b8d3efbc 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/ForecastResult.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/ForecastResult.scala @@ -55,6 +55,14 @@ object ForecastResult extends ShapeTag.Companion[ForecastResult] { def sun(value: UVIndex): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def rain(value: ChanceOfRain): A = default + def sun(value: UVIndex): A = default + } + } + implicit val schema: Schema[ForecastResult] = union( ForecastResult.RainCase.alt, ForecastResult.SunCase.alt, diff --git a/modules/bootstrapped/src/generated/smithy4s/example/KVStore.scala b/modules/bootstrapped/src/generated/smithy4s/example/KVStore.scala index a3d70e5e3..c423ecd5c 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/KVStore.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/KVStore.scala @@ -154,6 +154,14 @@ object KVStoreOperation { def keyNotFoundError(value: KeyNotFoundError): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def unauthorizedError(value: UnauthorizedError): A = default + def keyNotFoundError(value: KeyNotFoundError): A = default + } + } + implicit val schema: UnionSchema[GetError] = union( GetError.UnauthorizedErrorCase.alt, GetError.KeyNotFoundErrorCase.alt, @@ -216,6 +224,13 @@ object KVStoreOperation { def unauthorizedError(value: UnauthorizedError): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def unauthorizedError(value: UnauthorizedError): A = default + } + } + implicit val schema: UnionSchema[PutError] = union( PutError.UnauthorizedErrorCase.alt, ){ @@ -289,6 +304,14 @@ object KVStoreOperation { def keyNotFoundError(value: KeyNotFoundError): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def unauthorizedError(value: UnauthorizedError): A = default + def keyNotFoundError(value: KeyNotFoundError): A = default + } + } + implicit val schema: UnionSchema[DeleteError] = union( DeleteError.UnauthorizedErrorCase.alt, DeleteError.KeyNotFoundErrorCase.alt, diff --git a/modules/bootstrapped/src/generated/smithy4s/example/NameCollision.scala b/modules/bootstrapped/src/generated/smithy4s/example/NameCollision.scala index de57ea980..d0a87bdc6 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/NameCollision.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/NameCollision.scala @@ -134,6 +134,13 @@ object NameCollisionOperation { def myOpError(value: smithy4s.example.MyOpError): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def myOpError(value: smithy4s.example.MyOpError): A = default + } + } + implicit val schema: UnionSchema[MyOpError] = union( MyOpError.MyOpErrorCase.alt, ){ diff --git a/modules/bootstrapped/src/generated/smithy4s/example/ObjectService.scala b/modules/bootstrapped/src/generated/smithy4s/example/ObjectService.scala index 31ba35aba..72f24b939 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/ObjectService.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/ObjectService.scala @@ -160,6 +160,14 @@ object ObjectServiceOperation { def noMoreSpace(value: NoMoreSpace): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def serverError(value: ServerError): A = default + def noMoreSpace(value: NoMoreSpace): A = default + } + } + implicit val schema: UnionSchema[PutObjectError] = union( PutObjectError.ServerErrorCase.alt, PutObjectError.NoMoreSpaceCase.alt, @@ -225,6 +233,13 @@ object ObjectServiceOperation { def serverError(value: ServerError): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def serverError(value: ServerError): A = default + } + } + implicit val schema: UnionSchema[GetObjectError] = union( GetObjectError.ServerErrorCase.alt, ){ diff --git a/modules/bootstrapped/src/generated/smithy4s/example/OpticsUnion.scala b/modules/bootstrapped/src/generated/smithy4s/example/OpticsUnion.scala index f8d5164cb..6177fc2d5 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/OpticsUnion.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/OpticsUnion.scala @@ -44,6 +44,13 @@ object OpticsUnion extends ShapeTag.Companion[OpticsUnion] { def one(value: OpticsStructure): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def one(value: OpticsStructure): A = default + } + } + implicit val schema: Schema[OpticsUnion] = union( OpticsUnion.OneCase.alt, ){ diff --git a/modules/bootstrapped/src/generated/smithy4s/example/OrderType.scala b/modules/bootstrapped/src/generated/smithy4s/example/OrderType.scala index af1cebf60..3856130ff 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/OrderType.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/OrderType.scala @@ -78,6 +78,15 @@ object OrderType extends ShapeTag.Companion[OrderType] { def preview(value: OrderType.PreviewCase.type): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def online(value: OrderNumber): A = default + def inStore(value: OrderType.InStoreOrder): A = default + def preview(value: OrderType.PreviewCase.type): A = default + } + } + implicit val schema: Schema[OrderType] = union( OrderType.OnlineCase.alt, OrderType.InStoreOrder.alt, diff --git a/modules/bootstrapped/src/generated/smithy4s/example/PersonContactInfo.scala b/modules/bootstrapped/src/generated/smithy4s/example/PersonContactInfo.scala index 1bb73cecb..8665a57b3 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/PersonContactInfo.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/PersonContactInfo.scala @@ -58,6 +58,14 @@ object PersonContactInfo extends ShapeTag.Companion[PersonContactInfo] { def phone(value: PersonPhoneNumber): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def email(value: PersonEmail): A = default + def phone(value: PersonPhoneNumber): A = default + } + } + implicit val schema: Schema[PersonContactInfo] = union( PersonContactInfo.EmailCase.alt, PersonContactInfo.PhoneCase.alt, diff --git a/modules/bootstrapped/src/generated/smithy4s/example/PizzaAdminService.scala b/modules/bootstrapped/src/generated/smithy4s/example/PizzaAdminService.scala index f8b6e891a..ddb0448e8 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/PizzaAdminService.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/PizzaAdminService.scala @@ -212,6 +212,15 @@ object PizzaAdminServiceOperation { def genericClientError(value: GenericClientError): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def priceError(value: PriceError): A = default + def genericServerError(value: GenericServerError): A = default + def genericClientError(value: GenericClientError): A = default + } + } + implicit val schema: UnionSchema[AddMenuItemError] = union( AddMenuItemError.PriceErrorCase.alt, AddMenuItemError.GenericServerErrorCase.alt, @@ -314,6 +323,16 @@ object PizzaAdminServiceOperation { def notFoundError(value: NotFoundError): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def genericClientError(value: GenericClientError): A = default + def fallbackError2(value: FallbackError2): A = default + def fallbackError(value: FallbackError): A = default + def notFoundError(value: NotFoundError): A = default + } + } + implicit val schema: UnionSchema[GetMenuError] = union( GetMenuError.GenericClientErrorCase.alt, GetMenuError.FallbackError2Case.alt, @@ -400,6 +419,13 @@ object PizzaAdminServiceOperation { def unknownServerError(value: UnknownServerError): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def unknownServerError(value: UnknownServerError): A = default + } + } + implicit val schema: UnionSchema[HealthError] = union( HealthError.UnknownServerErrorCase.alt, ){ @@ -498,6 +524,13 @@ object PizzaAdminServiceOperation { def unknownServerError(value: UnknownServerError): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def unknownServerError(value: UnknownServerError): A = default + } + } + implicit val schema: UnionSchema[GetEnumError] = union( GetEnumError.UnknownServerErrorCase.alt, ){ @@ -562,6 +595,13 @@ object PizzaAdminServiceOperation { def unknownServerError(value: UnknownServerError): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def unknownServerError(value: UnknownServerError): A = default + } + } + implicit val schema: UnionSchema[GetIntEnumError] = union( GetIntEnumError.UnknownServerErrorCase.alt, ){ @@ -626,6 +666,13 @@ object PizzaAdminServiceOperation { def unknownServerError(value: UnknownServerError): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def unknownServerError(value: UnknownServerError): A = default + } + } + implicit val schema: UnionSchema[CustomCodeError] = union( CustomCodeError.UnknownServerErrorCase.alt, ){ diff --git a/modules/bootstrapped/src/generated/smithy4s/example/Podcast.scala b/modules/bootstrapped/src/generated/smithy4s/example/Podcast.scala index f479394d8..6b1c1073f 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/Podcast.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/Podcast.scala @@ -94,6 +94,14 @@ object Podcast extends ShapeTag.Companion[Podcast] { def audio(value: Podcast.Audio): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def video(value: Podcast.Video): A = default + def audio(value: Podcast.Audio): A = default + } + } + implicit val schema: Schema[Podcast] = union( Podcast.Video.alt, Podcast.Audio.alt, diff --git a/modules/bootstrapped/src/generated/smithy4s/example/TestAdt.scala b/modules/bootstrapped/src/generated/smithy4s/example/TestAdt.scala index 17a69cc79..1e16d65b8 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/TestAdt.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/TestAdt.scala @@ -80,6 +80,14 @@ object TestAdt extends ShapeTag.Companion[TestAdt] { def two(value: TestAdt.AdtTwo): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def one(value: TestAdt.AdtOne): A = default + def two(value: TestAdt.AdtTwo): A = default + } + } + implicit val schema: Schema[TestAdt] = union( TestAdt.AdtOne.alt, TestAdt.AdtTwo.alt, diff --git a/modules/bootstrapped/src/generated/smithy4s/example/TestBiggerUnion.scala b/modules/bootstrapped/src/generated/smithy4s/example/TestBiggerUnion.scala index c3afb5062..493809ad3 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/TestBiggerUnion.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/TestBiggerUnion.scala @@ -51,6 +51,14 @@ object TestBiggerUnion extends ShapeTag.Companion[TestBiggerUnion] { def two(value: Two): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def one(value: One): A = default + def two(value: Two): A = default + } + } + implicit val schema: Schema[TestBiggerUnion] = union( TestBiggerUnion.OneCase.alt, TestBiggerUnion.TwoCase.alt, diff --git a/modules/bootstrapped/src/generated/smithy4s/example/TestIdRefUnion.scala b/modules/bootstrapped/src/generated/smithy4s/example/TestIdRefUnion.scala index d015bf151..43fb4d271 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/TestIdRefUnion.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/TestIdRefUnion.scala @@ -50,6 +50,14 @@ object TestIdRefUnion extends ShapeTag.Companion[TestIdRefUnion] { def testTwo(value: TestIdRefTwo): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def test(value: ShapeId): A = default + def testTwo(value: TestIdRefTwo): A = default + } + } + implicit val schema: Schema[TestIdRefUnion] = union( TestIdRefUnion.TestCase.alt, TestIdRefUnion.TestTwoCase.alt, diff --git a/modules/bootstrapped/src/generated/smithy4s/example/TestMixinAdt.scala b/modules/bootstrapped/src/generated/smithy4s/example/TestMixinAdt.scala index 4e9463c40..e32252647 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/TestMixinAdt.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/TestMixinAdt.scala @@ -52,6 +52,13 @@ object TestMixinAdt extends ShapeTag.Companion[TestMixinAdt] { def test(value: TestMixinAdt.TestAdtMemberWithMixin): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def test(value: TestMixinAdt.TestAdtMemberWithMixin): A = default + } + } + implicit val schema: Schema[TestMixinAdt] = union( TestMixinAdt.TestAdtMemberWithMixin.alt, ){ diff --git a/modules/bootstrapped/src/generated/smithy4s/example/UnionWithRefinedTypes.scala b/modules/bootstrapped/src/generated/smithy4s/example/UnionWithRefinedTypes.scala index 7be0dddf1..366a54d5d 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/UnionWithRefinedTypes.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/UnionWithRefinedTypes.scala @@ -49,6 +49,14 @@ object UnionWithRefinedTypes extends ShapeTag.Companion[UnionWithRefinedTypes] { def dogName(value: smithy4s.refined.Name): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def age(value: Age): A = default + def dogName(value: smithy4s.refined.Name): A = default + } + } + implicit val schema: Schema[UnionWithRefinedTypes] = union( UnionWithRefinedTypes.AgeCase.alt, UnionWithRefinedTypes.DogNameCase.alt, diff --git a/modules/bootstrapped/src/generated/smithy4s/example/UntaggedUnion.scala b/modules/bootstrapped/src/generated/smithy4s/example/UntaggedUnion.scala index 00d6a9727..f69c4c84c 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/UntaggedUnion.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/UntaggedUnion.scala @@ -51,6 +51,14 @@ object UntaggedUnion extends ShapeTag.Companion[UntaggedUnion] { def four(value: Four): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def three(value: Three): A = default + def four(value: Four): A = default + } + } + implicit val schema: Schema[UntaggedUnion] = union( UntaggedUnion.ThreeCase.alt, UntaggedUnion.FourCase.alt, diff --git a/modules/bootstrapped/src/generated/smithy4s/example/Weather.scala b/modules/bootstrapped/src/generated/smithy4s/example/Weather.scala index 17af071b2..b81cb3d12 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/Weather.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/Weather.scala @@ -166,6 +166,13 @@ object WeatherOperation { def noSuchResource(value: NoSuchResource): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def noSuchResource(value: NoSuchResource): A = default + } + } + implicit val schema: UnionSchema[GetCityError] = union( GetCityError.NoSuchResourceCase.alt, ){ diff --git a/modules/bootstrapped/src/generated/smithy4s/example/guides/auth/HelloWorldAuthService.scala b/modules/bootstrapped/src/generated/smithy4s/example/guides/auth/HelloWorldAuthService.scala index 2a9aebe83..13c0fe5d8 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/guides/auth/HelloWorldAuthService.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/guides/auth/HelloWorldAuthService.scala @@ -143,6 +143,13 @@ object HelloWorldAuthServiceOperation { def notAuthorizedError(value: NotAuthorizedError): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def notAuthorizedError(value: NotAuthorizedError): A = default + } + } + implicit val schema: UnionSchema[SayWorldError] = union( SayWorldError.NotAuthorizedErrorCase.alt, ){ @@ -209,6 +216,13 @@ object HelloWorldAuthServiceOperation { def notAuthorizedError(value: NotAuthorizedError): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def notAuthorizedError(value: NotAuthorizedError): A = default + } + } + implicit val schema: UnionSchema[HealthCheckError] = union( HealthCheckError.NotAuthorizedErrorCase.alt, ){ diff --git a/modules/bootstrapped/src/generated/smithy4s/example/hello/HelloWorldService.scala b/modules/bootstrapped/src/generated/smithy4s/example/hello/HelloWorldService.scala index 3a28b49c1..f9dd5f569 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/hello/HelloWorldService.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/hello/HelloWorldService.scala @@ -147,6 +147,14 @@ object HelloWorldServiceOperation { def specificServerError(value: SpecificServerError): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def genericServerError(value: GenericServerError): A = default + def specificServerError(value: SpecificServerError): A = default + } + } + implicit val schema: UnionSchema[HelloError] = union( HelloError.GenericServerErrorCase.alt, HelloError.SpecificServerErrorCase.alt, diff --git a/modules/bootstrapped/src/generated/smithy4s/example/imp/ImportService.scala b/modules/bootstrapped/src/generated/smithy4s/example/imp/ImportService.scala index e803523a4..bb95d3531 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/imp/ImportService.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/imp/ImportService.scala @@ -137,6 +137,13 @@ object ImportServiceOperation { def notFoundError(value: NotFoundError): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def notFoundError(value: NotFoundError): A = default + } + } + implicit val schema: UnionSchema[ImportOperationError] = union( ImportOperationError.NotFoundErrorCase.alt, ){ diff --git a/modules/bootstrapped/src/generated/smithy4s/example/test/HelloService.scala b/modules/bootstrapped/src/generated/smithy4s/example/test/HelloService.scala index 9d46a2516..b0b11111e 100644 --- a/modules/bootstrapped/src/generated/smithy4s/example/test/HelloService.scala +++ b/modules/bootstrapped/src/generated/smithy4s/example/test/HelloService.scala @@ -156,6 +156,14 @@ object HelloServiceOperation { def complexError(value: ComplexError): A } + object Visitor { + trait Default[A] extends Visitor[A] { + def default: A + def simpleError(value: SimpleError): A = default + def complexError(value: ComplexError): A = default + } + } + implicit val schema: UnionSchema[SayHelloError] = union( SayHelloError.SimpleErrorCase.alt, SayHelloError.ComplexErrorCase.alt, diff --git a/modules/bootstrapped/test/src/smithy4s/VisitorAndProjectionSpec.scala b/modules/bootstrapped/test/src/smithy4s/VisitorAndProjectionSpec.scala index 8ff7b51d6..9c46659d9 100644 --- a/modules/bootstrapped/test/src/smithy4s/VisitorAndProjectionSpec.scala +++ b/modules/bootstrapped/test/src/smithy4s/VisitorAndProjectionSpec.scala @@ -25,6 +25,24 @@ final class VisitorAndProjectionSpec extends FunSuite { ) } + test("visitor - default") { + val visitor = new OrderType.Visitor.Default[String] { + def default: String = "test" + } + assertEquals( + OrderType.OnlineCase(OrderNumber(123)).accept(visitor), + "test" + ) + assertEquals( + OrderType.InStoreOrder(OrderNumber(2)).accept(visitor), + "test" + ) + assertEquals( + OrderType.PreviewCase.accept(visitor), + "test" + ) + } + test("projections") { val one = OrderType.OnlineCase(OrderNumber(123)) val two = OrderType.InStoreOrder(OrderNumber(2)) diff --git a/modules/codegen/src/smithy4s/codegen/internals/Renderer.scala b/modules/codegen/src/smithy4s/codegen/internals/Renderer.scala index 0c9151644..b2280898c 100644 --- a/modules/codegen/src/smithy4s/codegen/internals/Renderer.scala +++ b/modules/codegen/src/smithy4s/codegen/internals/Renderer.scala @@ -1037,11 +1037,23 @@ private[internals] class Renderer(compilationUnit: CompilationUnit) { self => line"def $ident: Option[${caseNameType(name, alt)}] = ${caseNameWithAlt(name, alt)}.project.lift(self)$maybeMap" } ) - val visitor: Lines = block(line"trait Visitor[A]")( - alts.map { alt => - val ident = NameDef(uncapitalise(alt.name)) - line"def $ident(value: ${caseNameType(name, alt)}): A" - } + val visitor: Lines = lines( + block(line"trait Visitor[A]")( + alts.map { alt => + val ident = NameDef(uncapitalise(alt.name)) + line"def $ident(value: ${caseNameType(name, alt)}): A" + } + ), + newline, + block(line"object Visitor")( + block(line"trait Default[A] extends Visitor[A]")( + line"def default: A", + alts.map { alt => + val ident = NameDef(uncapitalise(alt.name)) + line"def $ident(value: ${caseNameType(name, alt)}): A = default" + } + ) + ) ) val accept: Lines = block(line"def accept[A](visitor: $name.Visitor[A]): A = this match")( diff --git a/modules/codegen/test/src/smithy4s/codegen/internals/RendererConfigSpec.scala b/modules/codegen/test/src/smithy4s/codegen/internals/RendererConfigSpec.scala index 9354984c1..43e93fa03 100644 --- a/modules/codegen/test/src/smithy4s/codegen/internals/RendererConfigSpec.scala +++ b/modules/codegen/test/src/smithy4s/codegen/internals/RendererConfigSpec.scala @@ -279,6 +279,13 @@ final class RendererConfigSpec extends munit.FunSuite { | def badRequest(value: BadRequest): A | def internalServerError(value: InternalServerError): A | } + | object Visitor { + | trait Default[A] extends Visitor[A] { + | def default: A + | def badRequest(value: BadRequest): A = default + | def internalServerError(value: InternalServerError): A = default + | } + | } | implicit val schema: UnionSchema[OperationError] = union( | OperationError.BadRequestCase.alt, | OperationError.InternalServerErrorCase.alt, diff --git a/modules/docs/markdown/04-codegen/02-unions.md b/modules/docs/markdown/04-codegen/02-unions.md index 8586a08b4..5d19b7c73 100644 --- a/modules/docs/markdown/04-codegen/02-unions.md +++ b/modules/docs/markdown/04-codegen/02-unions.md @@ -212,3 +212,16 @@ val visitor = new Pet.Visitor[String] { myPet.accept(visitor) // "Dog named Spot" ``` + +You can also implement a Visitor using `Visitor.Default` to provide a default value to be used for cases that you don't explicitly implement. For example: + +```scala +val myPet: Pet = Pet.DogCase(Dog(name = "Spot")) + +val visitor = new Pet.Visitor.Default[String] { + def default: String = "default value" + def cat(cat: Cat): String = s"Cat named ${cat.name}" +} + +myPet.accept(visitor) // "default value" +```