Skip to content

Commit b9016ae

Browse files
committed
Add RPCv2 support
1 parent 9c1ae5a commit b9016ae

File tree

68 files changed

+4022
-120
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+4022
-120
lines changed

aws/sdk-adhoc-test/build.gradle.kts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ java {
2020
}
2121

2222
val smithyVersion: String by project
23-
val defaultRustDocFlags: String by project
2423
val properties = PropertyRetriever(rootProject, project)
2524

2625
val pluginName = "rust-client-codegen"
@@ -78,7 +77,7 @@ tasks["smithyBuild"].dependsOn("generateSmithyBuild")
7877
tasks["assemble"].finalizedBy("generateCargoWorkspace")
7978

8079
project.registerModifyMtimeTask()
81-
project.registerCargoCommandsTasks(layout.buildDirectory.dir(workingDirUnderBuildDir).get().asFile, defaultRustDocFlags)
80+
project.registerCargoCommandsTasks(layout.buildDirectory.dir(workingDirUnderBuildDir).get().asFile)
8281

8382
tasks["test"].finalizedBy(cargoCommands(properties).map { it.toString })
8483

aws/sdk/build.gradle.kts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ configure<software.amazon.smithy.gradle.SmithyExtension> {
3131
}
3232

3333
val smithyVersion: String by project
34-
val defaultRustDocFlags: String by project
3534
val properties = PropertyRetriever(rootProject, project)
3635

3736
val crateHasherToolPath = rootProject.projectDir.resolve("tools/ci-build/crate-hasher")
@@ -442,7 +441,7 @@ tasks["assemble"].apply {
442441
outputs.upToDateWhen { false }
443442
}
444443

445-
project.registerCargoCommandsTasks(outputDir.asFile, defaultRustDocFlags)
444+
project.registerCargoCommandsTasks(outputDir.asFile)
446445
project.registerGenerateCargoConfigTomlTask(outputDir.asFile)
447446

448447
//The task name "test" is already registered by one of our plugins

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ allprojects {
1818
val allowLocalDeps: String by project
1919
repositories {
2020
if (allowLocalDeps.toBoolean()) {
21-
mavenLocal()
21+
mavenLocal()
2222
}
2323
mavenCentral()
2424
google()

buildSrc/src/main/kotlin/CodegenTestCommon.kt

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,49 @@ fun generateImports(imports: List<String>): String =
2929
"\"imports\": [${imports.map { "\"$it\"" }.joinToString(", ")}],"
3030
}
3131

