diff --git a/serde_derive/src/internals/ast.rs b/serde_derive/src/internals/ast.rs index 9e54acf6..fd11f64b 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(); 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 da66ac0f..d3f636b6 100644 --- a/serde_derive/src/internals/attr.rs +++ b/serde_derive/src/internals/attr.rs @@ -111,13 +111,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, @@ -194,7 +199,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"); @@ -229,7 +235,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!( @@ -242,6 +251,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); @@ -465,7 +506,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), @@ -481,8 +525,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 { @@ -705,7 +749,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, @@ -722,7 +766,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"); @@ -753,7 +798,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!( @@ -766,6 +814,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); @@ -875,7 +955,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(), @@ -891,17 +974,17 @@ impl Variant { &self.name } - pub fn rename_by_rule(&mut self, rule: &RenameRule) { + pub fn rename_by_rules(&mut self) { if !self.ser_renamed { - self.name.serialize = rule.apply_to_variant(&self.name.serialize); + self.name.serialize = self.rename_all_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 = self.rename_all_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]> { @@ -1260,12 +1343,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..80da5a98 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(PartialEq, Copy, Clone)] pub enum RenameRule { /// Don't apply a default rename rule. None,