Skip to content

Commit 35be483

Browse files
committed
serde_derive: Add alias_all attribute to containers
This adds a new attribute `#[serde(alias_all = "...")]` to containers, which accepts the same rename rules as `#[serde(rename_all = "...")]`. When applied to a container, the alias will be added to all fields (or variants) similarly to how `#[serde(alias = "...")]` works on a single field/variant. This attribute can be specified multiple times, with the use-case being accepting multiple case styles during de-serialization. Resolves #1530 Signed-off-by: Michel Heily <[email protected]>
1 parent 49d098d commit 35be483

File tree

4 files changed

+341
-0
lines changed

4 files changed

+341
-0
lines changed

serde_derive/src/internals/ast.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,14 @@ impl<'a> Container<'a> {
8080
match &mut data {
8181
Data::Enum(variants) => {
8282
for variant in variants {
83+
for alias_all_rule in attrs.alias_all_rules() {
84+
variant.attrs.alias_by_rule(*alias_all_rule);
85+
}
8386
variant.attrs.rename_by_rules(attrs.rename_all_rules());
8487
for field in &mut variant.fields {
88+
for alias_all_rule in attrs.alias_all_rules() {
89+
field.attrs.alias_by_rule(*alias_all_rule);
90+
}
8591
field.attrs.rename_by_rules(
8692
variant
8793
.attrs
@@ -93,6 +99,9 @@ impl<'a> Container<'a> {
9399
}
94100
Data::Struct(_, fields) => {
95101
for field in fields {
102+
for alias_all_rule in attrs.alias_all_rules() {
103+
field.attrs.alias_by_rule(*alias_all_rule);
104+
}
96105
field.attrs.rename_by_rules(attrs.rename_all_rules());
97106
}
98107
}

serde_derive/src/internals/attr.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ pub struct Container {
160160
default: Default,
161161
rename_all_rules: RenameAllRules,
162162
rename_all_fields_rules: RenameAllRules,
163+
alias_all_rules: Vec<RenameRule>,
163164
ser_bound: Option<Vec<syn::WherePredicate>>,
164165
de_bound: Option<Vec<syn::WherePredicate>>,
165166
tag: TagType,
@@ -245,6 +246,7 @@ impl Container {
245246
let mut rename_all_de_rule = Attr::none(cx, RENAME_ALL);
246247
let mut rename_all_fields_ser_rule = Attr::none(cx, RENAME_ALL_FIELDS);
247248
let mut rename_all_fields_de_rule = Attr::none(cx, RENAME_ALL_FIELDS);
249+
let mut alias_all_rules = VecAttr::none(cx, ALIAS_ALL);
248250
let mut ser_bound = Attr::none(cx, BOUND);
249251
let mut de_bound = Attr::none(cx, BOUND);
250252
let mut untagged = BoolAttr::none(cx, UNTAGGED);
@@ -491,6 +493,14 @@ impl Container {
491493
if let Some(s) = get_lit_str(cx, EXPECTING, &meta)? {
492494
expecting.set(&meta.path, s.value());
493495
}
496+
} else if meta.path == ALIAS_ALL {
497+
// #[serde(alias_all = "...")]
498+
if let Some(s) = get_lit_str(cx, ALIAS_ALL, &meta)? {
499+
match RenameRule::from_str(&s.value()) {
500+
Ok(rename_rule) => alias_all_rules.insert(&meta.path, rename_rule),
501+
Err(err) => cx.error_spanned_by(s, err),
502+
}
503+
}
494504
} else {
495505
let path = meta.path.to_token_stream().to_string().replace(' ', "");
496506
return Err(
@@ -530,6 +540,7 @@ impl Container {
530540
serialize: rename_all_fields_ser_rule.get().unwrap_or(RenameRule::None),
531541
deserialize: rename_all_fields_de_rule.get().unwrap_or(RenameRule::None),
532542
},
543+
alias_all_rules: alias_all_rules.get(),
533544
ser_bound: ser_bound.get(),
534545
de_bound: de_bound.get(),
535546
tag: decide_tag(cx, item, untagged, internal_tag, content),
@@ -569,6 +580,10 @@ impl Container {
569580
&self.default
570581
}
571582

583+
pub fn alias_all_rules(&self) -> &[RenameRule] {
584+
&self.alias_all_rules
585+
}
586+
572587
pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> {
573588
self.ser_bound.as_ref().map(|vec| &vec[..])
574589
}
@@ -943,6 +958,15 @@ impl Variant {
943958
.insert(self.name.deserialize.clone());
944959
}
945960

961+
pub fn alias_by_rule(&mut self, rule: RenameRule) {
962+
let alias_name = rule.apply_to_variant(&self.name.deserialize.value);
963+
let alias = Name {
964+
value: alias_name,
965+
span: self.name.deserialize.span,
966+
};
967+
self.name.deserialize_aliases.insert(alias);
968+
}
969+
946970
pub fn rename_all_rules(&self) -> RenameAllRules {
947971
self.rename_all_rules
948972
}
@@ -1341,6 +1365,16 @@ impl Field {
13411365
pub fn mark_transparent(&mut self) {
13421366
self.transparent = true;
13431367
}
1368+
1369+
pub fn alias_by_rule(&mut self, rule: RenameRule) {
1370+
// Apply the rename rule to the original field name to create an alias
1371+
let alias_name = rule.apply_to_field(&self.name.deserialize.value);
1372+
let alias = Name {
1373+
value: alias_name,
1374+
span: self.name.deserialize.span,
1375+
};
1376+
self.name.deserialize_aliases.insert(alias);
1377+
}
13441378
}
13451379

13461380
type SerAndDe<T> = (Option<T>, Option<T>);

serde_derive/src/internals/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use syn::{Ident, Path};
55
pub struct Symbol(&'static str);
66

77
pub const ALIAS: Symbol = Symbol("alias");
8+
pub const ALIAS_ALL: Symbol = Symbol("alias_all");
89
pub const BORROW: Symbol = Symbol("borrow");
910
pub const BOUND: Symbol = Symbol("bound");
1011
pub const CONTENT: Symbol = Symbol("content");

0 commit comments

Comments
 (0)