diff --git a/yaserde/tests/option.rs b/yaserde/tests/option.rs index 9609796..cc9a4bd 100644 --- a/yaserde/tests/option.rs +++ b/yaserde/tests/option.rs @@ -37,6 +37,7 @@ fn basic_option_types() { test_for_type!(Option::, Some(-12.5 as f64), Some("-12.5")); test_for_type!(Option::, None, None); + // TODO // test_for_type!(Option::>, None, None); // test_for_type!(Option::>, Some(vec![0]), Some("0")); // test_for_type!(Option::>, None, None); diff --git a/yaserde/tests/skip_if.rs b/yaserde/tests/skip_if.rs index ad6f9de..ed45cb2 100644 --- a/yaserde/tests/skip_if.rs +++ b/yaserde/tests/skip_if.rs @@ -8,9 +8,18 @@ use yaserde::YaSerialize; #[test] fn skip_serializing_if_for_struct() { + fn default_string_function() -> String { + "mask_default".to_string() + } + #[derive(YaSerialize, PartialEq, Debug)] #[yaserde(root = "base")] pub struct XmlStruct { + #[yaserde( + skip_serializing_if = "check_string_function", + default = "default_string_function" + )] + string_with_default_item: String, #[yaserde(skip_serializing_if = "check_string_function")] string_item: String, #[yaserde(skip_serializing_if = "check_bool_function")] @@ -40,6 +49,7 @@ fn skip_serializing_if_for_struct() { } let model = XmlStruct { + string_with_default_item: "mask_default".to_string(), string_item: "something".to_string(), bool_item: true, f32_item: 0.0, diff --git a/yaserde_derive/src/common/field.rs b/yaserde_derive/src/common/field.rs index 4d0e2a4..e2faa0a 100644 --- a/yaserde_derive/src/common/field.rs +++ b/yaserde_derive/src/common/field.rs @@ -1,10 +1,10 @@ use crate::common::attribute::YaSerdeAttribute; -use proc_macro2::{Ident, TokenStream}; use proc_macro2::Span; +use proc_macro2::{Ident, TokenStream}; use std::fmt; use syn; -use syn::Type::Path; use syn::spanned::Spanned; +use syn::Type::Path; #[derive(Debug)] pub struct YaSerdeField { @@ -16,7 +16,7 @@ impl YaSerdeField { pub fn new(syn_field: syn::Field) -> Self { let attributes = YaSerdeAttribute::parse(&syn_field.attrs); - YaSerdeField{ + YaSerdeField { syn_field, attributes, } @@ -30,29 +30,70 @@ impl YaSerdeField { self.attributes.text } + pub fn is_flatten(&self) -> bool { + self.attributes.flatten + } + + // pub fn get_attributes(&self) -> YaSerdeAttribute { + // self.attributes.clone() + // } + pub fn label(&self) -> Option { self.syn_field.ident.clone() } + pub fn get_value_label(&self) -> Option { + self + .syn_field + .ident + .clone() + .map(|ident| syn::Ident::new(&format!("__{}_value", ident.to_string()), ident.span())) + } + + pub fn renamed_label_without_namespace(&self) -> String { + self + .attributes + .rename + .clone() + .unwrap_or_else(|| self.label().as_ref().unwrap().to_string()) + } + pub fn renamed_label(&self, root_attributes: &YaSerdeAttribute) -> String { let prefix = if root_attributes.default_namespace == self.attributes.prefix { "".to_string() } else { - self.attributes + self + .attributes .prefix .clone() .map_or("".to_string(), |prefix| prefix + ":") }; - let label = - self.attributes - .rename - .clone() - .unwrap_or_else(|| self.label().as_ref().unwrap().to_string()); + let label = self.renamed_label_without_namespace(); format!("{}{}", prefix, label) } + pub fn get_visitor_ident(&self, struct_name: Option<&syn::Path>) -> Ident { + let label = self.renamed_label_without_namespace(); + + let struct_id = struct_name.map_or_else( + || "".to_string(), + |struct_name| { + struct_name + .segments + .iter() + .map(|s| s.ident.to_string()) + .collect() + }, + ); + + Ident::new( + &format!("__Visitor_{}_{}", label.replace(".", "_"), struct_id), + self.get_span(), + ) + } + pub fn get_type(&self) -> Field { Field::from(&self.syn_field) } @@ -62,35 +103,64 @@ impl YaSerdeField { } pub fn get_default_function(&self) -> Option { - self.attributes.default.as_ref().map(|default|{ - Ident::new(&default, self.get_span()) - }) + self + .attributes + .default + .as_ref() + .map(|default| Ident::new(&default, self.get_span())) } pub fn get_skip_serializing_if_function(&self) -> Option { - self.attributes.skip_serializing_if.as_ref().map(|skip_serializing_if|{ - Ident::new(&skip_serializing_if, self.get_span()) - }) + self + .attributes + .skip_serializing_if + .as_ref() + .map(|skip_serializing_if| Ident::new(&skip_serializing_if, self.get_span())) } - pub fn ser_wrap_default_attribute(&self, builder: TokenStream, setter: TokenStream) -> TokenStream { + pub fn get_namespace_matching(&self, root_attributes: &YaSerdeAttribute) -> TokenStream { + root_attributes + .namespaces + .iter() + .map(|(prefix, namespace)| { + if self.attributes.prefix == Some(prefix.to_string()) { + Some(quote!(#namespace => {})) + } else { + None + } + }) + .filter_map(|x| x) + .collect() + } + + pub fn ser_wrap_default_attribute( + &self, + builder: Option, + setter: TokenStream, + ) -> TokenStream { let label = self.label(); - if let Some(ref default_function) = self.get_default_function() { - quote! { - let yaserde_inner = #builder; - let struct_start_event = - if self.#label != #default_function() { - #setter - } else { - struct_start_event - }; - } - } else { - quote! { - let yaserde_inner = #builder; + + let yaserde_inner_definition = builder + .map(|builder| quote!(let yaserde_inner = #builder;)) + .unwrap_or(quote!()); + + self + .get_default_function() + .map(|default_function| { + quote! { + #yaserde_inner_definition + let struct_start_event = + if self.#label != #default_function() { + #setter + } else { + struct_start_event + }; + } + }) + .unwrap_or(quote! { + #yaserde_inner_definition let struct_start_event = #setter; - } - } + }) } } @@ -140,7 +210,6 @@ impl Field { let label = attributes .rename - .clone() .unwrap_or_else(|| token_field.ident.as_ref().unwrap().to_string()); format!("{}{}", prefix, label) diff --git a/yaserde_derive/src/de/build_default_value.rs b/yaserde_derive/src/de/build_default_value.rs index 22a024e..cd1484d 100644 --- a/yaserde_derive/src/de/build_default_value.rs +++ b/yaserde_derive/src/de/build_default_value.rs @@ -1,28 +1,24 @@ -use proc_macro2::{Span, TokenStream}; -use syn::Ident; +use crate::common::YaSerdeField; +use proc_macro2::TokenStream; pub fn build_default_value( - label: &Option, - field_type: &TokenStream, - value: &TokenStream, - default: &Option, + field: &YaSerdeField, + field_type: Option, + value: TokenStream, ) -> Option { - let value = default - .as_ref() - .map(|d| { - let default_function = Ident::new( - &d, - label - .as_ref() - .map_or(Span::call_site(), |ident| ident.span()), - ); + let label = field.get_value_label(); - quote!(#default_function()) - }) + let default_value = field + .get_default_function() + .map(|default_function| quote!(#default_function())) .unwrap_or_else(|| quote!(#value)); + let field_type = field_type + .map(|field_type| quote!(: #field_type)) + .unwrap_or(quote!()); + Some(quote! { #[allow(unused_mut)] - let mut #label : #field_type = #value; + let mut #label #field_type = #default_value; }) } diff --git a/yaserde_derive/src/de/expand_enum.rs b/yaserde_derive/src/de/expand_enum.rs index c1efe82..76a110d 100644 --- a/yaserde_derive/src/de/expand_enum.rs +++ b/yaserde_derive/src/de/expand_enum.rs @@ -1,11 +1,6 @@ -use crate::common::{Field, YaSerdeAttribute}; +use crate::common::{Field, YaSerdeAttribute, YaSerdeField}; use proc_macro2::TokenStream; -use syn::{ - spanned::Spanned, - DataEnum, - Fields, - Ident, -}; +use syn::{DataEnum, Fields, Ident}; pub fn parse( data_enum: &DataEnum, @@ -142,9 +137,10 @@ fn build_unnamed_field_visitors(fields: &syn::FieldsUnnamed) -> TokenStream { fields .unnamed .iter() + .map(|field| YaSerdeField::new(field.clone())) .enumerate() .map(|(idx, field)| { - let visitor_label = Ident::new(&format!("__Visitor_{}", idx), field.span()); + let visitor_label = Ident::new(&format!("__Visitor_{}", idx), field.get_span()); let make_visitor = |visitor: &TokenStream, field_type: &TokenStream, fn_body: &TokenStream| { @@ -172,7 +168,7 @@ fn build_unnamed_field_visitors(fields: &syn::FieldsUnnamed) -> TokenStream { ) }; - match Field::from(field) { + match field.get_type() { Field::FieldStruct { struct_name } => { let struct_id: String = struct_name .segments @@ -208,9 +204,10 @@ fn build_unnamed_visitor_calls( fields .unnamed .iter() + .map(|field| YaSerdeField::new(field.clone())) .enumerate() .map(|(idx, field)| { - let visitor_label = Ident::new(&format!("__Visitor_{}", idx), field.span()); + let visitor_label = Ident::new(&format!("__Visitor_{}", idx), field.get_span()); let call_simple_type_visitor = |simple_type: Field, action| { let visitor = simple_type.get_simple_type_visitor(); @@ -278,7 +275,7 @@ fn build_unnamed_visitor_calls( } }; - match Field::from(field) { + match field.get_type() { Field::FieldStruct { struct_name } => call_struct_visitor(struct_name, set_val), Field::FieldOption { data_type } => match *data_type { Field::FieldStruct { struct_name } => call_struct_visitor(struct_name, set_opt), diff --git a/yaserde_derive/src/de/expand_struct.rs b/yaserde_derive/src/de/expand_struct.rs index 4066e62..0bc283f 100644 --- a/yaserde_derive/src/de/expand_struct.rs +++ b/yaserde_derive/src/de/expand_struct.rs @@ -1,12 +1,7 @@ -use crate::common::{Field, YaSerdeAttribute}; +use crate::common::{Field, YaSerdeAttribute, YaSerdeField}; use crate::de::build_default_value::build_default_value; use proc_macro2::{Span, TokenStream}; -use std::collections::BTreeMap; -use syn::{ - spanned::Spanned, - DataStruct, - Ident, -}; +use syn::{DataStruct, Ident}; pub fn parse( data_struct: &DataStruct, @@ -17,9 +12,9 @@ pub fn parse( let namespaces_matches: TokenStream = root_attributes .namespaces .iter() - .map(|(p, ns)| { - if root_attributes.prefix.as_ref() == Some(p) { - Some(quote!(#ns => {})) + .map(|(prefix, namespace)| { + if root_attributes.prefix.as_ref() == Some(prefix) { + Some(quote!(#namespace => {})) } else { None } @@ -30,63 +25,32 @@ pub fn parse( let variables: TokenStream = data_struct .fields .iter() - .map(|field| { - let label = &get_value_label(&field.ident); - let field_attrs = YaSerdeAttribute::parse(&field.attrs); - - match Field::from(field) { - Field::FieldStruct { struct_name } => build_default_value( - label, - "e! {#struct_name}, - "e! {#struct_name::default()}, - &field_attrs.default, - ), - Field::FieldOption { .. } => { - if let Some(d) = &field_attrs.default { - let default_function = Ident::new(&d, field.span()); - - Some(quote! { - #[allow(unused_mut, non_snake_case, non_camel_case_types)] - let mut #label = #default_function(); - }) - } else { - Some(quote! { - #[allow(unused_mut, non_snake_case, non_camel_case_types)] - let mut #label = None; - }) - } + .map(|field| YaSerdeField::new(field.clone())) + .map(|field| match field.get_type() { + Field::FieldStruct { struct_name } => build_default_value( + &field, + Some(quote!(#struct_name)), + quote!(#struct_name::default()), + ), + Field::FieldOption { .. } => build_default_value(&field, None, quote!(None)), + Field::FieldVec { data_type } => match *data_type { + Field::FieldStruct { ref struct_name } => { + build_default_value(&field, Some(quote!(Vec<#struct_name>)), quote!(vec![])) + } + Field::FieldOption { .. } | Field::FieldVec { .. } => { + unimplemented!(); } - Field::FieldVec { data_type } => match *data_type { - Field::FieldStruct { ref struct_name } => build_default_value( - label, - "e! {Vec<#struct_name>}, - "e! {vec![]}, - &field_attrs.default, - ), - Field::FieldOption { .. } | Field::FieldVec { .. } => { - unimplemented!(); - } - simple_type => { - let type_token: TokenStream = simple_type.into(); - - build_default_value( - label, - "e! {Vec<#type_token>}, - "e! {vec![]}, - &field_attrs.default, - ) - } - }, simple_type => { let type_token: TokenStream = simple_type.into(); - build_default_value( - label, - &type_token, - "e! {#type_token::default()}, - &field_attrs.default, - ) + build_default_value(&field, Some(quote!(Vec<#type_token>)), quote!(vec![])) } + }, + simple_type => { + let type_token: TokenStream = simple_type.into(); + let value_builder = quote!(#type_token::default()); + + build_default_value(&field, Some(type_token), value_builder) } }) .filter_map(|x| x) @@ -95,12 +59,8 @@ pub fn parse( let field_visitors: TokenStream = data_struct .fields .iter() + .map(|field| YaSerdeField::new(field.clone())) .map(|field| { - let field_attrs = YaSerdeAttribute::parse(&field.attrs); - let label_name = field_attrs - .rename - .unwrap_or_else(|| field.ident.as_ref().unwrap().to_string()); - let struct_visitor = |struct_name: syn::Path| { let struct_id: String = struct_name .segments @@ -108,7 +68,7 @@ pub fn parse( .map(|s| s.ident.to_string()) .collect(); - let visitor_label = build_visitor_ident(&label_name, field.span(), Some(&struct_name)); + let visitor_label = field.get_visitor_ident(Some(&struct_name)); Some(quote! { #[allow(non_snake_case, non_camel_case_types)] @@ -127,7 +87,7 @@ pub fn parse( let simple_type_visitor = |simple_type: Field| { let visitor = simple_type.get_simple_type_visitor(); - let visitor_label = build_visitor_ident(&label_name, field.span(), None); + let visitor_label = field.get_visitor_ident(None); let field_type: TokenStream = simple_type.into(); Some(quote! { @@ -143,7 +103,7 @@ pub fn parse( }) }; - match Field::from(field) { + match field.get_type() { Field::FieldStruct { struct_name } => struct_visitor(struct_name), Field::FieldOption { data_type } => match *data_type { Field::FieldStruct { struct_name } => struct_visitor(struct_name), @@ -164,19 +124,11 @@ pub fn parse( let call_visitors: TokenStream = data_struct .fields .iter() + .map(|field| YaSerdeField::new(field.clone())) + .filter(|field| !field.is_attribute() || !field.is_flatten()) .map(|field| { - let field_attrs = YaSerdeAttribute::parse(&field.attrs); - let label = &field.ident; - let value_label = &get_value_label(&field.ident); - - if field_attrs.attribute || field_attrs.flatten { - return None; - } - - let label_name = field_attrs - .rename - .clone() - .unwrap_or_else(|| label.as_ref().unwrap().to_string()); + let value_label = field.get_value_label(); + let label_name = field.renamed_label_without_namespace(); let visit_struct = |struct_name: syn::Path, action: TokenStream| { Some(quote! { @@ -201,10 +153,8 @@ pub fn parse( &field_type, &field_visitor, &action, - &field_attrs, - label, - &root_attributes.namespaces, - field.span(), + &field, + &root_attributes, ) }; @@ -214,7 +164,7 @@ pub fn parse( simple_type => visit_simple(simple_type, action), }; - match Field::from(field) { + match field.get_type() { Field::FieldStruct { struct_name } => visit_struct(struct_name, quote! {= value}), Field::FieldOption { data_type } => visit_sub(data_type, quote! {= Some(value)}), Field::FieldVec { data_type } => visit_sub(data_type, quote! {.push(value)}), @@ -227,15 +177,12 @@ pub fn parse( let call_flatten_visitors: TokenStream = data_struct .fields .iter() + .map(|field| YaSerdeField::new(field.clone())) + .filter(|field| !field.is_attribute() && field.is_flatten()) .map(|field| { - let field_attrs = YaSerdeAttribute::parse(&field.attrs); - let value_label = &get_value_label(&field.ident); + let value_label = field.get_value_label(); - if field_attrs.attribute || !field_attrs.flatten { - return None; - } - - match Field::from(field) { + match field.get_type() { Field::FieldStruct { .. } => Some(quote! { #value_label = yaserde::de::from_str(&unused_xml_elements)?; }), @@ -243,9 +190,9 @@ pub fn parse( Field::FieldStruct { .. } => Some(quote! { #value_label = yaserde::de::from_str(&unused_xml_elements).ok(); }), - field_type => unimplemented!("\"flatten\" is not implemented for {:?}", field_type), + field_type => unimplemented!(r#""flatten" is not implemented for {:?}"#, field_type), }, - field_type => unimplemented!("\"flatten\" is not implemented for {:?}", field_type), + field_type => unimplemented!(r#""flatten" is not implemented for {:?}"#, field_type), } }) .filter_map(|x| x) @@ -254,19 +201,12 @@ pub fn parse( let attributes_loading: TokenStream = data_struct .fields .iter() + .map(|field| YaSerdeField::new(field.clone())) + .filter(|field| field.is_attribute()) .map(|field| { - let field_attrs = YaSerdeAttribute::parse(&field.attrs); - if !field_attrs.attribute { - return None; - } - - let label = &get_value_label(&field.ident); - - let label_name = field_attrs - .rename - .unwrap_or_else(|| field.ident.as_ref().unwrap().to_string()); - - let visitor_label = build_visitor_ident(&label_name, field.span(), None); + 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 visit = |action: &TokenStream, visitor: &TokenStream, visitor_label: &Ident| { Some(quote! { @@ -294,7 +234,7 @@ pub fn parse( visit( &action, "e! {visit_str}, - &build_visitor_ident(&label_name, field.span(), Some(&struct_name)), + &build_visitor_ident(&label_name, field.get_span(), Some(&struct_name)), ) }; @@ -312,7 +252,7 @@ pub fn parse( simple_type => visit_simple(simple_type, action), }; - match Field::from(field) { + match field.get_type() { Field::FieldString => visit_string(), Field::FieldOption { data_type } => visit_sub(data_type, quote! {= Some(value)}), Field::FieldVec { .. } => unimplemented!(), @@ -326,19 +266,19 @@ pub fn parse( let set_text: TokenStream = data_struct .fields .iter() + .map(|field| YaSerdeField::new(field.clone())) .map(|field| { - let label = &get_value_label(&field.ident); - let field_attrs = YaSerdeAttribute::parse(&field.attrs); + let label = field.get_value_label(); let set_text = |action: &TokenStream| { - if field_attrs.text { + if field.is_text_content() { Some(quote! {#label = #action;}) } else { None } }; - match Field::from(field) { + match field.get_type() { Field::FieldString => set_text("e! {text_content.to_owned()}), Field::FieldStruct { .. } | Field::FieldOption { .. } | Field::FieldVec { .. } => None, simple_type => { @@ -353,9 +293,10 @@ pub fn parse( let struct_builder: TokenStream = data_struct .fields .iter() + .map(|field| YaSerdeField::new(field.clone())) .map(|field| { - let label = &field.ident; - let value_label = &get_value_label(&field.ident); + let label = &field.label(); + let value_label = field.get_value_label(); quote! { #label: #value_label, } }) @@ -471,33 +412,14 @@ fn build_call_visitor( field_type: &TokenStream, visitor: &TokenStream, action: &TokenStream, - field_attrs: &YaSerdeAttribute, - label: &Option, - namespaces: &BTreeMap, - span: Span, + field: &YaSerdeField, + root_attributes: &YaSerdeAttribute, ) -> Option { - let prefix = field_attrs.prefix.clone(); + 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 label = &field.ident; - let value_label = get_value_label(label); - let label_name = field_attrs - .rename - .clone() - .unwrap_or_else(|| label.as_ref().unwrap().to_string()); - - let visitor_label = build_visitor_ident(&label_name, span, None); - - let namespaces_matches: TokenStream = namespaces - .iter() - .map(|(p, ns)| { - if prefix == Some(p.to_string()) { - Some(quote!(#ns => {})) - } else { - None - } - }) - .filter_map(|x| x) - .collect(); + let namespaces_matches = field.get_namespace_matching(root_attributes); Some(quote! { #label_name => { @@ -530,12 +452,6 @@ fn build_call_visitor( }) } -fn get_value_label(ident: &Option) -> Option { - ident - .clone() - .map(|ident| syn::Ident::new(&format!("__{}_value", ident.to_string()), ident.span())) -} - fn build_visitor_ident(label: &str, span: Span, struct_name: Option<&syn::Path>) -> Ident { let struct_id = struct_name.map_or_else( || "".to_string(), diff --git a/yaserde_derive/src/ser/element.rs b/yaserde_derive/src/ser/element.rs index 65e5c44..d00e832 100644 --- a/yaserde_derive/src/ser/element.rs +++ b/yaserde_derive/src/ser/element.rs @@ -1,5 +1,5 @@ -use crate::common::YaSerdeAttribute; -use proc_macro2::{Ident, Span, TokenStream}; +use crate::common::YaSerdeField; +use proc_macro2::{Ident, TokenStream}; pub fn enclose_formatted_characters(label: &Ident, label_name: String) -> TokenStream { enclose_xml_event(label_name, quote!(format!("{}", &self.#label))) @@ -13,7 +13,7 @@ pub fn enclose_characters(label: &Option, label_name: String) -> TokenStr enclose_xml_event(label_name, quote!(format!("{}", self.#label))) } -pub fn enclose_xml_event(label_name: String, yaserde_format: TokenStream) -> TokenStream { +fn enclose_xml_event(label_name: String, yaserde_format: TokenStream) -> TokenStream { quote! { let start_event = XmlEvent::start_element(#label_name); writer.write(start_event).map_err(|e| e.to_string())?; @@ -41,34 +41,23 @@ pub fn serialize_element( }) } -pub fn condition_generator(label: &Option, attributes: &YaSerdeAttribute) -> TokenStream { - let mut conditions = None; +pub fn condition_generator(label: &Option, field: &YaSerdeField) -> TokenStream { + let default_condition = field + .get_default_function() + .map(|default_function| quote!(self.#label != #default_function())); - if let Some(ref d) = attributes.default { - let default_function = Ident::new( - &d, - label - .as_ref() - .map_or(Span::call_site(), |ident| ident.span()), - ); - - conditions = Some(quote!(self.#label != #default_function())) - } - - if let Some(ref s) = attributes.skip_serializing_if { - let skip_if_function = Ident::new( - &s, - label - .as_ref() - .map_or(Span::call_site(), |ident| ident.span()), - ); - - conditions = if let Some(prev_conditions) = conditions { - Some(quote!(!#skip_if_function() && #prev_conditions)) - } else { - Some(quote!(!self.#skip_if_function(&self.#label))) - }; - } - - conditions.map(|c| quote!(if #c)).unwrap_or(quote!()) + field + .get_skip_serializing_if_function() + .map(|skip_if_function| { + if let Some(prev_conditions) = &default_condition { + quote!(if !self.#skip_if_function(&self.#label) && #prev_conditions) + } else { + quote!(if !self.#skip_if_function(&self.#label)) + } + }) + .unwrap_or_else(|| { + default_condition + .map(|condition| quote!(if #condition)) + .unwrap_or(quote!()) + }) } diff --git a/yaserde_derive/src/ser/expand_enum.rs b/yaserde_derive/src/ser/expand_enum.rs index 74a04bf..eb9521c 100644 --- a/yaserde_derive/src/ser/expand_enum.rs +++ b/yaserde_derive/src/ser/expand_enum.rs @@ -52,7 +52,6 @@ fn inner_enum_inspector( .map(|field| YaSerdeField::new(field.clone())) .filter(|field| !field.is_attribute()) .map(|field| { - let field_label = field.label(); if field.is_text_content() { @@ -132,11 +131,9 @@ fn inner_enum_inspector( let enum_fields: TokenStream = fields .unnamed .iter() - .map(|token_field| { - if Field::is_attribute(token_field) { - return None; - } - + .map(|field| YaSerdeField::new(field.clone())) + .filter(|field| !field.is_attribute()) + .map(|field| { let write_element = |action: &TokenStream| { quote! { let struct_start_event = XmlEvent::start_element(#label_name); @@ -184,7 +181,7 @@ fn inner_enum_inspector( } }; - match Field::from(token_field) { + match field.get_type() { Field::FieldOption { data_type } => { let write = write_sub_type(*data_type); diff --git a/yaserde_derive/src/ser/expand_struct.rs b/yaserde_derive/src/ser/expand_struct.rs index c37b5e7..1201df4 100644 --- a/yaserde_derive/src/ser/expand_struct.rs +++ b/yaserde_derive/src/ser/expand_struct.rs @@ -2,7 +2,6 @@ use crate::common::{Field, YaSerdeAttribute, YaSerdeField}; use crate::ser::{element::*, implement_deserializer::implement_deserializer}; use proc_macro2::TokenStream; -use syn::spanned::Spanned; use syn::DataStruct; use syn::Ident; @@ -33,27 +32,23 @@ pub fn serialize( | Field::FieldI64 | Field::FieldU64 | Field::FieldF32 - | Field::FieldF64 => { - Some(field.ser_wrap_default_attribute( - quote!(self.#label.to_string()), - quote!({ - struct_start_event.attr(#label_name, &yaserde_inner) - }) - )) - } + | Field::FieldF64 => Some(field.ser_wrap_default_attribute( + Some(quote!(self.#label.to_string())), + quote!({ + struct_start_event.attr(#label_name, &yaserde_inner) + }), + )), Field::FieldOption { data_type } => match *data_type { - Field::FieldString => { - Some(field.ser_wrap_default_attribute( - quote!({}), - quote!({ - if let Some(ref value) = self.#label { - struct_start_event.attr(#label_name, value) - } else { - struct_start_event - } - }) - )) - } + Field::FieldString => Some(field.ser_wrap_default_attribute( + None, + quote!({ + if let Some(ref value) = self.#label { + struct_start_event.attr(#label_name, value) + } else { + struct_start_event + } + }), + )), Field::FieldBool | Field::FieldI8 | Field::FieldU8 @@ -64,57 +59,51 @@ pub fn serialize( | Field::FieldI64 | Field::FieldU64 | Field::FieldF32 - | Field::FieldF64 => { - Some(field.ser_wrap_default_attribute( - quote!(self.#label.map_or_else(|| String::new(), |v| v.to_string())), - quote!({ - if let Some(ref value) = self.#label { - struct_start_event.attr(#label_name, &yaserde_inner) - } else { - struct_start_event - } - }) - )) - } + | Field::FieldF64 => Some(field.ser_wrap_default_attribute( + Some(quote!(self.#label.map_or_else(|| String::new(), |v| v.to_string()))), + quote!({ + if let Some(ref value) = self.#label { + struct_start_event.attr(#label_name, &yaserde_inner) + } else { + struct_start_event + } + }), + )), Field::FieldVec { .. } => { let item_ident = Ident::new("yaserde_item", field.get_span()); let inner = enclose_formatted_characters(&item_ident, label_name); Some(field.ser_wrap_default_attribute( - quote!({}), + None, quote!({ if let Some(ref yaserde_list) = self.#label { for yaserde_item in yaserde_list.iter() { #inner } } - }) + }), )) } - Field::FieldStruct { .. } => { - Some(field.ser_wrap_default_attribute( - quote!(self.#label + Field::FieldStruct { .. } => Some(field.ser_wrap_default_attribute( + Some(quote!(self.#label .as_ref() - .map_or_else(|| Ok(String::new()), |v| yaserde::ser::to_string_content(v))?), - quote!({ - if let Some(ref yaserde_struct) = self.#label { - struct_start_event.attr(#label_name, &yaserde_inner) - } else { - struct_start_event - } - }) - )) - } + .map_or_else(|| Ok(String::new()), |v| yaserde::ser::to_string_content(v))?)), + quote!({ + if let Some(ref yaserde_struct) = self.#label { + struct_start_event.attr(#label_name, &yaserde_inner) + } else { + struct_start_event + } + }), + )), Field::FieldOption { .. } => unimplemented!(), }, - Field::FieldStruct { .. } => { - Some(field.ser_wrap_default_attribute( - quote!(yaserde::ser::to_string_content(&self.#label)?), - quote!({ - struct_start_event.attr(#label_name, &yaserde_inner) - }) - )) - } + Field::FieldStruct { .. } => Some(field.ser_wrap_default_attribute( + Some(quote!(yaserde::ser::to_string_content(&self.#label)?)), + quote!({ + struct_start_event.attr(#label_name, &yaserde_inner) + }), + )), Field::FieldVec { .. } => None, } }) @@ -124,25 +113,21 @@ pub fn serialize( let struct_inspector: TokenStream = data_struct .fields .iter() + .map(|field| YaSerdeField::new(field.clone())) + .filter(|field| !field.is_attribute()) .map(|field| { - let field_attrs = YaSerdeAttribute::parse(&field.attrs); - if Field::is_attribute(field) { - return None; - } - - let label = Field::label(field); - if Field::is_text_content(field) { + let label = field.label(); + if field.is_text_content() { return Some(quote!( let data_event = XmlEvent::characters(&self.#label); writer.write(data_event).map_err(|e| e.to_string())?; )); } - let label_name = Field::renamed_label(field, root_attributes); + let label_name = field.renamed_label(root_attributes); + let conditions = condition_generator(&label, &field); - let conditions = condition_generator(&label, &field_attrs); - - match Field::from(field) { + match field.get_type() { Field::FieldString | Field::FieldBool | Field::FieldI8 @@ -169,7 +154,7 @@ pub fn serialize( | Field::FieldU64 | Field::FieldF32 | Field::FieldF64 => { - let item_ident = Ident::new("yaserde_item", field.span()); + let item_ident = Ident::new("yaserde_item", field.get_span()); let inner = enclose_formatted_characters_for_value(&item_ident, label_name); Some(quote! { @@ -181,7 +166,7 @@ pub fn serialize( }) } Field::FieldVec { .. } => { - let item_ident = Ident::new("yaserde_item", field.span()); + let item_ident = Ident::new("yaserde_item", field.get_span()); let inner = enclose_formatted_characters_for_value(&item_ident, label_name); Some(quote! { @@ -194,7 +179,7 @@ pub fn serialize( } }) } - Field::FieldStruct { .. } => Some(if field_attrs.flatten { + Field::FieldStruct { .. } => Some(if field.is_flatten() { quote! { if let Some(ref item) = &self.#label { writer.set_start_event_name(None); @@ -214,7 +199,7 @@ pub fn serialize( _ => unimplemented!(), }, Field::FieldStruct { .. } => { - let (start_event, skip_start) = if field_attrs.flatten { + let (start_event, skip_start) = if field.is_flatten() { (quote!(None), true) } else { (quote!(Some(#label_name.to_string())), false) @@ -228,7 +213,7 @@ pub fn serialize( } Field::FieldVec { data_type } => match *data_type { Field::FieldString => { - let item_ident = Ident::new("yaserde_item", field.span()); + let item_ident = Ident::new("yaserde_item", field.get_span()); let inner = enclose_formatted_characters_for_value(&item_ident, label_name); Some(quote! { @@ -248,7 +233,7 @@ pub fn serialize( | Field::FieldU64 | Field::FieldF32 | Field::FieldF64 => { - let item_ident = Ident::new("yaserde_item", field.span()); + let item_ident = Ident::new("yaserde_item", field.get_span()); let inner = enclose_formatted_characters_for_value(&item_ident, label_name); Some(quote! {