Skip to content

Commit

Permalink
codegen-serde: traverse operations of resources (#3882)
Browse files Browse the repository at this point in the history
The current implementation doesn't traverse a resource's operations if
the serialization root is a service shape; the added test fails without
this fix.

----

_By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice._
  • Loading branch information
david-perez authored Oct 17, 2024
1 parent ef07c88 commit eb48261
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package software.amazon.smithy.rust.codegen.serde

import software.amazon.smithy.codegen.core.Symbol
import software.amazon.smithy.model.knowledge.TopDownIndex
import software.amazon.smithy.model.shapes.BlobShape
import software.amazon.smithy.model.shapes.BooleanShape
import software.amazon.smithy.model.shapes.CollectionShape
Expand Down Expand Up @@ -61,6 +62,7 @@ import software.amazon.smithy.rust.codegen.server.smithy.hasConstraintTrait

class SerializeImplGenerator(private val codegenContext: CodegenContext) {
private val model = codegenContext.model
private val topIndex = TopDownIndex.of(model)

fun generateRootSerializerForShape(shape: Shape): Writable = serializerFn(shape, null)

Expand All @@ -78,7 +80,9 @@ class SerializeImplGenerator(private val codegenContext: CodegenContext) {
applyTo: Writable?,
): Writable {
if (shape is ServiceShape) {
return shape.operations.map { serializerFn(model.expectShape(it), null) }.join("\n")
return topIndex.getContainedOperations(shape).map {
serializerFn(it, null)
}.join("\n")
} else if (shape is OperationShape) {
if (shape.isEventStream(model)) {
// Don't generate serializers for event streams
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,58 @@ class SerdeDecoratorTest {
structure NotSerde {}
""".asSmithyModel(smithyVersion = "2")

@Test
fun `decorator should traverse resources`() {
val model =
"""
namespace com.example
use smithy.rust#serde
use aws.protocols#awsJson1_0
@awsJson1_0
@serde
service MyResourceService {
resources: [MyResource]
}
resource MyResource {
read: ReadMyResource
}
@readonly
operation ReadMyResource {
input := { }
}
""".asSmithyModel(smithyVersion = "2")

val params =
IntegrationTestParams(cargoCommand = "cargo test --all-features", service = "com.example#MyResourceService")
serverIntegrationTest(model, params = params) { ctx, crate ->
val codegenScope =
arrayOf(
"crate" to RustType.Opaque(ctx.moduleUseName()),
"serde_json" to CargoDependency("serde_json", CratesIo("1")).toDevDependency().toType(),
// we need the derive feature
"serde" to CargoDependency.Serde.toDevDependency().toType(),
)

crate.integrationTest("test_serde") {
unitTest("input_serialized") {
rustTemplate(
"""
use #{crate}::input::ReadMyResourceInput;
use #{crate}::serde::*;
let input = ReadMyResourceInput { };
let settings = SerializationSettings::default();
let _serialized = #{serde_json}::to_string(&input.serialize_ref(&settings)).expect("failed to serialize");
""",
*codegenScope,
)
}
}
}
}

@Test
fun generateSerializersThatWorkServer() {
serverIntegrationTest(simpleModel, params = params) { ctx, crate ->
Expand Down

0 comments on commit eb48261

Please sign in to comment.