-
-
Notifications
You must be signed in to change notification settings - Fork 777
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
WIP: Allow #[serde(rename=str|bool|int)] for enum variants. #973
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. |
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.
Questions / Notes
} | ||
|
||
#[cfg(not(any(feature = "std", feature = "alloc")))] | ||
pub fn from_int(i: u64) -> [u8; 20] { |
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 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
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 seems fine. Nicely done.
@@ -19,25 +19,63 @@ pub fn constrain<T: ?Sized>(t: &T) -> &T { | |||
t | |||
} | |||
|
|||
pub enum VariantName { |
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.
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
?
@@ -602,7 +602,7 @@ fn deserialize_externally_tagged_enum( | |||
.iter() | |||
.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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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).
@@ -1366,14 +1366,29 @@ fn deserialize_custom_identifier( | |||
|
|||
fn deserialize_identifier( | |||
this: Tokens, | |||
fields: &[(String, Ident)], | |||
fields: &[(StrBoolInt, Ident)], |
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 { |
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.
Correct file for this struct?
let variant_name = variant.attrs.name().serialize_name(); | ||
let variant_name = match variant.attrs.name().serialize_name() { | ||
attr::StrBoolInt::Str(s) => s, | ||
_ => unreachable!(), |
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.
check.rs
prevents this case
Token::Bool(false) | ||
], | ||
"unknown variant `false`, expected one of `abc`, `true`, `3`, `4`, `5`, `6`", | ||
); |
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 error message doesn't differentiate between string literals and non string literals ('3' vs 3). Should be ok anyway I hope.
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.
That's fine.
Token::Bool(true), | ||
|
||
Token::Str("c"), | ||
// TODO: Is this the correct way to name the struct? stringify the rename? |
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.
that is the comment I referred to earlier in the review.
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 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_internals
and once again inserde_derive
, so that I can implementToTokens
.StrBoolInt
is stuffed intofragment.rs
. Should I use a new file or is that ok?Serializers
have the choice to serialize either with the name of the variant or with the id. What happens ifrename=2
is stated for attribute with field number 1? Should I just replace the whole thederserialize_u32
part as soon as an int-rename is encountered?[#serde(field_identifier/variant_identifier)]
setting? It is not mentioned in the docs.Thx, Daniel