-
Notifications
You must be signed in to change notification settings - Fork 180
/
ConstrainedShapeSymbolProvider.kt
115 lines (107 loc) · 5.45 KB
/
ConstrainedShapeSymbolProvider.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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package software.amazon.smithy.rust.codegen.server.smithy
import software.amazon.smithy.codegen.core.Symbol
import software.amazon.smithy.model.Model
import software.amazon.smithy.model.knowledge.NullableIndex
import software.amazon.smithy.model.shapes.ByteShape
import software.amazon.smithy.model.shapes.CollectionShape
import software.amazon.smithy.model.shapes.IntegerShape
import software.amazon.smithy.model.shapes.LongShape
import software.amazon.smithy.model.shapes.MapShape
import software.amazon.smithy.model.shapes.MemberShape
import software.amazon.smithy.model.shapes.ServiceShape
import software.amazon.smithy.model.shapes.Shape
import software.amazon.smithy.model.shapes.ShortShape
import software.amazon.smithy.model.shapes.StringShape
import software.amazon.smithy.model.traits.LengthTrait
import software.amazon.smithy.rust.codegen.core.rustlang.RustType
import software.amazon.smithy.rust.codegen.core.smithy.ModelsModule
import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider
import software.amazon.smithy.rust.codegen.core.smithy.WrappingSymbolProvider
import software.amazon.smithy.rust.codegen.core.smithy.contextName
import software.amazon.smithy.rust.codegen.core.smithy.handleOptionality
import software.amazon.smithy.rust.codegen.core.smithy.handleRustBoxing
import software.amazon.smithy.rust.codegen.core.smithy.locatedIn
import software.amazon.smithy.rust.codegen.core.smithy.rustType
import software.amazon.smithy.rust.codegen.core.smithy.symbolBuilder
import software.amazon.smithy.rust.codegen.core.util.hasTrait
import software.amazon.smithy.rust.codegen.core.util.toPascalCase
/**
* The [ConstrainedShapeSymbolProvider] returns, for a given _directly_
* constrained shape, a symbol whose Rust type can hold the constrained values.
*
* For all shapes with supported traits directly attached to them, this type is
* a [RustType.Opaque] wrapper tuple newtype holding the inner constrained
* type.
*
* The symbols this symbol provider returns are always public and exposed to
* the end user.
*
* This symbol provider is meant to be used "deep" within the wrapped symbol
* providers chain, just above the core base symbol provider, `SymbolVisitor`.
*
* If the shape is _transitively but not directly_ constrained, use
* [PubCrateConstrainedShapeSymbolProvider] instead, which returns symbols
* whose associated types are `pub(crate)` and thus not exposed to the end
* user.
*/
class ConstrainedShapeSymbolProvider(
private val base: RustSymbolProvider,
private val model: Model,
private val serviceShape: ServiceShape,
) : WrappingSymbolProvider(base) {
private val nullableIndex = NullableIndex.of(model)
private fun publicConstrainedSymbolForMapShape(shape: Shape): Symbol {
check(shape is MapShape)
val rustType = RustType.Opaque(shape.contextName(serviceShape).toPascalCase())
return symbolBuilder(shape, rustType).locatedIn(ModelsModule).build()
}
override fun toSymbol(shape: Shape): Symbol {
return when (shape) {
is MemberShape -> {
// TODO(https://github.com/awslabs/smithy-rs/issues/1401) Member shapes can have constraint traits
// (constraint trait precedence).
val target = model.expectShape(shape.target)
val targetSymbol = this.toSymbol(target)
// Handle boxing first so we end up with `Option<Box<_>>`, not `Box<Option<_>>`.
handleOptionality(handleRustBoxing(targetSymbol, shape), shape, nullableIndex, base.config().nullabilityCheckMode)
}
is MapShape -> {
if (shape.isDirectlyConstrained(base)) {
check(shape.hasTrait<LengthTrait>()) { "Only the `length` constraint trait can be applied to maps" }
publicConstrainedSymbolForMapShape(shape)
} else {
val keySymbol = this.toSymbol(shape.key)
val valueSymbol = this.toSymbol(shape.value)
symbolBuilder(shape, RustType.HashMap(keySymbol.rustType(), valueSymbol.rustType()))
.addReference(keySymbol)
.addReference(valueSymbol)
.build()
}
}
is CollectionShape -> {
// TODO(https://github.com/awslabs/smithy-rs/issues/1401) Both arms return the same because we haven't
// implemented any constraint trait on collection shapes yet.
if (shape.isDirectlyConstrained(base)) {
val inner = this.toSymbol(shape.member)
symbolBuilder(shape, RustType.Vec(inner.rustType())).addReference(inner).build()
} else {
val inner = this.toSymbol(shape.member)
symbolBuilder(shape, RustType.Vec(inner.rustType())).addReference(inner).build()
}
}
is StringShape, is IntegerShape, is ShortShape, is LongShape, is ByteShape -> {
if (shape.isDirectlyConstrained(base)) {
val rustType = RustType.Opaque(shape.contextName(serviceShape).toPascalCase())
symbolBuilder(shape, rustType).locatedIn(ModelsModule).build()
} else {
base.toSymbol(shape)
}
}
else -> base.toSymbol(shape)
}
}
}