forked from smithy-lang/smithy-rs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
CollectionConstraintViolationGenerator.kt
99 lines (92 loc) · 5.06 KB
/
CollectionConstraintViolationGenerator.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package software.amazon.smithy.rust.codegen.server.smithy.generators
import software.amazon.smithy.model.shapes.CollectionShape
import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter
import software.amazon.smithy.rust.codegen.core.rustlang.Visibility
import software.amazon.smithy.rust.codegen.core.rustlang.join
import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate
import software.amazon.smithy.rust.codegen.core.smithy.makeRustBoxed
import software.amazon.smithy.rust.codegen.core.smithy.module
import software.amazon.smithy.rust.codegen.core.util.hasTrait
import software.amazon.smithy.rust.codegen.core.util.letIf
import software.amazon.smithy.rust.codegen.server.smithy.PubCrateConstraintViolationSymbolProvider
import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenContext
import software.amazon.smithy.rust.codegen.server.smithy.canReachConstrainedShape
import software.amazon.smithy.rust.codegen.server.smithy.traits.ConstraintViolationRustBoxTrait
import software.amazon.smithy.rust.codegen.server.smithy.traits.isReachableFromOperationInput
class CollectionConstraintViolationGenerator(
codegenContext: ServerCodegenContext,
private val modelsModuleWriter: RustWriter,
private val shape: CollectionShape,
private val collectionConstraintsInfo: List<CollectionTraitInfo>,
private val validationExceptionConversionGenerator: ValidationExceptionConversionGenerator,
) {
private val model = codegenContext.model
private val symbolProvider = codegenContext.symbolProvider
private val publicConstrainedTypes = codegenContext.settings.codegenConfig.publicConstrainedTypes
private val constraintViolationSymbolProvider =
with(codegenContext.constraintViolationSymbolProvider) {
if (publicConstrainedTypes) {
this
} else {
PubCrateConstraintViolationSymbolProvider(this)
}
}
private val constraintsInfo: List<TraitInfo> = collectionConstraintsInfo.map { it.toTraitInfo() }
fun render() {
val targetShape = model.expectShape(shape.member.target)
val constraintViolationSymbol = constraintViolationSymbolProvider.toSymbol(shape)
val constraintViolationName = constraintViolationSymbol.name
val isMemberConstrained = targetShape.canReachConstrainedShape(model, symbolProvider)
val constraintViolationVisibility = Visibility.publicIf(publicConstrainedTypes, Visibility.PUBCRATE)
modelsModuleWriter.withInlineModule(constraintViolationSymbol.module()) {
val constraintViolationVariants = constraintsInfo.map { it.constraintViolationVariant }.toMutableList()
if (isMemberConstrained) {
constraintViolationVariants += {
val memberConstraintViolationSymbol =
constraintViolationSymbolProvider.toSymbol(targetShape).letIf(
shape.member.hasTrait<ConstraintViolationRustBoxTrait>(),
) {
it.makeRustBoxed()
}
rustTemplate(
"""
/// Constraint violation error when an element doesn't satisfy its own constraints.
/// The first component of the tuple is the index in the collection where the
/// first constraint violation was found.
##[doc(hidden)]
Member(usize, #{MemberConstraintViolationSymbol})
""",
"MemberConstraintViolationSymbol" to memberConstraintViolationSymbol,
)
}
}
// TODO(https://github.com/awslabs/smithy-rs/issues/1401) We should really have two `ConstraintViolation`
// types here. One will just have variants for each constraint trait on the collection shape, for use by the user.
// The other one will have variants if the shape's member is directly or transitively constrained,
// and is for use by the framework.
rustTemplate(
"""
##[derive(Debug, PartialEq)]
${constraintViolationVisibility.toRustQualifier()} enum $constraintViolationName {
#{ConstraintViolationVariants:W}
}
""",
"ConstraintViolationVariants" to constraintViolationVariants.join(",\n"),
)
if (shape.isReachableFromOperationInput()) {
rustTemplate(
"""
impl $constraintViolationName {
#{CollectionShapeConstraintViolationImplBlock}
}
""",
"CollectionShapeConstraintViolationImplBlock" to validationExceptionConversionGenerator.collectionShapeConstraintViolationImplBlock(collectionConstraintsInfo, isMemberConstrained),
)
}
}
}
}