diff --git a/serde_derive/src/internals/ast.rs b/serde_derive/src/internals/ast.rs index 9e54acf6..442f69d1 100644 --- a/serde_derive/src/internals/ast.rs +++ b/serde_derive/src/internals/ast.rs @@ -85,12 +85,12 @@ impl<'a> Container<'a> { match data { Data::Enum(ref mut variants) => { for variant in variants { - variant.attrs.rename_by_rule(attrs.rename_all()); + variant.attrs.rename_by_rules(attrs.rename_all_rules()); for field in &mut variant.fields { if field.attrs.flatten() { has_flatten = true; } - field.attrs.rename_by_rule(variant.attrs.rename_all()); + field.attrs.rename_by_rules(variant.attrs.rename_all_rules()); } } } @@ -99,7 +99,7 @@ impl<'a> Container<'a> { if field.attrs.flatten() { has_flatten = true; } - field.attrs.rename_by_rule(attrs.rename_all()); + field.attrs.rename_by_rules(attrs.rename_all_rules()); } } } diff --git a/serde_derive/src/internals/attr.rs b/serde_derive/src/internals/attr.rs index a89c0ce0..a02b9ea4 100644 --- a/serde_derive/src/internals/attr.rs +++ b/serde_derive/src/internals/attr.rs @@ -115,13 +115,18 @@ impl Name { } } +pub struct RenameAllRules { + serialize: RenameRule, + deserialize: RenameRule, +} + /// Represents struct or enum attribute information. pub struct Container { name: Name, transparent: bool, deny_unknown_fields: bool, default: Default, - rename_all: RenameRule, + rename_all_rules: RenameAllRules, ser_bound: Option>, de_bound: Option>, tag: EnumTag, @@ -198,7 +203,8 @@ impl Container { let mut transparent = BoolAttr::none(cx, "transparent"); let mut deny_unknown_fields = BoolAttr::none(cx, "deny_unknown_fields"); let mut default = Attr::none(cx, "default"); - let mut rename_all = Attr::none(cx, "rename_all"); + let mut rename_all_ser_rule = Attr::none(cx, "rename_all"); + let mut rename_all_de_rule = Attr::none(cx, "rename_all"); let mut ser_bound = Attr::none(cx, "bound"); let mut de_bound = Attr::none(cx, "bound"); let mut untagged = BoolAttr::none(cx, "untagged"); @@ -233,7 +239,10 @@ impl Container { Meta(NameValue(ref m)) if m.ident == "rename_all" => { if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) { match RenameRule::from_str(&s.value()) { - Ok(rename_rule) => rename_all.set(&m.ident, rename_rule), + Ok(rename_rule) => { + rename_all_ser_rule.set(&m.ident, rename_rule); + rename_all_de_rule.set(&m.ident, rename_rule); + }, Err(()) => cx.error_spanned_by( s, format!( @@ -246,6 +255,38 @@ impl Container { } } + // Parse `#[serde(rename_all(serialize = "foo", deserialize = "bar"))]` + Meta(List(ref m)) if m.ident == "rename_all" => { + if let Ok((ser, de)) = get_renames(cx, &m.nested) { + if let Some(ser) = ser { + match RenameRule::from_str(&ser.value()) { + Ok(rename_rule) => rename_all_ser_rule.set(&m.ident, rename_rule), + Err(()) => cx.error_spanned_by( + ser, + format!( + "unknown rename rule for #[serde(rename_all \ + = {:?})]", + ser.value(), + ), + ), + } + } + if let Some(de) = de { + match RenameRule::from_str(&de.value()) { + Ok(rename_rule) => rename_all_de_rule.set(&m.ident, rename_rule), + Err(()) => cx.error_spanned_by( + de, + format!( + "unknown rename rule for #[serde(rename_all \ + = {:?})]", + de.value(), + ), + ), + } + } + } + } + // Parse `#[serde(transparent)]` Meta(Word(ref word)) if word == "transparent" => { transparent.set_true(word); @@ -469,7 +510,10 @@ impl Container { transparent: transparent.get(), deny_unknown_fields: deny_unknown_fields.get(), default: default.get().unwrap_or(Default::None), - rename_all: rename_all.get().unwrap_or(RenameRule::None), + rename_all_rules: RenameAllRules { + serialize: rename_all_ser_rule.get().unwrap_or(RenameRule::None), + deserialize: rename_all_de_rule.get().unwrap_or(RenameRule::None), + }, ser_bound: ser_bound.get(), de_bound: de_bound.get(), tag: decide_tag(cx, item, untagged, internal_tag, content), @@ -485,8 +529,8 @@ impl Container { &self.name } - pub fn rename_all(&self) -> &RenameRule { - &self.rename_all + pub fn rename_all_rules(&self) -> &RenameAllRules { + &self.rename_all_rules } pub fn transparent(&self) -> bool { @@ -709,7 +753,7 @@ pub struct Variant { name: Name, ser_renamed: bool, de_renamed: bool, - rename_all: RenameRule, + rename_all_rules: RenameAllRules, ser_bound: Option>, de_bound: Option>, skip_deserializing: bool, @@ -726,7 +770,8 @@ impl Variant { let mut de_name = Attr::none(cx, "rename"); let mut skip_deserializing = BoolAttr::none(cx, "skip_deserializing"); let mut skip_serializing = BoolAttr::none(cx, "skip_serializing"); - let mut rename_all = Attr::none(cx, "rename_all"); + let mut rename_all_ser_rule = Attr::none(cx, "rename_all"); + let mut rename_all_de_rule = Attr::none(cx, "rename_all"); let mut ser_bound = Attr::none(cx, "bound"); let mut de_bound = Attr::none(cx, "bound"); let mut other = BoolAttr::none(cx, "other"); @@ -757,7 +802,10 @@ impl Variant { Meta(NameValue(ref m)) if m.ident == "rename_all" => { if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) { match RenameRule::from_str(&s.value()) { - Ok(rename_rule) => rename_all.set(&m.ident, rename_rule), + Ok(rename_rule) => { + rename_all_ser_rule.set(&m.ident, rename_rule); + rename_all_de_rule.set(&m.ident, rename_rule); + }, Err(()) => cx.error_spanned_by( s, format!( @@ -770,6 +818,38 @@ impl Variant { } } + // Parse `#[serde(rename_all(serialize = "foo", deserialize = "bar"))]` + Meta(List(ref m)) if m.ident == "rename_all" => { + if let Ok((ser, de)) = get_renames(cx, &m.nested) { + if let Some(ser) = ser { + match RenameRule::from_str(&ser.value()) { + Ok(rename_rule) => rename_all_ser_rule.set(&m.ident, rename_rule), + Err(()) => cx.error_spanned_by( + ser, + format!( + "unknown rename rule for #[serde(rename_all \ + = {:?})]", + ser.value(), + ), + ), + } + } + if let Some(de) = de { + match RenameRule::from_str(&de.value()) { + Ok(rename_rule) => rename_all_de_rule.set(&m.ident, rename_rule), + Err(()) => cx.error_spanned_by( + de, + format!( + "unknown rename rule for #[serde(rename_all \ + = {:?})]", + de.value(), + ), + ), + } + } + } + } + // Parse `#[serde(skip)]` Meta(Word(ref word)) if word == "skip" => { skip_serializing.set_true(word); @@ -879,7 +959,10 @@ impl Variant { }, ser_renamed: ser_renamed, de_renamed: de_renamed, - rename_all: rename_all.get().unwrap_or(RenameRule::None), + rename_all_rules: RenameAllRules { + serialize: rename_all_ser_rule.get().unwrap_or(RenameRule::None), + deserialize: rename_all_de_rule.get().unwrap_or(RenameRule::None), + }, ser_bound: ser_bound.get(), de_bound: de_bound.get(), skip_deserializing: skip_deserializing.get(), @@ -895,17 +978,17 @@ impl Variant { &self.name } - pub fn rename_by_rule(&mut self, rule: &RenameRule) { + pub fn rename_by_rules(&mut self, rules: &RenameAllRules) { if !self.ser_renamed { - self.name.serialize = rule.apply_to_variant(&self.name.serialize); + self.name.serialize = rules.serialize.apply_to_variant(&self.name.serialize); } if !self.de_renamed { - self.name.deserialize = rule.apply_to_variant(&self.name.deserialize); + self.name.deserialize = rules.deserialize.apply_to_variant(&self.name.deserialize); } } - pub fn rename_all(&self) -> &RenameRule { - &self.rename_all + pub fn rename_all_rules(&self) -> &RenameAllRules { + &self.rename_all_rules } pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> { @@ -1264,12 +1347,12 @@ impl Field { &self.name } - pub fn rename_by_rule(&mut self, rule: &RenameRule) { + pub fn rename_by_rules(&mut self, rules: &RenameAllRules) { if !self.ser_renamed { - self.name.serialize = rule.apply_to_field(&self.name.serialize); + self.name.serialize = rules.serialize.apply_to_field(&self.name.serialize); } if !self.de_renamed { - self.name.deserialize = rule.apply_to_field(&self.name.deserialize); + self.name.deserialize = rules.deserialize.apply_to_field(&self.name.deserialize); } } diff --git a/serde_derive/src/internals/case.rs b/serde_derive/src/internals/case.rs index e21558a7..3fcbb32d 100644 --- a/serde_derive/src/internals/case.rs +++ b/serde_derive/src/internals/case.rs @@ -10,7 +10,7 @@ use std::str::FromStr; use self::RenameRule::*; /// The different possible ways to change case of fields in a struct, or variants in an enum. -#[derive(PartialEq)] +#[derive(Copy, Clone, PartialEq)] pub enum RenameRule { /// Don't apply a default rename rule. None,