-
Notifications
You must be signed in to change notification settings - Fork 197
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
Add initial implementation of a Serde Decorator #3753
Conversation
A new generated diff is ready to view.
A new doc preview is ready to view. |
A new generated diff is ready to view.
A new doc preview is ready to view. |
A new generated diff is ready to view.
A new doc preview is ready to view. |
A new generated diff is ready to view.
A new doc preview is ready to view. |
A new generated diff is ready to view.
A new doc preview is ready to view. |
} | ||
|
||
java { | ||
sourceCompatibility = JavaVersion.VERSION_11 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aren't we on v17 now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh dono, I copied this from codegen core, can change it to whatever.
...erde/src/main/kotlin/software/amazon/smithy/rust/codegen/serde/KotlinClientSerdeDecorator.kt
Outdated
Show resolved
Hide resolved
...erde/src/main/kotlin/software/amazon/smithy/rust/codegen/serde/KotlinClientSerdeDecorator.kt
Outdated
Show resolved
Hide resolved
...erde/src/main/kotlin/software/amazon/smithy/rust/codegen/serde/KotlinClientSerdeDecorator.kt
Outdated
Show resolved
Hide resolved
return RuntimeType.forInlineFun(codegenContext.symbolProvider.toSymbol(shape).rustType().toString(), Module) { | ||
implSerializeConfigured(codegenContext.symbolProvider.toSymbol(shape)) { | ||
val baseValue = | ||
writable { rust("self.value") }.letIf(shape.isStringShape) { it.plus(writable(".as_str()")) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is super cool, I didn't realize we could conditionally extend writables like this!
...erde/src/main/kotlin/software/amazon/smithy/rust/codegen/serde/KotlinClientSerdeDecorator.kt
Outdated
Show resolved
Hide resolved
...erde/src/main/kotlin/software/amazon/smithy/rust/codegen/serde/KotlinClientSerdeDecorator.kt
Outdated
Show resolved
Hide resolved
codegen-serde/src/main/kotlin/software/amazon/smithy/rust/codegen/serde/Traits.kt
Outdated
Show resolved
Hide resolved
971662e
to
a88f021
Compare
A new generated diff is ready to view.
A new doc preview is ready to view. |
A new generated diff is ready to view.
A new doc preview is ready to view. |
...en-serde/src/main/kotlin/software/amazon/smithy/rust/codegen/serde/SerializeImplGenerator.kt
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea separating the implementation of serialization and deserialization.
A new generated diff is ready to view.
A new doc preview is ready to view. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Brilliant piece of work!
A new generated diff is ready to view.
A new doc preview is ready to view. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the solution explained in the RFC.
Main issue with current implementation is that it won't handle constrained shapes in the server, for which we generate Rust newtypes.
Something that would make us gain confidence in the implementation is if we integration tested against the constraints.smithy
model (or any large model like the restJson1
one), post transforming it to add @serde
to the service shape.
Have a look at this test:
Line 116 in c63e792
var model = Model.assembler().discoverModels().assemble().result.get() |
This RFC defines how smithy-rs will enable customers to use the [serde](serde.rs) library with generated clients & servers. This is a common request | ||
for myriad reasons, but as we have written about [before](https://github.com/awslabs/aws-sdk-rust/issues/269#issuecomment-1227518721) this is a challenging design area. This RFC proposes a new approach: **Rather than implement `Serialize` directly, add a method to types that returns a type that implements `Serialize`.** This solves a number of issues: | ||
|
||
1. It is minimally impactful: It doesn't lock us into one `Serialize` implementation. It contains only one public trait, `SerializeConfigured`. This trait will initially be defined on a per-crate basis to avoid the orphan-trait rule. It doesn't also doesn't have any impact on shared runtime crates (since no types actually need to implement serialize). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1. It is minimally impactful: It doesn't lock us into one `Serialize` implementation. It contains only one public trait, `SerializeConfigured`. This trait will initially be defined on a per-crate basis to avoid the orphan-trait rule. It doesn't also doesn't have any impact on shared runtime crates (since no types actually need to implement serialize). | |
1. It is minimally impactful: It doesn't lock us into one `Serialize` implementation. It contains only one public trait, `SerializeConfigured`. This trait will initially be defined on a per-crate basis to avoid the orphan-trait rule. It also doesn't have any impact on shared runtime crates (since no types actually need to implement serialize). |
return writable { | ||
serializerFn(target) { | ||
rust("&$memberRef") | ||
}.plus { rust(".serialize_ref(&self.settings)") }(this) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm Clippy should catch this, there's no need for &
here. Which makes me think that we're not running cargo clippy --all-features
in CI.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed we aren't. I'm guessing toggling --all-features
will cause other things to fail, so we should probably cut a separate GitHub issue.
commandLine("cargo", "clippy") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed clippy lints in the generated code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The unnecessary iter
s are still there. Can we run integration tests with --all-features
in CI, or at least have a tracking issue for it?
codegen-serde/src/main/kotlin/software/amazon/smithy/rust/codegen/serde/SerdeDecorator.kt
Show resolved
Hide resolved
...en-serde/src/main/kotlin/software/amazon/smithy/rust/codegen/serde/SerializeImplGenerator.kt
Show resolved
Hide resolved
#{Document}::Object(v) => { | ||
use #{serde}::ser::SerializeMap; | ||
let mut map = serializer.serialize_map(Some(v.len()))?; | ||
for (k, v) in v.iter() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these iter()
needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no, removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They're still there.
codegen-serde/src/test/kotlin/software/amazon/smithy/rust/codegen/serde/SerdeDecoratorTest.kt
Outdated
Show resolved
Hide resolved
import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenContext | ||
import software.amazon.smithy.rust.codegen.server.smithy.customize.ServerCodegenDecorator | ||
|
||
val SerdeFeature = Feature("serde", false, listOf("dep:serde")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the feature name overridable? If we were to add this to the AWS SDK I would imagine we would want to introduce it under something like experimental-serde
to let it bake for awhile before we finalize it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not currently, but this would be an easy follow-on
codegen-serde/src/test/kotlin/software/amazon/smithy/rust/codegen/serde/SerdeDecoratorTest.kt
Show resolved
Hide resolved
A new generated diff is ready to view.
A new doc preview is ready to view. |
A new generated diff is ready to view.
A new doc preview is ready to view. |
A new generated diff is ready to view.
A new doc preview is ready to view. |
A new generated diff is ready to view.
A new doc preview is ready to view. |
Co-authored-by: david-perez <[email protected]>
a0ab7a4
to
5aa1794
Compare
A new generated diff is ready to view.
A new doc preview is ready to view. |
cargoCommand = "cargo test --all-features", | ||
additionalSettings = constrainedShapesSettings, | ||
), | ||
) { clientCodegenContext, rustCrate -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
) { clientCodegenContext, rustCrate -> | |
) { serverCodegenContext, rustCrate -> |
""" | ||
use #{serde}::ser::SerializeMap; | ||
let mut map = serializer.serialize_map(Some(#{value}.len()))?; | ||
for (k, v) in #{value}.iter() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unnecessary iter
s still here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these are load bearing
Motivation and Context
Customers want to be able to use
serde
with Smithy models. For details, see the RFCDescription
Implementation of
serde::Serialize
for smithy-rs code generators. This takes the approach of a trait,SerializeConfigured
which returns a type that implementsSerialize
. This allows customers to control serde behavior for their use case.This can be used as follows:
Currently, this codegen plugin is not used by anything. It can be enabled by bringing it in scope during code generation & adding the
@serde
trait to the model for the fields where serialization is desired. This will allow the SDK (if they choose to) roll it out only for specific types or services that have customer demand.There are a number of follow on items required:
Server
codegenDeserialize
implementationsTesting
Unit test testing serialization with a kitchen-sink model
Checklist
CHANGELOG.next.toml
if I made changes to the smithy-rs codegen or runtime cratesCHANGELOG.next.toml
if I made changes to the AWS SDK, generated SDK code, or SDK runtime cratesBy submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.