WIP: Allow #[serde(rename=str|bool|int)] for enum variants.#973
WIP: Allow #[serde(rename=str|bool|int)] for enum variants.#973Phaiax wants to merge 7 commits intoserde-rs:masterfrom
Conversation
(This commit contains untested code and a dirty hacks so that the rename="str" still works)
…pport non-str attribute literals
|
Hey @dtolnay . I think this is ready for a first review. As for my Questions.
After review I will merge the commits (except for the last) into one. |
| } | ||
|
|
||
| #[cfg(not(any(feature = "std", feature = "alloc")))] | ||
| pub fn from_int(i: u64) -> [u8; 20] { |
There was a problem hiding this comment.
the int/bool to string is needed for fn deserialize_identifier(..., fallthrough_arm : Option<Tokens>) where the fallthrough arm expects a local '&str' value, so writing to stdout is not possible.
It feels a bit too hacky :D
| t | ||
| } | ||
|
|
||
| pub enum VariantName { |
There was a problem hiding this comment.
Note: This enum is defined three times. The other two times it is named StrBoolInt.
Should it be named after its purpose or after its content?
In the serde_derive_internals crate, the name VariantName is already occupied by the struct VariantName { deserialize: StrBoolInt, serialize: StrBoolInt }. Maybe rename the VariantName into SerDeVariantName and StrBoolInt into VariantName?
| .enumerate() | ||
| .filter(|&(_, variant)| !variant.attrs.skip_deserializing()) | ||
| .map(|(i, variant)| (variant.attrs.name().deserialize_name(), field_i(i)),) | ||
| .map(|(i, variant)| (StrBoolInt::from(variant.attrs.name().deserialize_name()), field_i(i))) |
There was a problem hiding this comment.
Note: These StrBoolInt::from() calls convert from serde_derive_internals::StrBoolInt into serde_derive::StrBoolInt (at least in enum/variant related functions, not in struct/field related functions).
| fn deserialize_identifier( | ||
| this: Tokens, | ||
| fields: &[(String, Ident)], | ||
| fields: &[(StrBoolInt, Ident)], |
There was a problem hiding this comment.
Maybe renaming StrBoolInt into VariantName is not so good because it can also represent a FieldName, (in this case it is always a string).
|
|
||
| let constructors: &Vec<_> = &fields | ||
| let field_strs = fields.iter().filter_map(|&(ref n, _)| n.as_str()); | ||
| let field_bytes = fields.iter().filter_map(|&(ref n, _)| n.as_str().map(|n| quote::ByteStr(n))); |
There was a problem hiding this comment.
maybe rename into matcharms_str. (field_strs was the original name)
| /// | ||
| /// It will be used as second argument in | ||
| /// `_serde::Serializer::serialize_struct(__serializer, name, len)` | ||
| /// while serializing the inner struct in adjacently tagged enums. |
There was a problem hiding this comment.
This may be a problem, depending on how a serializer serializes a struct name. But I guess that formats that require a tagged enum do not serialize the variant/struct name. (This case is part of the tests and has a comment there also)
There was a problem hiding this comment.
I am okay with the behavior as you implemented it.
|
|
||
| /// An extended name, used for the type tag for enums. | ||
| #[derive(Debug, Clone)] | ||
| pub enum StrBoolInt { |
| let variant_name = variant.attrs.name().serialize_name(); | ||
| let variant_name = match variant.attrs.name().serialize_name() { | ||
| attr::StrBoolInt::Str(s) => s, | ||
| _ => unreachable!(), |
| Token::Str("type"), | ||
| Token::Bool(false) | ||
| ], | ||
| "unknown variant `false`, expected one of `abc`, `true`, `3`, `4`, `5`, `6`", |
There was a problem hiding this comment.
the error message doesn't differentiate between string literals and non string literals ('3' vs 3). Should be ok anyway I hope.
| Token::Str("t"), | ||
| Token::Bool(true), | ||
|
|
||
| Token::Str("c"), |
There was a problem hiding this comment.
that is the comment I referred to earlier in the review.
dtolnay
left a comment
There was a problem hiding this comment.
I would prefer not to implement this with rename_as because we will need to support that for long after the better attribute way is stable.
How would you feel about implementing just the attr_literals way and putting some pressure on the lang team to stabilize rust-lang/rust#34981? As far as I can tell there haven't been objections or changes to it over the past 11 months so it should be just about ready.
Alternatively I would be okay with a temporary fork of serde_derive under a different name like serde_derive_experimental that provides the rename_as workaround.
It should be in
Yes I agree with this choice.
They generate a Deserialize impl for reading field names in a struct or variant names in an enum in a way that is compatible with how derive(Deserialize) behaves on structs and externally tagged enums. See the example of field_identifier in Manually implementing Deserialize for a struct. This is helpful when you want custom Deserialize logic but the field names / variant names do not need to be custom. |
|
What happened to this ? Oh nvm it's replaced by #1392 right? |
(This commit contains untested code and a dirty hacks so that the rename="str" still works)
#745 Issue for this PR
I got started and it was not too hard, serde derive is written very well. (I'm still confused by the deserializiation part, but I have not looked into it to much)
Some questions:
#[serde(rename="1", rename_as="int")]. This is necessary since serde supports old rustc versions anyway, so even with stabilization this will not go away.StrBoolInt, but I had to define it twice, once inserde_derive_internalsand once again inserde_derive, so that I can implementToTokens.StrBoolIntis stuffed intofragment.rs. Should I use a new file or is that ok?Serializershave the choice to serialize either with the name of the variant or with the id. What happens ifrename=2is stated for attribute with field number 1? Should I just replace the whole thederserialize_u32part as soon as an int-rename is encountered?[#serde(field_identifier/variant_identifier)]setting? It is not mentioned in the docs.Thx, Daniel