From 34c28b1fc5ff6ff7154a38ea7fc22efa8371cf1a Mon Sep 17 00:00:00 2001 From: Marc-Antoine Arnaud Date: Sat, 3 Feb 2024 07:52:56 +0100 Subject: [PATCH] fix: support attribute and field with same name --- yaserde/tests/deserializer.rs | 39 ++++++++++++++++++++++++++ yaserde_derive/src/common/field.rs | 8 ++++-- yaserde_derive/src/de/expand_struct.rs | 27 ++++++++++++------ 3 files changed, 63 insertions(+), 11 deletions(-) diff --git a/yaserde/tests/deserializer.rs b/yaserde/tests/deserializer.rs index 0f96078..fbc8612 100644 --- a/yaserde/tests/deserializer.rs +++ b/yaserde/tests/deserializer.rs @@ -345,6 +345,45 @@ fn de_attributes_complex() { ); } +#[test] +fn de_attributes_with_same_name_field() { + init(); + + #[derive(Default, YaDeserialize, PartialEq, Debug)] + pub struct Struct { + #[yaserde(attribute, rename = "content")] + attribute: Option, + content: Option, + } + + convert_and_validate!( + r#""#, + Struct, + Struct { + attribute: None, + content: None + } + ); + + convert_and_validate!( + r#""#, + Struct, + Struct { + attribute: Some("attribute".to_string()), + content: None + } + ); + + convert_and_validate!( + r#"Field"#, + Struct, + Struct { + attribute: Some("attribute".to_string()), + content: Some("Field".to_string()) + } + ); +} + #[test] fn de_rename() { init(); diff --git a/yaserde_derive/src/common/field.rs b/yaserde_derive/src/common/field.rs index b8daff0..078aeec 100644 --- a/yaserde_derive/src/common/field.rs +++ b/yaserde_derive/src/common/field.rs @@ -76,7 +76,7 @@ impl YaSerdeField { format!("{}{}", prefix, label) } - pub fn get_visitor_ident(&self, struct_name: Option<&syn::Path>) -> Ident { + pub fn get_visitor_ident(&self, struct_name: Option<&syn::Path>, is_attribute: bool) -> Ident { let label = self.renamed_label_without_namespace(); let struct_id = struct_name.map_or_else( @@ -90,9 +90,13 @@ impl YaSerdeField { }, ); + let attribute = is_attribute + .then_some("Attribute_".to_string()) + .unwrap_or_default(); + Ident::new( &format!( - "__Visitor_{}_{}", + "__Visitor_{attribute}{}_{}", label.replace('.', "_").to_upper_camel_case(), struct_id ), diff --git a/yaserde_derive/src/de/expand_struct.rs b/yaserde_derive/src/de/expand_struct.rs index 2c9d7a1..a2c3a55 100644 --- a/yaserde_derive/src/de/expand_struct.rs +++ b/yaserde_derive/src/de/expand_struct.rs @@ -71,7 +71,7 @@ pub fn parse( .map(|s| s.ident.to_string()) .collect(); - let visitor_label = field.get_visitor_ident(Some(&struct_name)); + let visitor_label = field.get_visitor_ident(Some(&struct_name), field.is_attribute()); Some(quote! { #[allow(non_snake_case, non_camel_case_types)] @@ -92,7 +92,7 @@ pub fn parse( let simple_type_visitor = |simple_type: Field| { let visitor = simple_type.get_simple_type_visitor(); - let visitor_label = field.get_visitor_ident(None); + let visitor_label = field.get_visitor_ident(None, field.is_attribute()); let field_type = TokenStream::from(simple_type); let map_if_bool = if field_type.to_string() == "bool" { @@ -142,7 +142,7 @@ pub fn parse( .fields .iter() .map(|field| YaSerdeField::new(field.clone())) - .filter(|field| !field.is_attribute() || !field.is_flatten()) + .filter(|field| !field.is_attribute() && !field.is_flatten()) .filter_map(|field| { let value_label = field.get_value_label(); let label_name = field.renamed_label_without_namespace(); @@ -225,7 +225,7 @@ pub fn parse( .filter_map(|field| { let label = field.get_value_label(); let label_name = field.renamed_label_without_namespace(); - let visitor_label = build_visitor_ident(&label_name, field.get_span(), None); + let visitor_label = build_visitor_ident(&label_name, field.get_span(), None, true); let visit = |action: &TokenStream, visitor: &Ident, visitor_label: &Ident| { Some(quote! { @@ -267,7 +267,7 @@ pub fn parse( visit( &action, &Ident::new("visit_str", Span::call_site()), - &build_visitor_ident(&label_name, field.get_span(), Some(&struct_name)), + &build_visitor_ident(&label_name, field.get_span(), Some(&struct_name), true), ) }; @@ -294,7 +294,7 @@ pub fn parse( Field::FieldStruct { struct_name } => visit_vec( "e! { .push(value) }, &Ident::new("visit_str", field.get_span()), - &build_visitor_ident(&label_name, field.get_span(), Some(struct_name)), + &build_visitor_ident(&label_name, field.get_span(), Some(struct_name), true), ), Field::FieldOption { .. } | Field::FieldVec { .. } => unimplemented!("Not supported"), simple_type => visit_vec( @@ -463,7 +463,7 @@ fn build_call_visitor( ) -> Option { let value_label = field.get_value_label(); let label_name = field.renamed_label_without_namespace(); - let visitor_label = build_visitor_ident(&label_name, field.get_span(), None); + let visitor_label = build_visitor_ident(&label_name, field.get_span(), None, false); let namespaces_matching = field.get_namespace_matching( root_attributes, @@ -494,7 +494,12 @@ fn build_call_visitor( }) } -fn build_visitor_ident(label: &str, span: Span, struct_name: Option<&syn::Path>) -> Ident { +fn build_visitor_ident( + label: &str, + span: Span, + struct_name: Option<&syn::Path>, + is_attribute: bool, +) -> Ident { let struct_id = struct_name.map_or_else( || "".to_string(), |struct_name| { @@ -506,9 +511,13 @@ fn build_visitor_ident(label: &str, span: Span, struct_name: Option<&syn::Path>) }, ); + let attribute = is_attribute + .then_some("Attribute_".to_string()) + .unwrap_or_default(); + Ident::new( &format!( - "__Visitor_{}_{}", + "__Visitor_{attribute}{}_{}", label.replace('.', "_").to_upper_camel_case(), struct_id ),