32+
fun toRustCrateName(input: String): String {
33+
val rustKeywords = setOf(
34+
// Strict Keywords.
35+
"as", "break", "const", "continue", "crate", "else", "enum", "extern",
36+
"false", "fn", "for", "if", "impl", "in", "let", "loop", "match", "mod",
37+
"move", "mut", "pub", "ref", "return", "Self", "self", "static", "struct",
38+
"super", "trait", "true", "type", "unsafe", "use", "where", "while",
39+
40+
// Weak Keywords.
41+
"dyn", "async", "await", "try",
42+
43+
// Reserved for Future Use.
44+
"abstract", "become", "box", "do", "final", "macro", "override", "priv",
45+
"typeof", "unsized", "virtual", "yield",
46+
47+
// Primitive Types.
48+
"bool", "char", "i8", "i16", "i32", "i64", "i128", "isize",
49+
"u8", "u16", "u32", "u64", "u128", "usize", "f32", "f64", "str",
50+
51+
// Additional significant identifiers.
52+
"proc_macro"
53+
)
54+
55+
// Then within your function, you could include a check against this set
56+
if (input.isBlank()) {
57+
throw IllegalArgumentException("Rust crate name cannot be empty")
58+
}
59+
val lowerCased = input.lowercase()
60+
// Replace any sequence of characters that are not lowercase letters, numbers, or underscores with a single underscore.
61+
val sanitized = lowerCased.replace(Regex("[^a-z0-9_]+"), "_")
62+
// Trim leading or trailing underscores.
63+
val trimmed = sanitized.trim('_')
64+
// Check if the resulting string is empty, purely numeric, or a reserved name
65+
val finalName = when {
66+
trimmed.isEmpty() -> throw IllegalArgumentException("Rust crate name after sanitizing cannot be empty.")
67+
trimmed.matches(Regex("\\d+")) -> "n$trimmed" // Prepend 'n' if the name is purely numeric.
68+
trimmed in rustKeywords -> "${trimmed}_" // Append an underscore if the name is reserved.
69+
else -> trimmed
70+
}
71+
return finalName
72+
}
73+
74+
3275
private fun generateSmithyBuild(
3376
projectDir: String,
3477
pluginName: String,
@@ -48,7 +91,7 @@ private fun generateSmithyBuild(
4891
${it.extraCodegenConfig ?: ""}
4992
},
5093
"service": "${it.service}",
51-
"module": "${it.module}",
94+
"module": "${toRustCrateName(it.module)}",
5295
"moduleVersion": "0.0.1",
5396
"moduleDescription": "test",
5497
"moduleAuthors": ["[email protected]"]
@@ -205,13 +248,15 @@ fun Project.registerGenerateCargoWorkspaceTask(
205248
fun Project.registerGenerateCargoConfigTomlTask(outputDir: File) {
206249
this.tasks.register("generateCargoConfigToml") {
207250
description = "generate `.cargo/config.toml`"
251+
// TODO(https://github.com/smithy-lang/smithy-rs/issues/1068): Once doc normalization
252+
// is completed, warnings can be prohibited in rustdoc by setting `rustdocflags` to `-D warnings`.
208253
doFirst {
209254
outputDir.resolve(".cargo").mkdirs()
210255
outputDir.resolve(".cargo/config.toml")
211256
.writeText(
212257
"""
213258
[build]
214-
rustflags = ["--deny", "warnings"]
259+
rustflags = ["--deny", "warnings", "--cfg", "aws_sdk_unstable"]
215260
""".trimIndent(),
216261
)
217262
}
@@ -255,10 +300,7 @@ fun Project.registerModifyMtimeTask() {
255300
}
256301
}
257302

258-
fun Project.registerCargoCommandsTasks(
259-
outputDir: File,
260-
defaultRustDocFlags: String,
261-
) {
303+
fun Project.registerCargoCommandsTasks(outputDir: File) {
262304
val dependentTasks =
263305
listOfNotNull(
264306
"assemble",
@@ -269,29 +311,24 @@ fun Project.registerCargoCommandsTasks(
269311
this.tasks.register<Exec>(Cargo.CHECK.toString) {
270312
dependsOn(dependentTasks)
271313
workingDir(outputDir)
272-
environment("RUSTFLAGS", "--cfg aws_sdk_unstable")
273314
commandLine("cargo", "check", "--lib", "--tests", "--benches", "--all-features")
274315
}
275316

276317
this.tasks.register<Exec>(Cargo.TEST.toString) {
277318
dependsOn(dependentTasks)
278319
workingDir(outputDir)
279-
environment("RUSTFLAGS", "--cfg aws_sdk_unstable")
280320
commandLine("cargo", "test", "--all-features", "--no-fail-fast")
281321
}
282322

283323
this.tasks.register<Exec>(Cargo.DOCS.toString) {
284324
dependsOn(dependentTasks)
285325
workingDir(outputDir)
286-
environment("RUSTDOCFLAGS", defaultRustDocFlags)
287-
environment("RUSTFLAGS", "--cfg aws_sdk_unstable")
288326
commandLine("cargo", "doc", "--no-deps", "--document-private-items")
289327
}
290328

291329
this.tasks.register<Exec>(Cargo.CLIPPY.toString) {
292330
dependsOn(dependentTasks)
293331
workingDir(outputDir)
294-
environment("RUSTFLAGS", "--cfg aws_sdk_unstable")
295332
commandLine("cargo", "clippy")
296333
}
297334
}

codegen-client-test/build.gradle.kts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ plugins {
1515
}
1616

1717
val smithyVersion: String by project
18-
val defaultRustDocFlags: String by project
1918
val properties = PropertyRetriever(rootProject, project)
2019
fun getSmithyRuntimeMode(): String = properties.get("smithy.runtime.mode") ?: "orchestrator"
2120

@@ -112,6 +111,11 @@ val allCodegenTests = listOf(
112111
"pokemon-service-awsjson-client",
113112
dependsOn = listOf("pokemon-awsjson.smithy", "pokemon-common.smithy"),
114113
),
114+
ClientTest(
115+
"com.amazonaws.simple#RpcV2Service",
116+
"rpcv2-pokemon-client",
117+
dependsOn = listOf("rpcv2.smithy")
118+
),
115119
ClientTest("aws.protocoltests.misc#QueryCompatService", "query-compat-test", dependsOn = listOf("aws-json-query-compat.smithy")),
116120
).map(ClientTest::toCodegenTest)
117121

@@ -125,7 +129,7 @@ tasks["smithyBuild"].dependsOn("generateSmithyBuild")
125129
tasks["assemble"].finalizedBy("generateCargoWorkspace")
126130

127131
project.registerModifyMtimeTask()
128-
project.registerCargoCommandsTasks(layout.buildDirectory.dir(workingDirUnderBuildDir).get().asFile, defaultRustDocFlags)
132+
project.registerCargoCommandsTasks(layout.buildDirectory.dir(workingDirUnderBuildDir).get().asFile)
129133

130134
tasks["test"].finalizedBy(cargoCommands(properties).map { it.toString })
131135

codegen-client/build.gradle.kts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,10 @@ dependencies {
2727
implementation("software.amazon.smithy:smithy-protocol-test-traits:$smithyVersion")
2828
implementation("software.amazon.smithy:smithy-waiters:$smithyVersion")
2929
implementation("software.amazon.smithy:smithy-rules-engine:$smithyVersion")
30+
implementation("software.amazon.smithy:smithy-protocol-traits:$smithyVersion")
3031

3132
// `smithy.framework#ValidationException` is defined here, which is used in event stream
32-
// marshalling/unmarshalling tests.
33+
// marshalling/unmarshalling tests.
3334
testImplementation("software.amazon.smithy:smithy-validation-model:$smithyVersion")
3435
}
3536

codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolTestGenerator.kt

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ import software.amazon.smithy.rust.codegen.core.rustlang.rustBlock
3333
import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate
3434
import software.amazon.smithy.rust.codegen.core.rustlang.withBlock
3535
import software.amazon.smithy.rust.codegen.core.rustlang.writable
36+
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType
3637
import software.amazon.smithy.rust.codegen.core.smithy.generators.protocol.ProtocolSupport
38+
import software.amazon.smithy.rust.codegen.core.testutil.testDependenciesOnly
3739
import software.amazon.smithy.rust.codegen.core.util.dq
3840
import software.amazon.smithy.rust.codegen.core.util.getTrait
3941
import software.amazon.smithy.rust.codegen.core.util.hasTrait
@@ -173,13 +175,19 @@ class DefaultProtocolTestGenerator(
173175
}
174176
testModuleWriter.write("Test ID: ${testCase.id}")
175177
testModuleWriter.newlinePrefix = ""
178+
176179
Attribute.TokioTest.render(testModuleWriter)
177-
val action =
178-
when (testCase) {
179-
is HttpResponseTestCase -> Action.Response
180-
is HttpRequestTestCase -> Action.Request
181-
else -> throw CodegenException("unknown test case type")
182-
}
180+
Attribute.TracedTest.render(testModuleWriter)
181+
// The `#[traced_test]` macro desugars to using `tracing`, so we need to depend on the latter explicitly in
182+
// case the code rendered by the test does not make use of `tracing` at all.
183+
val tracingDevDependency = testDependenciesOnly { addDependency(CargoDependency.Tracing.toDevDependency()) }
184+
testModuleWriter.rustTemplate("#{TracingDevDependency:W}", "TracingDevDependency" to tracingDevDependency)
185+
186+
val action = when (testCase) {
187+
is HttpResponseTestCase -> Action.Response
188+
is HttpRequestTestCase -> Action.Request
189+
else -> throw CodegenException("unknown test case type")
190+
}
183191
if (expectFail(testCase)) {
184192
testModuleWriter.writeWithNoFormatting("#[should_panic]")
185193
}
@@ -415,8 +423,8 @@ class DefaultProtocolTestGenerator(
415423
if (body == "") {
416424
rustWriter.rustTemplate(
417425
"""
418-
// No body
419-
#{AssertEq}(::std::str::from_utf8(body).unwrap(), "");
426+
// No body.
427+
#{AssertEq}(&body, &bytes::Bytes::new());
420428
""",
421429
*codegenScope,
422430
)

codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/ClientProtocolLoader.kt

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import software.amazon.smithy.aws.traits.protocols.Ec2QueryTrait
1313
import software.amazon.smithy.aws.traits.protocols.RestJson1Trait
1414
import software.amazon.smithy.aws.traits.protocols.RestXmlTrait
1515
import software.amazon.smithy.model.shapes.ServiceShape
16+
import software.amazon.smithy.protocol.traits.Rpcv2CborTrait
1617
import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext
1718
import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationGenerator
1819
import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext
@@ -28,20 +29,21 @@ import software.amazon.smithy.rust.codegen.core.smithy.protocols.ProtocolLoader
2829
import software.amazon.smithy.rust.codegen.core.smithy.protocols.ProtocolMap
2930
import software.amazon.smithy.rust.codegen.core.smithy.protocols.RestJson
3031
import software.amazon.smithy.rust.codegen.core.smithy.protocols.RestXml
32+
import software.amazon.smithy.rust.codegen.core.smithy.protocols.RpcV2
3133
import software.amazon.smithy.rust.codegen.core.util.hasTrait
3234

3335
class ClientProtocolLoader(supportedProtocols: ProtocolMap<OperationGenerator, ClientCodegenContext>) :
3436
ProtocolLoader<OperationGenerator, ClientCodegenContext>(supportedProtocols) {
3537
companion object {
36-
val DefaultProtocols =
37-
mapOf(
38-
AwsJson1_0Trait.ID to ClientAwsJsonFactory(AwsJsonVersion.Json10),
39-
AwsJson1_1Trait.ID to ClientAwsJsonFactory(AwsJsonVersion.Json11),
40-
AwsQueryTrait.ID to ClientAwsQueryFactory(),
41-
Ec2QueryTrait.ID to ClientEc2QueryFactory(),
42-
RestJson1Trait.ID to ClientRestJsonFactory(),
43-
RestXmlTrait.ID to ClientRestXmlFactory(),
44-
)
38+
val DefaultProtocols = mapOf(
39+
AwsJson1_0Trait.ID to ClientAwsJsonFactory(AwsJsonVersion.Json10),
40+
AwsJson1_1Trait.ID to ClientAwsJsonFactory(AwsJsonVersion.Json11),
41+
AwsQueryTrait.ID to ClientAwsQueryFactory(),
42+
Ec2QueryTrait.ID to ClientEc2QueryFactory(),
43+
RestJson1Trait.ID to ClientRestJsonFactory(),
44+
RestXmlTrait.ID to ClientRestXmlFactory(),
45+
Rpcv2CborTrait.ID to ClientRpcV2CborFactory(),
46+
)
4547
val Default = ClientProtocolLoader(DefaultProtocols)
4648
}
4749
}
@@ -117,3 +119,12 @@ class ClientRestXmlFactory(
117119

118120
override fun support(): ProtocolSupport = CLIENT_PROTOCOL_SUPPORT
119121
}
122+
123+
class ClientRpcV2CborFactory : ProtocolGeneratorFactory<OperationGenerator, ClientCodegenContext> {
124+
override fun protocol(codegenContext: ClientCodegenContext): Protocol = RpcV2(codegenContext)
125+
126+
override fun buildProtocolGenerator(codegenContext: ClientCodegenContext): OperationGenerator =
127+
OperationGenerator(codegenContext, protocol(codegenContext))
128+
129+
override fun support(): ProtocolSupport = CLIENT_PROTOCOL_SUPPORT
130+
}

codegen-core/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ dependencies {
2828
implementation("software.amazon.smithy:smithy-aws-traits:$smithyVersion")
2929
implementation("software.amazon.smithy:smithy-protocol-test-traits:$smithyVersion")
3030
implementation("software.amazon.smithy:smithy-waiters:$smithyVersion")
31+
implementation("software.amazon.smithy:smithy-protocol-traits:$smithyVersion")
3132
}
3233

3334
fun gitCommitHash(): String {

0 commit comments

Comments
 (0)