Skip to content

Commit

Permalink
fix: support attribute and field with same name
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcAntoine-Arnaud committed Feb 3, 2024
1 parent 0578b73 commit 34c28b1
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 11 deletions.
39 changes: 39 additions & 0 deletions yaserde/tests/deserializer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<String>,
content: Option<String>,
}

convert_and_validate!(
r#"<Struct />"#,
Struct,
Struct {
attribute: None,
content: None
}
);

convert_and_validate!(
r#"<Struct content="attribute" />"#,
Struct,
Struct {
attribute: Some("attribute".to_string()),
content: None
}
);

convert_and_validate!(
r#"<Struct content="attribute"><content>Field</content></Struct>"#,
Struct,
Struct {
attribute: Some("attribute".to_string()),
content: Some("Field".to_string())
}
);
}

#[test]
fn de_rename() {
init();
Expand Down
8 changes: 6 additions & 2 deletions yaserde_derive/src/common/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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
),
Expand Down
27 changes: 18 additions & 9 deletions yaserde_derive/src/de/expand_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand All @@ -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" {
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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! {
Expand Down Expand Up @@ -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),
)
};

Expand All @@ -294,7 +294,7 @@ pub fn parse(
Field::FieldStruct { struct_name } => visit_vec(
&quote! { .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(
Expand Down Expand Up @@ -463,7 +463,7 @@ fn build_call_visitor(
) -> Option<TokenStream> {
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,
Expand Down Expand Up @@ -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| {
Expand All @@ -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
),
Expand Down

0 comments on commit 34c28b1

Please sign in to comment.