diff --git a/yaserde_derive/src/common/field.rs b/yaserde_derive/src/common/field.rs index 6e01569..4d0e2a4 100644 --- a/yaserde_derive/src/common/field.rs +++ b/yaserde_derive/src/common/field.rs @@ -1,8 +1,98 @@ use crate::common::attribute::YaSerdeAttribute; use proc_macro2::{Ident, TokenStream}; +use proc_macro2::Span; use std::fmt; use syn; use syn::Type::Path; +use syn::spanned::Spanned; + +#[derive(Debug)] +pub struct YaSerdeField { + syn_field: syn::Field, + attributes: YaSerdeAttribute, +} + +impl YaSerdeField { + pub fn new(syn_field: syn::Field) -> Self { + let attributes = YaSerdeAttribute::parse(&syn_field.attrs); + + YaSerdeField{ + syn_field, + attributes, + } + } + + pub fn is_attribute(&self) -> bool { + self.attributes.attribute + } + + pub fn is_text_content(&self) -> bool { + self.attributes.text + } + + pub fn label(&self) -> Option { + self.syn_field.ident.clone() + } + + pub fn renamed_label(&self, root_attributes: &YaSerdeAttribute) -> String { + let prefix = if root_attributes.default_namespace == self.attributes.prefix { + "".to_string() + } else { + 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()); + + format!("{}{}", prefix, label) + } + + pub fn get_type(&self) -> Field { + Field::from(&self.syn_field) + } + + pub fn get_span(&self) -> Span { + self.syn_field.span() + } + + pub fn get_default_function(&self) -> Option { + 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()) + }) + } + + pub fn ser_wrap_default_attribute(&self, builder: TokenStream, 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 struct_start_event = #setter; + } + } + } +} #[derive(Debug)] pub enum Field { diff --git a/yaserde_derive/src/common/mod.rs b/yaserde_derive/src/common/mod.rs index 2dc2de9..cee0625 100644 --- a/yaserde_derive/src/common/mod.rs +++ b/yaserde_derive/src/common/mod.rs @@ -2,4 +2,4 @@ mod attribute; mod field; pub use attribute::YaSerdeAttribute; -pub use field::Field; +pub use field::{Field, YaSerdeField}; diff --git a/yaserde_derive/src/ser/expand_enum.rs b/yaserde_derive/src/ser/expand_enum.rs index cb85a93..74a04bf 100644 --- a/yaserde_derive/src/ser/expand_enum.rs +++ b/yaserde_derive/src/ser/expand_enum.rs @@ -1,4 +1,4 @@ -use crate::common::{Field, YaSerdeAttribute}; +use crate::common::{Field, YaSerdeAttribute, YaSerdeField}; use crate::ser::{implement_deserializer::implement_deserializer, label::build_label_name}; use proc_macro2::TokenStream; use syn::DataEnum; @@ -49,23 +49,22 @@ fn inner_enum_inspector( let enum_fields: TokenStream = fields .named .iter() + .map(|field| YaSerdeField::new(field.clone())) + .filter(|field| !field.is_attribute()) .map(|field| { - if Field::is_attribute(field) { - return None; - } - let field_label = Field::label(field); + let field_label = field.label(); - if Field::is_text_content(field) { + if field.is_text_content() { return Some(quote!( let data_event = XmlEvent::characters(&self.#field_label); writer.write(data_event).map_err(|e| e.to_string())?; )); } - let field_label_name = Field::renamed_label(field, root_attributes); + let field_label_name = field.renamed_label(root_attributes); - match Field::from(field) { + match field.get_type() { Field::FieldString | Field::FieldBool | Field::FieldU8 diff --git a/yaserde_derive/src/ser/expand_struct.rs b/yaserde_derive/src/ser/expand_struct.rs index 32567f9..c37b5e7 100644 --- a/yaserde_derive/src/ser/expand_struct.rs +++ b/yaserde_derive/src/ser/expand_struct.rs @@ -1,4 +1,4 @@ -use crate::common::{Field, YaSerdeAttribute}; +use crate::common::{Field, YaSerdeAttribute, YaSerdeField}; use crate::ser::{element::*, implement_deserializer::implement_deserializer}; use proc_macro2::TokenStream; @@ -15,16 +15,13 @@ pub fn serialize( let build_attributes: 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(); + let label_name = field.renamed_label(root_attributes); - let label = Field::label(field); - let label_name = Field::renamed_label(field, root_attributes); - - match Field::from(field) { + match field.get_type() { Field::FieldString | Field::FieldBool | Field::FieldI8 @@ -37,50 +34,25 @@ pub fn serialize( | Field::FieldU64 | Field::FieldF32 | Field::FieldF64 => { - if let Some(ref d) = field_attrs.default { - let default_function = Ident::new(&d, field.span()); - Some(quote! { - let content = self.#label.to_string(); - let struct_start_event = - if self.#label != #default_function() { - struct_start_event.attr(#label_name, &content) - } else { - struct_start_event - }; + Some(field.ser_wrap_default_attribute( + quote!(self.#label.to_string()), + quote!({ + struct_start_event.attr(#label_name, &yaserde_inner) }) - } else { - Some(quote! { - let content = self.#label.to_string(); - let struct_start_event = struct_start_event.attr(#label_name, &content); - }) - } + )) } Field::FieldOption { data_type } => match *data_type { Field::FieldString => { - if let Some(ref d) = field_attrs.default { - let default_function = Ident::new(&d, field.span()); - Some(quote! { - let struct_start_event = - if self.#label != #default_function() { - if let Some(ref value) = self.#label { - struct_start_event.attr(#label_name, &value) - } else { - struct_start_event - } - } else { - struct_start_event - }; + 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 + } }) - } else { - Some(quote! { - let struct_start_event = - if let Some(ref value) = self.#label { - struct_start_event.attr(#label_name, &value) - } else { - struct_start_event - }; - }) - } + )) } Field::FieldBool | Field::FieldI8 @@ -93,109 +65,57 @@ pub fn serialize( | Field::FieldU64 | Field::FieldF32 | Field::FieldF64 => { - if let Some(ref d) = field_attrs.default { - let default_function = Ident::new(&d, field.span()); - Some(quote! { - let content = self.#label.map_or_else(|| String::new(), |v| v.to_string()); - let struct_start_event = - if self.#label != #default_function() { - if let Some(ref value) = self.#label { - struct_start_event.attr(#label_name, &content) - } else { - struct_start_event - } - } else { - struct_start_event - }; + 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 + } }) - } else { - Some(quote! { - let content = self.#label.map_or_else(|| String::new(), |v| v.to_string()); - let struct_start_event = - if let Some(ref value) = self.#label { - struct_start_event.attr(#label_name, &content) - } else { - struct_start_event - }; - }) - } + )) } 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(&item_ident, label_name); - if let Some(ref d) = field_attrs.default { - let default_function = Ident::new(&d, field.span()); - - Some(quote! { - if self.#label != #default_function() { - if let Some(ref yaserde_list) = self.#label { - for yaserde_item in yaserde_list.iter() { - #inner - } + Some(field.ser_wrap_default_attribute( + quote!({}), + quote!({ + if let Some(ref yaserde_list) = self.#label { + for yaserde_item in yaserde_list.iter() { + #inner } } }) - } else { - Some(quote! { - for yaserde_item in &self.#label { - #inner - } - }) - } + )) } Field::FieldStruct { .. } => { - if let Some(ref d) = field_attrs.default { - let default_function = Ident::new(&d, field.span()); - Some(quote! { - let content = self.#label + Some(field.ser_wrap_default_attribute( + quote!(self.#label .as_ref() - .map_or_else(|| Ok(String::new()), |v| yaserde::ser::to_string_content(v))?; - let struct_start_event = if let Some(ref value) = self.#label { - if *value != #default_function() { - struct_start_event.attr(#label_name, &content) - } 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 - }; + } }) - } else { - Some(quote! { - let content = self.#label - .as_ref() - .map_or_else(|| Ok(String::new()), |v| yaserde::ser::to_string_content(v))?; - let struct_start_event = if let Some(ref value) = self.#label { - struct_start_event.attr(#label_name, &content) - } else { - struct_start_event - }; - }) - } + )) } - _ => unimplemented!(), + Field::FieldOption { .. } => unimplemented!(), }, Field::FieldStruct { .. } => { - if let Some(ref d) = field_attrs.default { - let default_function = Ident::new(&d, field.span()); - Some(quote! { - let content = yaserde::ser::to_string_content(&self.#label)?; - let struct_start_event = - if self.#label != #default_function() { - struct_start_event.attr(#label_name, &content) - } else { - struct_start_event - }; + Some(field.ser_wrap_default_attribute( + quote!(yaserde::ser::to_string_content(&self.#label)?), + quote!({ + struct_start_event.attr(#label_name, &yaserde_inner) }) - } else { - Some(quote! { - let content = yaserde::ser::to_string_content(&self.#label)?; - let struct_start_event = struct_start_event.attr(#label_name, &content); - }) - } + )) } - _ => None, + Field::FieldVec { .. } => None, } }) .filter_map(|x| x)