diff --git a/yaserde_derive/src/ser/expand_enum.rs b/yaserde_derive/src/ser/expand_enum.rs index a357272..71cd343 100644 --- a/yaserde_derive/src/ser/expand_enum.rs +++ b/yaserde_derive/src/ser/expand_enum.rs @@ -1,5 +1,9 @@ use crate::attribute::*; use crate::field_type::*; +use crate::ser::{ + implement_deserializer::implement_deserializer, + label::build_label_name, +}; use proc_macro2::TokenStream; use syn::spanned::Spanned; use syn::DataEnum; @@ -12,20 +16,32 @@ pub fn serialize( root: &str, root_attributes: &YaSerdeAttribute, ) -> TokenStream { - let write_enum_content: TokenStream = data_enum + let inner_enum_inspector = inner_enum_inspector(data_enum, name, root_attributes); + + implement_deserializer( + name, + root, + root_attributes, + quote!(), + quote!(match self { + #inner_enum_inspector + }), + ) +} + +fn inner_enum_inspector( + data_enum: &DataEnum, + name: &Ident, + root_attributes: &YaSerdeAttribute, + ) -> TokenStream { + data_enum .variants .iter() .map(|variant| { - let label = &variant.ident; - let label_name = { - let variant_attrs = YaSerdeAttribute::parse(&variant.attrs); - let prefix = variant_attrs.prefix.map_or(String::new(), |p| p + ":"); - let renamed_label = variant_attrs - .rename - .unwrap_or_else(|| variant.ident.to_string()); + let variant_attrs = YaSerdeAttribute::parse(&variant.attrs); - prefix + renamed_label.as_str() - }; + let label = &variant.ident; + let label_name = build_label_name(&label, &variant_attrs, &root_attributes.default_namespace); match variant.fields { Fields::Unit => Some(quote! { @@ -220,58 +236,5 @@ pub fn serialize( } }) .filter_map(|x| x) - .collect(); - - let add_namespaces: TokenStream = root_attributes - .namespaces - .iter() - .map(|(prefix, namespace)| { - if let Some(dn) = &root_attributes.default_namespace { - if dn == prefix { - return Some(quote!( - .default_ns(#namespace) - )); - } - } - Some(quote!( - .ns(#prefix, #namespace) - )) - }) - .filter_map(|x| x) - .collect(); - - let flatten = root_attributes.flatten; - - quote! { - use xml::writer::XmlEvent; - - impl YaSerialize for #name { - #[allow(unused_variables)] - fn serialize(&self, writer: &mut yaserde::ser::Serializer) - -> Result<(), String> { - let skip = writer.skip_start_end(); - - if !#flatten && !skip { - if let Some(label) = writer.get_start_event_name() { - let struct_start_event = XmlEvent::start_element(label.as_ref()); - writer.write(struct_start_event).map_err(|e| e.to_string())?; - } else { - let struct_start_event = XmlEvent::start_element(#root)#add_namespaces; - writer.write(struct_start_event).map_err(|e| e.to_string())?; - } - } - - match self { - #write_enum_content - } - - if !#flatten && !skip { - let struct_end_event = XmlEvent::end_element(); - writer.write(struct_end_event).map_err(|e| e.to_string())?; - } - - Ok(()) - } - } - } + .collect() } diff --git a/yaserde_derive/src/ser/expand_struct.rs b/yaserde_derive/src/ser/expand_struct.rs index 83bbd19..4b36882 100644 --- a/yaserde_derive/src/ser/expand_struct.rs +++ b/yaserde_derive/src/ser/expand_struct.rs @@ -1,8 +1,11 @@ use crate::attribute::*; use crate::field_type::*; -use crate::ser::element::*; +use crate::ser::{ + element::*, + implement_deserializer::implement_deserializer, + label::build_label_name, +}; use proc_macro2::TokenStream; -use std::string::ToString; use syn::spanned::Spanned; use syn::DataStruct; use syn::Ident; @@ -24,7 +27,7 @@ pub fn serialize( let label = &field.ident; - let label_name = build_label_name(&field, &field_attrs, &root_attributes.default_namespace); + let label_name = build_label_name(&label.as_ref().unwrap(), &field_attrs, &root_attributes.default_namespace); get_field_type(field).and_then(|f| match f { FieldType::FieldTypeString @@ -203,24 +206,6 @@ pub fn serialize( .filter_map(|x| x) .collect(); - let add_namespaces: TokenStream = root_attributes - .namespaces - .iter() - .map(|(prefix, namespace)| { - if let Some(dn) = &root_attributes.default_namespace { - if dn == prefix { - return Some(quote!( - .default_ns(#namespace) - )); - } - } - Some(quote!( - .ns(#prefix, #namespace) - )) - }) - .filter_map(|x| x) - .collect(); - let struct_inspector: TokenStream = data_struct .fields .iter() @@ -238,7 +223,7 @@ pub fn serialize( )); } - let label_name = build_label_name(&field, &field_attrs, &root_attributes.default_namespace); + let label_name = build_label_name(&label.as_ref().unwrap(), &field_attrs, &root_attributes.default_namespace); let conditions = condition_generator(label, &field_attrs); get_field_type(field).and_then(|f| match f { @@ -380,55 +365,11 @@ pub fn serialize( .filter_map(|x| x) .collect(); - let flatten = root_attributes.flatten; - - quote! { - use xml::writer::XmlEvent; - - impl YaSerialize for #name { - #[allow(unused_variables)] - fn serialize(&self, writer: &mut yaserde::ser::Serializer) - -> Result<(), String> { - let skip = writer.skip_start_end(); - - if !#flatten && !skip { - let yaserde_label = writer.get_start_event_name().unwrap_or_else(|| #root.to_string()); - let struct_start_event = XmlEvent::start_element(yaserde_label.as_ref())#add_namespaces; - #build_attributes - writer.write(struct_start_event).map_err(|e| e.to_string())?; - } - - #struct_inspector - - if !#flatten && !skip { - let struct_end_event = XmlEvent::end_element(); - writer.write(struct_end_event).map_err(|e| e.to_string())?; - } - - Ok(()) - } - } - } -} - -fn build_label_name( - field: &syn::Field, - field_attrs: &YaSerdeAttribute, - default_namespace: &Option, -) -> String { - let prefix = if default_namespace == &field_attrs.prefix { - "".to_string() - } else { - field_attrs - .prefix - .clone() - .map_or("".to_string(), |prefix| prefix + ":") - }; - - let label = field_attrs - .rename - .clone() - .unwrap_or_else(|| field.ident.as_ref().unwrap().to_string()); - - format!("{}{}", prefix, label) + implement_deserializer( + name, + root, + root_attributes, + build_attributes, + struct_inspector, + ) } diff --git a/yaserde_derive/src/ser/implement_deserializer.rs b/yaserde_derive/src/ser/implement_deserializer.rs new file mode 100644 index 0000000..b128d7b --- /dev/null +++ b/yaserde_derive/src/ser/implement_deserializer.rs @@ -0,0 +1,43 @@ +use crate::attribute::YaSerdeAttribute; +use crate::ser::namespace::generate_namespaces_definition; +use proc_macro2::Ident; +use proc_macro2::TokenStream; + +pub fn implement_deserializer( + name: &Ident, + root: &str, + attributes: &YaSerdeAttribute, + attributes_inspector: TokenStream, + inner_inspector: TokenStream, +) -> TokenStream { + let namespaces_definition = generate_namespaces_definition(attributes); + let flatten = attributes.flatten; + + quote! { + use xml::writer::XmlEvent; + + impl YaSerialize for #name { + #[allow(unused_variables)] + fn serialize(&self, writer: &mut yaserde::ser::Serializer) + -> Result<(), String> { + let skip = writer.skip_start_end(); + + if !#flatten && !skip { + let yaserde_label = writer.get_start_event_name().unwrap_or_else(|| #root.to_string()); + let struct_start_event = XmlEvent::start_element(yaserde_label.as_ref())#namespaces_definition; + #attributes_inspector + writer.write(struct_start_event).map_err(|e| e.to_string())?; + } + + #inner_inspector + + if !#flatten && !skip { + let struct_end_event = XmlEvent::end_element(); + writer.write(struct_end_event).map_err(|e| e.to_string())?; + } + + Ok(()) + } + } + } +} diff --git a/yaserde_derive/src/ser/label.rs b/yaserde_derive/src/ser/label.rs new file mode 100644 index 0000000..640ab49 --- /dev/null +++ b/yaserde_derive/src/ser/label.rs @@ -0,0 +1,25 @@ + +use crate::attribute::YaSerdeAttribute; +use proc_macro2::Ident; + +pub fn build_label_name( + label: &Ident, + field_attrs: &YaSerdeAttribute, + default_namespace: &Option, +) -> String { + let prefix = if default_namespace == &field_attrs.prefix { + "".to_string() + } else { + field_attrs + .prefix + .clone() + .map_or("".to_string(), |prefix| prefix + ":") + }; + + let label = field_attrs + .rename + .clone() + .unwrap_or_else(|| label.to_string()); + + format!("{}{}", prefix, label) +} diff --git a/yaserde_derive/src/ser/mod.rs b/yaserde_derive/src/ser/mod.rs index dec8dfa..10255ca 100644 --- a/yaserde_derive/src/ser/mod.rs +++ b/yaserde_derive/src/ser/mod.rs @@ -1,6 +1,9 @@ pub mod element; pub mod expand_enum; pub mod expand_struct; +pub mod label; +pub mod implement_deserializer; +pub mod namespace; use crate::attribute::YaSerdeAttribute; use proc_macro2::TokenStream; diff --git a/yaserde_derive/src/ser/namespace.rs b/yaserde_derive/src/ser/namespace.rs new file mode 100644 index 0000000..6a7bf5a --- /dev/null +++ b/yaserde_derive/src/ser/namespace.rs @@ -0,0 +1,22 @@ +use crate::attribute::YaSerdeAttribute; +use proc_macro2::TokenStream; + +pub fn generate_namespaces_definition(attributes: &YaSerdeAttribute) -> TokenStream { + attributes + .namespaces + .iter() + .map(|(prefix, namespace)| { + if let Some(dn) = &attributes.default_namespace { + if dn == prefix { + return Some(quote!( + .default_ns(#namespace) + )); + } + } + Some(quote!( + .ns(#prefix, #namespace) + )) + }) + .filter_map(|x| x) + .collect() +}