-
-
Notifications
You must be signed in to change notification settings - Fork 779
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
Untagged and internally tagged enums #739
Conversation
Awesome, thanks @dtolnay! |
Yay! |
Out of curiosity, why is |
I would prefer to be able to iterate on the implementation for a few releases and only have to think about backward compatibility for the attributes rather than the entire mechanism. This is quite a large PR and I think we can reach consensus on the attributes and the semantics significantly sooner than we could reach consensus on the entire Once this merges I will file a ticket to follow up on polishing and exposing some of the pieces. |
Cool, sounds good. |
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.
cool! yes let's delay iterating on the exact structures later.
Implementation looks good to me.
@@ -0,0 +1,732 @@ | |||
use core::fmt; |
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.
hide the entire module with ![doc(hidden)]
or at least write a doc comment stating that nothing in this module should be used outside of generated code. The PR comments contains all of that already, maybe just place them 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.
impl<E> Deserialize for Content<E> { | ||
fn deserialize<D: Deserializer>(deserializer: D) -> Result<Self, D::Error> { | ||
// Untagged and internally tagged enums are only supported in | ||
// self-describing formats. |
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.
We could find some way to support other formats through some rewinding API. This would also have uses for streaming.
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 filed #742 to follow up on this.
Fixes #415 and fixes serde-rs/json#67.
The attribute for untagged enums is:
During serialization, the variant is serialized as though it were not part of an enum. Struct variants are serialized as structs, tuple variants are serialized as tuples, unit variants are serialized as unit, and newtype variants are serialized as the value.
During deserialization, we buffer the content of the Deserializer and try it against each variant in order, returning the first one that deserializes successfully from that content.
The attribute for internally tagged enums is:
The enum must contain only unit, newtype and struct variants. Tuple variants are not supported. During serialization unit variants are serialized as structs with a single field:
{"type": "T"}
, struct variants are serialized with"type": "T"
inserted as the first field, and newtype variants must contain either a struct or a map and are serialized with"type": "T"
inserted as the first field.During deserialization, we buffer the content of the Deserializer, pull out the tag, and deserialize the rest of the content against the correct variant.
The use case from #415 looks like:
And the use case from serde-rs/json#67 looks like:
cc @sfackler who asked about this in IRC and @alexcrichton who is removing this functionality from toml.