@@ -19,7 +19,10 @@ import software.amazon.smithy.model.shapes.ServiceShape
19
19
import software.amazon.smithy.model.shapes.Shape
20
20
import software.amazon.smithy.model.shapes.ShortShape
21
21
import software.amazon.smithy.model.shapes.StringShape
22
+ import software.amazon.smithy.model.shapes.StructureShape
22
23
import software.amazon.smithy.model.traits.LengthTrait
24
+ import software.amazon.smithy.rust.codegen.core.rustlang.RustModule
25
+ import software.amazon.smithy.rust.codegen.core.rustlang.RustReservedWords
23
26
import software.amazon.smithy.rust.codegen.core.rustlang.RustType
24
27
import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider
25
28
import software.amazon.smithy.rust.codegen.core.smithy.WrappingSymbolProvider
@@ -32,6 +35,8 @@ import software.amazon.smithy.rust.codegen.core.smithy.symbolBuilder
32
35
import software.amazon.smithy.rust.codegen.core.util.hasTrait
33
36
import software.amazon.smithy.rust.codegen.core.util.orNull
34
37
import software.amazon.smithy.rust.codegen.core.util.toPascalCase
38
+ import software.amazon.smithy.rust.codegen.core.util.toSnakeCase
39
+ import software.amazon.smithy.rust.codegen.server.smithy.generators.serverBuilderModule
35
40
36
41
/* *
37
42
* The [ConstrainedShapeSymbolProvider] returns, for a given _directly_
@@ -56,14 +61,19 @@ class ConstrainedShapeSymbolProvider(
56
61
private val base : RustSymbolProvider ,
57
62
private val model : Model ,
58
63
private val serviceShape : ServiceShape ,
64
+ private val publicConstrainedTypes : Boolean = true
59
65
) : WrappingSymbolProvider(base) {
60
66
private val nullableIndex = NullableIndex .of(model)
61
67
62
68
private fun publicConstrainedSymbolForMapOrCollectionShape (shape : Shape ): Symbol {
63
69
check(shape is MapShape || shape is CollectionShape )
70
+ // FZ rebase
71
+ // val rustType = RustType.Opaque(shape.contextName(serviceShape).toPascalCase())
72
+ // return symbolBuilder(shape, rustType).locatedIn(ServerRustModule.Model).build()
64
73
65
- val rustType = RustType .Opaque (shape.contextName(serviceShape).toPascalCase())
66
- return symbolBuilder(shape, rustType).locatedIn(ServerRustModule .Model ).build()
74
+ val (name, module) = getMemberNameAndModule(shape, serviceShape, ServerRustModule .Model , ! publicConstrainedTypes)
75
+ val rustType = RustType .Opaque (name)
76
+ return symbolBuilder(shape, rustType).locatedIn(module).build()
67
77
}
68
78
69
79
override fun toSymbol (shape : Shape ): Symbol {
@@ -74,8 +84,14 @@ class ConstrainedShapeSymbolProvider(
74
84
val target = model.expectShape(shape.target)
75
85
val targetSymbol = this .toSymbol(target)
76
86
// Handle boxing first, so we end up with `Option<Box<_>>`, not `Box<Option<_>>`.
77
- handleOptionality(handleRustBoxing(targetSymbol, shape), shape, nullableIndex, base.config().nullabilityCheckMode)
87
+ handleOptionality(
88
+ handleRustBoxing(targetSymbol, shape),
89
+ shape,
90
+ nullableIndex,
91
+ base.config().nullabilityCheckMode,
92
+ )
78
93
}
94
+
79
95
is MapShape -> {
80
96
if (shape.isDirectlyConstrained(base)) {
81
97
check(shape.hasTrait<LengthTrait >()) {
@@ -91,6 +107,7 @@ class ConstrainedShapeSymbolProvider(
91
107
.build()
92
108
}
93
109
}
110
+
94
111
is CollectionShape -> {
95
112
if (shape.isDirectlyConstrained(base)) {
96
113
check(constrainedCollectionCheck(shape)) {
@@ -105,8 +122,15 @@ class ConstrainedShapeSymbolProvider(
105
122
106
123
is StringShape , is IntegerShape , is ShortShape , is LongShape , is ByteShape , is BlobShape -> {
107
124
if (shape.isDirectlyConstrained(base)) {
108
- val rustType = RustType .Opaque (shape.contextName(serviceShape).toPascalCase())
109
- symbolBuilder(shape, rustType).locatedIn(ServerRustModule .Model ).build()
125
+ // FZ rebase
126
+ // val rustType = RustType.Opaque(shape.contextName(serviceShape).toPascalCase())
127
+ // symbolBuilder(shape, rustType).locatedIn(ServerRustModule.Model).build()
128
+
129
+ // A standalone constrained shape goes into `ModelsModule`, but one
130
+ // arising from a constrained member shape goes into a module for the container.
131
+ val (name, module) = getMemberNameAndModule(shape, serviceShape, ServerRustModule .Model , ! publicConstrainedTypes)
132
+ val rustType = RustType .Opaque (name)
133
+ symbolBuilder(shape, rustType).locatedIn(module).build()
110
134
} else {
111
135
base.toSymbol(shape)
112
136
}
@@ -122,9 +146,51 @@ class ConstrainedShapeSymbolProvider(
122
146
* - That it has no unsupported constraints applied.
123
147
*/
124
148
private fun constrainedCollectionCheck (shape : CollectionShape ): Boolean {
125
- val supportedConstraintTraits = supportedCollectionConstraintTraits.mapNotNull { shape.getTrait(it).orNull() }.toSet()
149
+ val supportedConstraintTraits =
150
+ supportedCollectionConstraintTraits.mapNotNull { shape.getTrait(it).orNull() }.toSet()
126
151
val allConstraintTraits = allConstraintTraits.mapNotNull { shape.getTrait(it).orNull() }.toSet()
127
152
128
- return supportedConstraintTraits.isNotEmpty() && allConstraintTraits.subtract(supportedConstraintTraits).isEmpty()
153
+ return supportedConstraintTraits.isNotEmpty() && allConstraintTraits.subtract(supportedConstraintTraits)
154
+ .isEmpty()
155
+ }
156
+
157
+
158
+ /* *
159
+ * Returns the pair (Rust Symbol Name, Inline Module) for the shape. At the time of model transformation all
160
+ * constrained member shapes are extracted and are given a model-wide unique name. However, the generated code
161
+ * for the new shapes is in a module that is named after the containing shape (structure, list, map or union).
162
+ * The new shape's Rust Symbol is renamed from `{structureName}{memberName}` to `{structure_name}::{member_name}`
163
+ */
164
+ private fun getMemberNameAndModule (
165
+ shape : Shape ,
166
+ serviceShape : ServiceShape ,
167
+ defaultModule : RustModule .LeafModule ,
168
+ pubCrateServerBuilder : Boolean ,
169
+ ): Pair <String , RustModule .LeafModule > {
170
+ val (container, member) =
171
+ shape.overriddenConstrainedMemberInfo() ? : return Pair (shape.contextName(serviceShape), defaultModule)
172
+
173
+ return if (container is StructureShape ) {
174
+ val builderModule = container.serverBuilderModule(base, pubCrateServerBuilder)
175
+ val renameTo = member.memberName ? : member.id.name
176
+ Pair (renameTo.toPascalCase(), builderModule)
177
+ } else {
178
+ // For List, Union and Map, the new shape defined for a constrained member shape
179
+ // need to be placed into an inline module named `pub {container_name_in_snake_case}`
180
+ val innerModuleName = RustReservedWords .escapeIfNeeded(container.id.name.toSnakeCase()) + if (pubCrateServerBuilder) {
181
+ " _internal"
182
+ } else {
183
+ " "
184
+ }
185
+
186
+ val innerModule = RustModule .new(
187
+ innerModuleName,
188
+ visibility = Visibility .publicIf(! pubCrateServerBuilder, Visibility .PUBCRATE ),
189
+ parent = defaultModule,
190
+ inline = true ,
191
+ )
192
+ val renameTo = member.memberName ? : member.id.name
193
+ Pair (renameTo.toPascalCase(), innerModule)
194
+ }
129
195
}
130
196
}
0 commit comments