Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Finish the JSON serialization refactor #423

Merged
merged 6 commits into from
May 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 35 additions & 1 deletion codegen-test/model/rest-json-extras.smithy
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ apply QueryPrecedence @httpRequestTests([
@restJson1
service RestJsonExtras {
version: "2019-12-16",
operations: [StringPayload, PrimitiveIntHeader, EnumQuery, StatusResponse]
operations: [StringPayload, PrimitiveIntHeader, EnumQuery, StatusResponse, MapWithEnumKeyOp]
}

@http(uri: "/StringPayload", method: "POST")
Expand Down Expand Up @@ -135,3 +135,37 @@ structure StatusOutput {
@httpResponseCode
field: PrimitiveInt
}

map MapWithEnumKey {
key: StringEnum,
value: String,
}

structure MapWithEnumKeyInputOutput {
map: MapWithEnumKey,
}

@http(uri: "/map-with-enum-key", method: "POST")
@httpRequestTests([
{
id: "MapWithEnumKeyRequest",
uri: "/map-with-enum-key",
method: "POST",
protocol: "aws.protocols#restJson1",
body: "{\"map\":{\"enumvalue\":\"something\"}}",
params: { map: { "enumvalue": "something" } }
},
])
@httpResponseTests([
{
id: "MapWithEnumKeyResponse",
protocol: "aws.protocols#restJson1",
code: 200,
body: "{\"map\":{\"enumvalue\":\"something\"}}",
params: { map: { "enumvalue": "something" } },
},
])
operation MapWithEnumKeyOp {
input: MapWithEnumKeyInputOutput,
output: MapWithEnumKeyInputOutput,
}
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,7 @@ data class RuntimeType(val name: String?, val dependency: RustDependency?, val n
path, dependency = CargoDependency.Serde, namespace = "serde"
)

val Serialize = RuntimeType("Serialize", CargoDependency.Serde, namespace = "serde")
val Deserialize: RuntimeType = RuntimeType("Deserialize", CargoDependency.Serde, namespace = "serde")
val Serializer = RuntimeType("Serializer", CargoDependency.Serde, namespace = "serde")
val Deserializer = RuntimeType("Deserializer", CargoDependency.Serde, namespace = "serde")
fun SerdeJson(path: String) =
RuntimeType(path, dependency = CargoDependency.SerdeJson, namespace = "serde_json")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,21 +176,13 @@ class EnumGenerator(
private fun renderSerde() {
writer.rustTemplate(
"""
impl #{serialize} for $enumName {
fn serialize<S>(&self, serializer: S) -> Result<<S as #{serializer}>::Ok, <S as #{serializer}>::Error> where S: #{serializer}{
serializer.serialize_str(self.as_str())
}
}

impl<'de> #{deserialize}<'de> for $enumName {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: #{deserializer}<'de> {
let data = <&str>::deserialize(deserializer)?;
Ok(Self::from(data))
}
}
""",
"serializer" to RuntimeType.Serializer,
"serialize" to RuntimeType.Serialize,
"deserializer" to RuntimeType.Deserializer,
"deserialize" to RuntimeType.Deserialize
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ import software.amazon.smithy.rust.codegen.smithy.letIf
import software.amazon.smithy.rust.codegen.smithy.rustType
import software.amazon.smithy.rust.codegen.util.dq
import software.amazon.smithy.rust.codegen.util.expectMember
import software.amazon.smithy.rust.codegen.util.getTrait
import software.amazon.smithy.rust.codegen.util.hasTrait
import software.amazon.smithy.rust.codegen.util.isStreaming
import software.amazon.smithy.rust.codegen.util.toPascalCase

Expand Down Expand Up @@ -126,12 +126,7 @@ class Instantiator(
* If the shape is optional: `Some(inner)` or `None`
* otherwise: `inner`
*/
private fun renderMember(
writer: RustWriter,
shape: MemberShape,
arg: Node,
ctx: Ctx
) {
private fun renderMember(writer: RustWriter, shape: MemberShape, arg: Node, ctx: Ctx) {
val target = model.expectShape(shape.target)
val symbol = symbolProvider.toSymbol(shape)
if (arg is NullNode) {
Expand Down Expand Up @@ -176,28 +171,24 @@ class Instantiator(
* ret
* }
*/
private fun renderMap(
writer: RustWriter,
shape: MapShape,
data: ObjectNode,
ctx: Ctx,
) {
val lowercase = when (ctx.lowercaseMapKeys) {
true -> ".to_ascii_lowercase()"
else -> ""
}
if (data.members.isNotEmpty()) {
private fun renderMap(writer: RustWriter, shape: MapShape, data: ObjectNode, ctx: Ctx) {
if (data.members.isEmpty()) {
writer.write("#T::new()", RustType.HashMap.RuntimeType)
} else {
writer.rustBlock("") {
write("let mut ret = #T::new();", RustType.HashMap.RuntimeType)
data.members.forEach { (k, v) ->
withBlock("ret.insert(${k.value.dq()}.to_string()$lowercase,", ");") {
renderMember(this, shape.value, v, ctx)
for ((key, value) in data.members) {
withBlock("ret.insert(", ");") {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should actually just be able to use renderMember(this, shape.key, k, ctx)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great suggestion. Fixed.

renderMember(this, shape.key, key, ctx)
when (ctx.lowercaseMapKeys) {
true -> rust(".to_ascii_lowercase(), ")
else -> rust(", ")
}
renderMember(this, shape.value, value, ctx)
}
}
write("ret")
}
} else {
writer.write("#T::new()", RustType.HashMap.RuntimeType)
}
}

Expand All @@ -206,12 +197,7 @@ class Instantiator(
* MyUnion::Variant(...)
* ```
*/
private fun renderUnion(
writer: RustWriter,
shape: UnionShape,
data: ObjectNode,
ctx: Ctx
) {
private fun renderUnion(writer: RustWriter, shape: UnionShape, data: ObjectNode, ctx: Ctx) {
val unionSymbol = symbolProvider.toSymbol(shape)
check(data.members.size == 1)
val variant = data.members.iterator().next()
Expand All @@ -230,12 +216,7 @@ class Instantiator(
* vec![..., ..., ...]
* ```
*/
private fun renderList(
writer: RustWriter,
shape: CollectionShape,
data: ArrayNode,
ctx: Ctx
) {
private fun renderList(writer: RustWriter, shape: CollectionShape, data: ArrayNode, ctx: Ctx) {
writer.withBlock("vec![", "]") {
data.elements.forEach { v ->
renderMember(this, shape.member, v, ctx)
Expand All @@ -244,14 +225,9 @@ class Instantiator(
}
}

private fun renderString(
writer: RustWriter,
shape: StringShape,
arg: StringNode
) {
val enumTrait = shape.getTrait<EnumTrait>()
private fun renderString(writer: RustWriter, shape: StringShape, arg: StringNode) {
val data = writer.escape(arg.value).dq()
if (enumTrait == null) {
if (!shape.hasTrait<EnumTrait>()) {
writer.rust("$data.to_string()")
} else {
val enumSymbol = symbolProvider.toSymbol(shape)
Expand All @@ -264,12 +240,7 @@ class Instantiator(
* MyStruct::builder().field_1("hello").field_2(5).build()
* ```
*/
private fun renderStructure(
writer: RustWriter,
shape: StructureShape,
data: ObjectNode,
ctx: Ctx
) {
private fun renderStructure(writer: RustWriter, shape: StructureShape, data: ObjectNode, ctx: Ctx) {
writer.write("#T::builder()", symbolProvider.toSymbol(shape))
data.members.forEach { (key, value) ->
val memberShape = shape.expectMember(key.value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ import software.amazon.smithy.rust.codegen.smithy.generators.error.errorSymbol
import software.amazon.smithy.rust.codegen.smithy.generators.operationBuildError
import software.amazon.smithy.rust.codegen.smithy.locatedIn
import software.amazon.smithy.rust.codegen.smithy.meta
import software.amazon.smithy.rust.codegen.smithy.protocols.parsers.JsonSerializerGenerator
import software.amazon.smithy.rust.codegen.smithy.protocols.parsers.SerdeJsonParserGenerator
import software.amazon.smithy.rust.codegen.smithy.protocols.parsers.SerdeJsonSerializerGenerator
import software.amazon.smithy.rust.codegen.smithy.rustType
import software.amazon.smithy.rust.codegen.smithy.traits.InputBodyTrait
import software.amazon.smithy.rust.codegen.smithy.traits.OutputBodyTrait
Expand Down Expand Up @@ -198,7 +198,7 @@ class BasicAwsJsonGenerator(
}

override fun RustWriter.body(self: String, operationShape: OperationShape): BodyMetadata {
val generator = SerdeJsonSerializerGenerator(protocolConfig)
val generator = JsonSerializerGenerator(protocolConfig)
val serializer = generator.operationSerializer(operationShape)
serializer?.also { sym ->
rustTemplate(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ import software.amazon.smithy.rust.codegen.smithy.RustSymbolProvider
import software.amazon.smithy.rust.codegen.smithy.generators.ProtocolConfig
import software.amazon.smithy.rust.codegen.smithy.generators.ProtocolGeneratorFactory
import software.amazon.smithy.rust.codegen.smithy.generators.ProtocolSupport
import software.amazon.smithy.rust.codegen.smithy.protocols.parsers.JsonSerializerGenerator
import software.amazon.smithy.rust.codegen.smithy.protocols.parsers.SerdeJsonParserGenerator
import software.amazon.smithy.rust.codegen.smithy.protocols.parsers.SerdeJsonSerializerGenerator
import software.amazon.smithy.rust.codegen.smithy.protocols.parsers.StructuredDataParserGenerator
import software.amazon.smithy.rust.codegen.smithy.protocols.parsers.StructuredDataSerializerGenerator
import software.amazon.smithy.rust.codegen.smithy.transformers.OperationNormalizer
Expand Down Expand Up @@ -81,7 +81,7 @@ class RestJson(private val protocolConfig: ProtocolConfig) : Protocol {
}

override fun structuredDataSerializer(operationShape: OperationShape): StructuredDataSerializerGenerator {
return SerdeJsonSerializerGenerator(protocolConfig)
return JsonSerializerGenerator(protocolConfig)
}

override fun parseGenericError(operationShape: OperationShape): RuntimeType {
Expand Down
Loading