diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index 518f84320..2f18dd8b1 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -1,5 +1,6 @@ use crate::fragment::{Expr, Fragment, Match, Stmts}; use crate::internals::ast::{Container, Data, Field, Style, Variant}; +use crate::internals::name::Name; use crate::internals::{attr, replace_receiver, ungroup, Ctxt, Derive}; use crate::{bound, dummy, pretend, this}; use proc_macro2::{Literal, Span, TokenStream}; @@ -2002,7 +2003,7 @@ fn deserialize_untagged_newtype_variant( struct FieldWithAliases<'a> { ident: Ident, - aliases: &'a BTreeSet, + aliases: &'a BTreeSet, } fn deserialize_generated_identifier( @@ -2224,7 +2225,7 @@ fn deserialize_identifier( let aliases = field .aliases .iter() - .map(|alias| Literal::byte_string(alias.as_bytes())); + .map(|alias| Literal::byte_string(alias.value.as_bytes())); quote!(#(#aliases)|* => _serde::__private::Ok(#this_value::#ident)) }); diff --git a/serde_derive/src/internals/attr.rs b/serde_derive/src/internals/attr.rs index dd9e2b7dd..6d846ed01 100644 --- a/serde_derive/src/internals/attr.rs +++ b/serde_derive/src/internals/attr.rs @@ -1,3 +1,4 @@ +use crate::internals::name::{MultiName, Name}; use crate::internals::symbol::*; use crate::internals::{ungroup, Ctxt}; use proc_macro2::{Spacing, Span, TokenStream, TokenTree}; @@ -21,7 +22,7 @@ use syn::{parse_quote, token, Ident, Lifetime, Token}; pub use crate::internals::case::RenameRule; -struct Attr<'c, T> { +pub(crate) struct Attr<'c, T> { cx: &'c Ctxt, name: Symbol, tokens: TokenStream, @@ -62,7 +63,7 @@ impl<'c, T> Attr<'c, T> { } } - fn get(self) -> Option { + pub(crate) fn get(self) -> Option { self.value } @@ -90,7 +91,7 @@ impl<'c> BoolAttr<'c> { } } -struct VecAttr<'c, T> { +pub(crate) struct VecAttr<'c, T> { cx: &'c Ctxt, name: Symbol, first_dup_tokens: TokenStream, @@ -125,63 +126,13 @@ impl<'c, T> VecAttr<'c, T> { } } - fn get(self) -> Vec { + pub(crate) fn get(self) -> Vec { self.values } } -pub struct Name { - serialize: String, - serialize_renamed: bool, - deserialize: String, - deserialize_renamed: bool, - deserialize_aliases: BTreeSet, -} - -fn unraw(ident: &Ident) -> String { - ident.to_string().trim_start_matches("r#").to_owned() -} - -impl Name { - fn from_attrs( - source_name: String, - ser_name: Attr, - de_name: Attr, - de_aliases: Option>, - ) -> Name { - let mut alias_set = BTreeSet::new(); - if let Some(de_aliases) = de_aliases { - for alias_name in de_aliases.get() { - alias_set.insert(alias_name); - } - } - - let ser_name = ser_name.get(); - let ser_renamed = ser_name.is_some(); - let de_name = de_name.get(); - let de_renamed = de_name.is_some(); - Name { - serialize: ser_name.unwrap_or_else(|| source_name.clone()), - serialize_renamed: ser_renamed, - deserialize: de_name.unwrap_or(source_name), - deserialize_renamed: de_renamed, - deserialize_aliases: alias_set, - } - } - - /// Return the container name for the container when serializing. - pub fn serialize_name(&self) -> &str { - &self.serialize - } - - /// Return the container name for the container when deserializing. - pub fn deserialize_name(&self) -> &str { - &self.deserialize - } - - fn deserialize_aliases(&self) -> &BTreeSet { - &self.deserialize_aliases - } +fn unraw(ident: &Ident) -> Ident { + Ident::new(ident.to_string().trim_start_matches("r#"), ident.span()) } #[derive(Copy, Clone)] @@ -203,7 +154,7 @@ impl RenameAllRules { /// Represents struct or enum attribute information. pub struct Container { - name: Name, + name: MultiName, transparent: bool, deny_unknown_fields: bool, default: Default, @@ -327,8 +278,8 @@ impl Container { // #[serde(rename = "foo")] // #[serde(rename(serialize = "foo", deserialize = "bar"))] let (ser, de) = get_renames(cx, RENAME, &meta)?; - ser_name.set_opt(&meta.path, ser.as_ref().map(syn::LitStr::value)); - de_name.set_opt(&meta.path, de.as_ref().map(syn::LitStr::value)); + ser_name.set_opt(&meta.path, ser.as_ref().map(Name::from)); + de_name.set_opt(&meta.path, de.as_ref().map(Name::from)); } else if meta.path == RENAME_ALL { // #[serde(rename_all = "foo")] // #[serde(rename_all(serialize = "foo", deserialize = "bar"))] @@ -567,7 +518,7 @@ impl Container { } Container { - name: Name::from_attrs(unraw(&item.ident), ser_name, de_name, None), + name: MultiName::from_attrs(Name::from(&unraw(&item.ident)), ser_name, de_name, None), transparent: transparent.get(), deny_unknown_fields: deny_unknown_fields.get(), default: default.get().unwrap_or(Default::None), @@ -594,7 +545,7 @@ impl Container { } } - pub fn name(&self) -> &Name { + pub fn name(&self) -> &MultiName { &self.name } @@ -781,7 +732,7 @@ fn decide_identifier( /// Represents variant attribute information pub struct Variant { - name: Name, + name: MultiName, rename_all_rules: RenameAllRules, ser_bound: Option>, de_bound: Option>, @@ -832,15 +783,15 @@ impl Variant { // #[serde(rename = "foo")] // #[serde(rename(serialize = "foo", deserialize = "bar"))] let (ser, de) = get_multiple_renames(cx, &meta)?; - ser_name.set_opt(&meta.path, ser.as_ref().map(syn::LitStr::value)); + ser_name.set_opt(&meta.path, ser.as_ref().map(Name::from)); for de_value in de { - de_name.set_if_none(de_value.value()); - de_aliases.insert(&meta.path, de_value.value()); + de_name.set_if_none(Name::from(&de_value)); + de_aliases.insert(&meta.path, Name::from(&de_value)); } } else if meta.path == ALIAS { // #[serde(alias = "foo")] if let Some(s) = get_lit_str(cx, ALIAS, &meta)? { - de_aliases.insert(&meta.path, s.value()); + de_aliases.insert(&meta.path, Name::from(&s)); } } else if meta.path == RENAME_ALL { // #[serde(rename_all = "foo")] @@ -947,7 +898,12 @@ impl Variant { } Variant { - name: Name::from_attrs(unraw(&variant.ident), ser_name, de_name, Some(de_aliases)), + name: MultiName::from_attrs( + Name::from(&unraw(&variant.ident)), + ser_name, + de_name, + Some(de_aliases), + ), rename_all_rules: RenameAllRules { serialize: rename_all_ser_rule.get().unwrap_or(RenameRule::None), deserialize: rename_all_de_rule.get().unwrap_or(RenameRule::None), @@ -964,20 +920,23 @@ impl Variant { } } - pub fn name(&self) -> &Name { + pub fn name(&self) -> &MultiName { &self.name } - pub fn aliases(&self) -> &BTreeSet { + pub fn aliases(&self) -> &BTreeSet { self.name.deserialize_aliases() } pub fn rename_by_rules(&mut self, rules: RenameAllRules) { if !self.name.serialize_renamed { - self.name.serialize = rules.serialize.apply_to_variant(&self.name.serialize); + self.name.serialize.value = + rules.serialize.apply_to_variant(&self.name.serialize.value); } if !self.name.deserialize_renamed { - self.name.deserialize = rules.deserialize.apply_to_variant(&self.name.deserialize); + self.name.deserialize.value = rules + .deserialize + .apply_to_variant(&self.name.deserialize.value); } self.name .deserialize_aliases @@ -1023,7 +982,7 @@ impl Variant { /// Represents field attribute information pub struct Field { - name: Name, + name: MultiName, skip_serializing: bool, skip_deserializing: bool, skip_serializing_if: Option, @@ -1082,8 +1041,11 @@ impl Field { let mut flatten = BoolAttr::none(cx, FLATTEN); let ident = match &field.ident { - Some(ident) => unraw(ident), - None => index.to_string(), + Some(ident) => Name::from(&unraw(ident)), + None => Name { + value: index.to_string(), + span: Span::call_site(), + }, }; if let Some(borrow_attribute) = attrs.and_then(|variant| variant.borrow.as_ref()) { @@ -1119,15 +1081,15 @@ impl Field { // #[serde(rename = "foo")] // #[serde(rename(serialize = "foo", deserialize = "bar"))] let (ser, de) = get_multiple_renames(cx, &meta)?; - ser_name.set_opt(&meta.path, ser.as_ref().map(syn::LitStr::value)); + ser_name.set_opt(&meta.path, ser.as_ref().map(Name::from)); for de_value in de { - de_name.set_if_none(de_value.value()); - de_aliases.insert(&meta.path, de_value.value()); + de_name.set_if_none(Name::from(&de_value)); + de_aliases.insert(&meta.path, Name::from(&de_value)); } } else if meta.path == ALIAS { // #[serde(alias = "foo")] if let Some(s) = get_lit_str(cx, ALIAS, &meta)? { - de_aliases.insert(&meta.path, s.value()); + de_aliases.insert(&meta.path, Name::from(&s)); } } else if meta.path == DEFAULT { if meta.input.peek(Token![=]) { @@ -1290,7 +1252,7 @@ impl Field { } Field { - name: Name::from_attrs(ident, ser_name, de_name, Some(de_aliases)), + name: MultiName::from_attrs(ident, ser_name, de_name, Some(de_aliases)), skip_serializing: skip_serializing.get(), skip_deserializing: skip_deserializing.get(), skip_serializing_if: skip_serializing_if.get(), @@ -1306,20 +1268,22 @@ impl Field { } } - pub fn name(&self) -> &Name { + pub fn name(&self) -> &MultiName { &self.name } - pub fn aliases(&self) -> &BTreeSet { + pub fn aliases(&self) -> &BTreeSet { self.name.deserialize_aliases() } pub fn rename_by_rules(&mut self, rules: RenameAllRules) { if !self.name.serialize_renamed { - self.name.serialize = rules.serialize.apply_to_field(&self.name.serialize); + self.name.serialize.value = rules.serialize.apply_to_field(&self.name.serialize.value); } if !self.name.deserialize_renamed { - self.name.deserialize = rules.deserialize.apply_to_field(&self.name.deserialize); + self.name.deserialize.value = rules + .deserialize + .apply_to_field(&self.name.deserialize.value); } self.name .deserialize_aliases @@ -1769,7 +1733,7 @@ fn is_primitive_path(path: &syn::Path, primitive: &str) -> bool { // attribute on the field so there must be at least one borrowable lifetime. fn borrowable_lifetimes( cx: &Ctxt, - name: &str, + name: &Name, field: &syn::Field, ) -> Result, ()> { let mut lifetimes = BTreeSet::new(); diff --git a/serde_derive/src/internals/check.rs b/serde_derive/src/internals/check.rs index 9594b35a5..c9c0fa46d 100644 --- a/serde_derive/src/internals/check.rs +++ b/serde_derive/src/internals/check.rs @@ -332,13 +332,13 @@ fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) { let name = field.attrs.name(); let ser_name = name.serialize_name(); - if check_ser && ser_name == tag { + if check_ser && ser_name.value == tag { diagnose_conflict(); return; } for de_name in field.attrs.aliases() { - if check_de && de_name == tag { + if check_de && de_name.value == tag { diagnose_conflict(); return; } diff --git a/serde_derive/src/internals/mod.rs b/serde_derive/src/internals/mod.rs index f98ef08e8..cd1e81052 100644 --- a/serde_derive/src/internals/mod.rs +++ b/serde_derive/src/internals/mod.rs @@ -1,5 +1,6 @@ pub mod ast; pub mod attr; +pub mod name; mod case; mod check; diff --git a/serde_derive/src/internals/name.rs b/serde_derive/src/internals/name.rs new file mode 100644 index 000000000..4c59f9636 --- /dev/null +++ b/serde_derive/src/internals/name.rs @@ -0,0 +1,113 @@ +use crate::internals::attr::{Attr, VecAttr}; +use proc_macro2::{Ident, Span, TokenStream}; +use quote::ToTokens; +use std::cmp::Ordering; +use std::collections::BTreeSet; +use std::fmt::{self, Display}; +use syn::LitStr; + +pub struct MultiName { + pub(crate) serialize: Name, + pub(crate) serialize_renamed: bool, + pub(crate) deserialize: Name, + pub(crate) deserialize_renamed: bool, + pub(crate) deserialize_aliases: BTreeSet, +} + +impl MultiName { + pub(crate) fn from_attrs( + source_name: Name, + ser_name: Attr, + de_name: Attr, + de_aliases: Option>, + ) -> Self { + let mut alias_set = BTreeSet::new(); + if let Some(de_aliases) = de_aliases { + for alias_name in de_aliases.get() { + alias_set.insert(alias_name); + } + } + + let ser_name = ser_name.get(); + let ser_renamed = ser_name.is_some(); + let de_name = de_name.get(); + let de_renamed = de_name.is_some(); + MultiName { + serialize: ser_name.unwrap_or_else(|| source_name.clone()), + serialize_renamed: ser_renamed, + deserialize: de_name.unwrap_or(source_name), + deserialize_renamed: de_renamed, + deserialize_aliases: alias_set, + } + } + + /// Return the container name for the container when serializing. + pub fn serialize_name(&self) -> &Name { + &self.serialize + } + + /// Return the container name for the container when deserializing. + pub fn deserialize_name(&self) -> &Name { + &self.deserialize + } + + pub(crate) fn deserialize_aliases(&self) -> &BTreeSet { + &self.deserialize_aliases + } +} + +#[derive(Clone)] +pub struct Name { + pub value: String, + pub span: Span, +} + +impl ToTokens for Name { + fn to_tokens(&self, tokens: &mut TokenStream) { + LitStr::new(&self.value, self.span).to_tokens(tokens); + } +} + +impl Ord for Name { + fn cmp(&self, other: &Self) -> Ordering { + Ord::cmp(&self.value, &other.value) + } +} + +impl PartialOrd for Name { + fn partial_cmp(&self, other: &Self) -> Option { + Some(Ord::cmp(self, other)) + } +} + +impl Eq for Name {} + +impl PartialEq for Name { + fn eq(&self, other: &Self) -> bool { + self.value == other.value + } +} + +impl From<&Ident> for Name { + fn from(ident: &Ident) -> Self { + Name { + value: ident.to_string(), + span: ident.span(), + } + } +} + +impl From<&LitStr> for Name { + fn from(lit: &LitStr) -> Self { + Name { + value: lit.value(), + span: lit.span(), + } + } +} + +impl Display for Name { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.value, formatter) + } +} diff --git a/serde_derive/src/ser.rs b/serde_derive/src/ser.rs index 47384f16f..ecdf6470d 100644 --- a/serde_derive/src/ser.rs +++ b/serde_derive/src/ser.rs @@ -1,5 +1,6 @@ use crate::fragment::{Fragment, Match, Stmts}; use crate::internals::ast::{Container, Data, Field, Style, Variant}; +use crate::internals::name::Name; use crate::internals::{attr, replace_receiver, Ctxt, Derive}; use crate::{bound, dummy, pretend, this}; use proc_macro2::{Span, TokenStream}; @@ -798,9 +799,9 @@ fn serialize_untagged_variant( enum TupleVariant<'a> { ExternallyTagged { - type_name: &'a str, + type_name: &'a Name, variant_index: u32, - variant_name: &'a str, + variant_name: &'a Name, }, Untagged, } @@ -867,11 +868,11 @@ fn serialize_tuple_variant( enum StructVariant<'a> { ExternallyTagged { variant_index: u32, - variant_name: &'a str, + variant_name: &'a Name, }, InternallyTagged { tag: &'a str, - variant_name: &'a str, + variant_name: &'a Name, }, Untagged, } @@ -880,7 +881,7 @@ fn serialize_struct_variant( context: StructVariant, params: &Parameters, fields: &[Field], - name: &str, + name: &Name, ) -> Fragment { if fields.iter().any(|field| field.attrs.flatten()) { return serialize_struct_variant_with_flatten(context, params, fields, name); @@ -964,7 +965,7 @@ fn serialize_struct_variant_with_flatten( context: StructVariant, params: &Parameters, fields: &[Field], - name: &str, + name: &Name, ) -> Fragment { let struct_trait = StructTrait::SerializeMap; let serialize_fields = serialize_struct_visitor(fields, params, true, &struct_trait);