Skip to content

Commit b0bf70d

Browse files
jdisantiaws-sdk-rust-ci
authored andcommitted
Move symbol extension functions into SymbolExt (#2378)
1 parent 3042b7c commit b0bf70d

File tree

2 files changed

+140
-135
lines changed

2 files changed

+140
-135
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package software.amazon.smithy.rust.codegen.core.smithy
7+
8+
import software.amazon.smithy.codegen.core.Symbol
9+
import software.amazon.smithy.model.shapes.Shape
10+
import software.amazon.smithy.rust.codegen.core.rustlang.RustModule
11+
import software.amazon.smithy.rust.codegen.core.rustlang.RustType
12+
import software.amazon.smithy.rust.codegen.core.rustlang.stripOuter
13+
import software.amazon.smithy.rust.codegen.core.util.orNull
14+
15+
/** Set the symbolLocation for this symbol builder */
16+
fun Symbol.Builder.locatedIn(rustModule: RustModule.LeafModule): Symbol.Builder {
17+
val currentRustType = this.build().rustType()
18+
check(currentRustType is RustType.Opaque) {
19+
"Only `RustType.Opaque` can have its namespace updated. Received $currentRustType."
20+
}
21+
val newRustType = currentRustType.copy(namespace = rustModule.fullyQualifiedPath())
22+
return this.definitionFile(rustModule.definitionFile())
23+
.namespace(rustModule.fullyQualifiedPath(), "::")
24+
.rustType(newRustType)
25+
.module(rustModule)
26+
}
27+
28+
/**
29+
* Make the Rust type of a symbol optional (hold `Option<T>`)
30+
*
31+
* This is idempotent and will have no change if the type is already optional.
32+
*/
33+
fun Symbol.makeOptional(): Symbol =
34+
if (isOptional()) {
35+
this
36+
} else {
37+
val rustType = RustType.Option(this.rustType())
38+
Symbol.builder()
39+
.rustType(rustType)
40+
.addReference(this)
41+
.name(rustType.name)
42+
.build()
43+
}
44+
45+
/**
46+
* Make the Rust type of a symbol boxed (hold `Box<T>`).
47+
*
48+
* This is idempotent and will have no change if the type is already boxed.
49+
*/
50+
fun Symbol.makeRustBoxed(): Symbol =
51+
if (isRustBoxed()) {
52+
this
53+
} else {
54+
val rustType = RustType.Box(this.rustType())
55+
Symbol.builder()
56+
.rustType(rustType)
57+
.addReference(this)
58+
.name(rustType.name)
59+
.build()
60+
}
61+
62+
/**
63+
* Make the Rust type of a symbol wrapped in `MaybeConstrained`. (hold `MaybeConstrained<T>`).
64+
*
65+
* This is idempotent and will have no change if the type is already `MaybeConstrained<T>`.
66+
*/
67+
fun Symbol.makeMaybeConstrained(): Symbol =
68+
if (this.rustType() is RustType.MaybeConstrained) {
69+
this
70+
} else {
71+
val rustType = RustType.MaybeConstrained(this.rustType())
72+
Symbol.builder()
73+
.rustType(rustType)
74+
.addReference(this)
75+
.name(rustType.name)
76+
.build()
77+
}
78+
79+
/**
80+
* Map the [RustType] of a symbol with [f].
81+
*
82+
* WARNING: This function does not update any symbol references (e.g., `symbol.addReference()`) on the
83+
* returned symbol. You will have to add those yourself if your logic relies on them.
84+
**/
85+
fun Symbol.mapRustType(f: (RustType) -> RustType): Symbol {
86+
val newType = f(this.rustType())
87+
return Symbol.builder().rustType(newType)
88+
.name(newType.name)
89+
.build()
90+
}
91+
92+
/**
93+
* Type representing the default value for a given type (e.g. for Strings, this is `""`).
94+
*/
95+
sealed class Default {
96+
/**
97+
* This symbol has no default value. If the symbol is not optional, this will error during builder construction
98+
*/
99+
object NoDefault : Default()
100+
101+
/**
102+
* This symbol should use the Rust `std::default::Default` when unset
103+
*/
104+
object RustDefault : Default()
105+
}
106+
107+
/**
108+
* Returns true when it's valid to use the default/0 value for [this] symbol during construction.
109+
*/
110+
fun Symbol.canUseDefault(): Boolean = this.defaultValue() != Default.NoDefault
111+
112+
/**
113+
* True when [this] is will be represented by Option<T> in Rust
114+
*/
115+
fun Symbol.isOptional(): Boolean = when (this.rustType()) {
116+
is RustType.Option -> true
117+
else -> false
118+
}
119+
120+
fun Symbol.isRustBoxed(): Boolean = rustType().stripOuter<RustType.Option>() is RustType.Box
121+
122+
private const val RUST_TYPE_KEY = "rusttype"
123+
private const val SHAPE_KEY = "shape"
124+
private const val RUST_MODULE_KEY = "rustmodule"
125+
private const val RENAMED_FROM_KEY = "renamedfrom"
126+
private const val SYMBOL_DEFAULT = "symboldefault"
127+
128+
// Symbols should _always_ be created with a Rust type & shape attached
129+
fun Symbol.rustType(): RustType = this.expectProperty(RUST_TYPE_KEY, RustType::class.java)
130+
fun Symbol.Builder.rustType(rustType: RustType): Symbol.Builder = this.putProperty(RUST_TYPE_KEY, rustType)
131+
fun Symbol.shape(): Shape = this.expectProperty(SHAPE_KEY, Shape::class.java)
132+
fun Symbol.Builder.shape(shape: Shape?): Symbol.Builder = this.putProperty(SHAPE_KEY, shape)
133+
fun Symbol.module(): RustModule.LeafModule = this.expectProperty(RUST_MODULE_KEY, RustModule.LeafModule::class.java)
134+
fun Symbol.Builder.module(module: RustModule.LeafModule): Symbol.Builder = this.putProperty(RUST_MODULE_KEY, module)
135+
fun Symbol.renamedFrom(): String? = this.getProperty(RENAMED_FROM_KEY, String::class.java).orNull()
136+
fun Symbol.Builder.renamedFrom(name: String): Symbol.Builder = this.putProperty(RENAMED_FROM_KEY, name)
137+
fun Symbol.defaultValue(): Default = this.getProperty(SYMBOL_DEFAULT, Default::class.java).orElse(Default.NoDefault)
138+
fun Symbol.Builder.setDefault(default: Default): Symbol.Builder = this.putProperty(SYMBOL_DEFAULT, default)

codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolVisitor.kt

+2-135
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ import software.amazon.smithy.rust.codegen.core.rustlang.RustModule
4343
import software.amazon.smithy.rust.codegen.core.rustlang.RustReservedWords
4444
import software.amazon.smithy.rust.codegen.core.rustlang.RustType
4545
import software.amazon.smithy.rust.codegen.core.rustlang.Visibility
46-
import software.amazon.smithy.rust.codegen.core.rustlang.stripOuter
4746
import software.amazon.smithy.rust.codegen.core.smithy.traits.RustBoxTrait
4847
import software.amazon.smithy.rust.codegen.core.util.PANIC
4948
import software.amazon.smithy.rust.codegen.core.util.hasTrait
@@ -86,83 +85,6 @@ data class SymbolVisitorConfig(
8685
val moduleProvider: ModuleProvider,
8786
)
8887

89-
/**
90-
* Make the Rust type of a symbol optional (hold `Option<T>`)
91-
*
92-
* This is idempotent and will have no change if the type is already optional.
93-
*/
94-
fun Symbol.makeOptional(): Symbol =
95-
if (isOptional()) {
96-
this
97-
} else {
98-
val rustType = RustType.Option(this.rustType())
99-
Symbol.builder()
100-
.rustType(rustType)
101-
.addReference(this)
102-
.name(rustType.name)
103-
.build()
104-
}
105-
106-
/**
107-
* Make the Rust type of a symbol boxed (hold `Box<T>`).
108-
*
109-
* This is idempotent and will have no change if the type is already boxed.
110-
*/
111-
fun Symbol.makeRustBoxed(): Symbol =
112-
if (isRustBoxed()) {
113-
this
114-
} else {
115-
val rustType = RustType.Box(this.rustType())
116-
Symbol.builder()
117-
.rustType(rustType)
118-
.addReference(this)
119-
.name(rustType.name)
120-
.build()
121-
}
122-
123-
/**
124-
* Make the Rust type of a symbol wrapped in `MaybeConstrained`. (hold `MaybeConstrained<T>`).
125-
*
126-
* This is idempotent and will have no change if the type is already `MaybeConstrained<T>`.
127-
*/
128-
fun Symbol.makeMaybeConstrained(): Symbol =
129-
if (this.rustType() is RustType.MaybeConstrained) {
130-
this
131-
} else {
132-
val rustType = RustType.MaybeConstrained(this.rustType())
133-
Symbol.builder()
134-
.rustType(rustType)
135-
.addReference(this)
136-
.name(rustType.name)
137-
.build()
138-
}
139-
140-
/**
141-
* Map the [RustType] of a symbol with [f].
142-
*
143-
* WARNING: This function does not set any `SymbolReference`s on the returned symbol. You will have to add those
144-
* yourself if your logic relies on them.
145-
**/
146-
fun Symbol.mapRustType(f: (RustType) -> RustType): Symbol {
147-
val newType = f(this.rustType())
148-
return Symbol.builder().rustType(newType)
149-
.name(newType.name)
150-
.build()
151-
}
152-
153-
/** Set the symbolLocation for this symbol builder */
154-
fun Symbol.Builder.locatedIn(rustModule: RustModule.LeafModule): Symbol.Builder {
155-
val currentRustType = this.build().rustType()
156-
check(currentRustType is RustType.Opaque) {
157-
"Only `Opaque` can have their namespace updated"
158-
}
159-
val newRustType = currentRustType.copy(namespace = rustModule.fullyQualifiedPath())
160-
return this.definitionFile(rustModule.definitionFile())
161-
.namespace(rustModule.fullyQualifiedPath(), "::")
162-
.rustType(newRustType)
163-
.module(rustModule)
164-
}
165-
16688
/**
16789
* Track both the past and current name of a symbol
16890
*
@@ -401,28 +323,16 @@ fun handleRustBoxing(symbol: Symbol, shape: MemberShape): Symbol =
401323
symbol.makeRustBoxed()
402324
} else symbol
403325

404-
fun symbolBuilder(shape: Shape?, rustType: RustType): Symbol.Builder {
405-
val builder = Symbol.builder().putProperty(SHAPE_KEY, shape)
406-
return builder.rustType(rustType)
326+
fun symbolBuilder(shape: Shape?, rustType: RustType): Symbol.Builder =
327+
Symbol.builder().shape(shape).rustType(rustType)
407328
.name(rustType.name)
408329
// Every symbol that actually gets defined somewhere should set a definition file
409330
// If we ever generate a `thisisabug.rs`, there is a bug in our symbol generation
410331
.definitionFile("thisisabug.rs")
411-
}
412332

413333
fun handleOptionality(symbol: Symbol, member: MemberShape, nullableIndex: NullableIndex, nullabilityCheckMode: CheckMode): Symbol =
414334
symbol.letIf(nullableIndex.isMemberNullable(member, nullabilityCheckMode)) { symbol.makeOptional() }
415335

416-
private const val RUST_TYPE_KEY = "rusttype"
417-
private const val RUST_MODULE_KEY = "rustmodule"
418-
private const val SHAPE_KEY = "shape"
419-
private const val SYMBOL_DEFAULT = "symboldefault"
420-
private const val RENAMED_FROM_KEY = "renamedfrom"
421-
422-
fun Symbol.Builder.rustType(rustType: RustType): Symbol.Builder = this.putProperty(RUST_TYPE_KEY, rustType)
423-
fun Symbol.Builder.module(module: RustModule.LeafModule): Symbol.Builder = this.putProperty(RUST_MODULE_KEY, module)
424-
fun Symbol.module(): RustModule.LeafModule = this.expectProperty(RUST_MODULE_KEY, RustModule.LeafModule::class.java)
425-
426336
/**
427337
* Creates a test module for this symbol.
428338
* For example if the symbol represents the name for the struct `struct MyStruct { ... }`,
@@ -445,49 +355,6 @@ fun SymbolProvider.testModuleForShape(shape: Shape): RustModule.LeafModule {
445355
)
446356
}
447357

448-
fun Symbol.Builder.renamedFrom(name: String): Symbol.Builder {
449-
return this.putProperty(RENAMED_FROM_KEY, name)
450-
}
451-
452-
fun Symbol.renamedFrom(): String? = this.getProperty(RENAMED_FROM_KEY, String::class.java).orNull()
453-
454-
fun Symbol.defaultValue(): Default = this.getProperty(SYMBOL_DEFAULT, Default::class.java).orElse(Default.NoDefault)
455-
fun Symbol.Builder.setDefault(default: Default): Symbol.Builder = this.putProperty(SYMBOL_DEFAULT, default)
456-
457-
/**
458-
* Type representing the default value for a given type. (eg. for Strings, this is `""`)
459-
*/
460-
sealed class Default {
461-
/**
462-
* This symbol has no default value. If the symbol is not optional, this will be an error during builder construction
463-
*/
464-
object NoDefault : Default()
465-
466-
/**
467-
* This symbol should use the Rust `std::default::Default` when unset
468-
*/
469-
object RustDefault : Default()
470-
}
471-
472-
/**
473-
* True when it is valid to use the default/0 value for [this] symbol during construction.
474-
*/
475-
fun Symbol.canUseDefault(): Boolean = this.defaultValue() != Default.NoDefault
476-
477-
/**
478-
* True when [this] is will be represented by Option<T> in Rust
479-
*/
480-
fun Symbol.isOptional(): Boolean = when (this.rustType()) {
481-
is RustType.Option -> true
482-
else -> false
483-
}
484-
485-
fun Symbol.isRustBoxed(): Boolean = rustType().stripOuter<RustType.Option>() is RustType.Box
486-
487-
// Symbols should _always_ be created with a Rust type & shape attached
488-
fun Symbol.rustType(): RustType = this.expectProperty(RUST_TYPE_KEY, RustType::class.java)
489-
fun Symbol.shape(): Shape = this.expectProperty(SHAPE_KEY, Shape::class.java)
490-
491358
/**
492359
* You should rarely need this function, rust names in general should be symbol-aware,
493360
* this is "automatic" if you use things like [software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate].

0 commit comments

Comments
 (0)