use crate::common::{Field, YaSerdeAttribute, YaSerdeField}; use crate::ser::{implement_serializer::implement_serializer, label::build_label_name}; use proc_macro2::TokenStream; use syn::DataEnum; use syn::Fields; use syn::Ident; pub fn serialize( data_enum: &DataEnum, name: &Ident, root: &str, root_attributes: &YaSerdeAttribute, ) -> TokenStream { let inner_enum_inspector = inner_enum_inspector(data_enum, name, root_attributes); implement_serializer( 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 variant_attrs = YaSerdeAttribute::parse(&variant.attrs); let label = &variant.ident; let label_name = build_label_name(&label, &variant_attrs, &root_attributes.default_namespace); match variant.fields { Fields::Unit => Some(quote! { &#name::#label => { let data_event = XmlEvent::characters(#label_name); writer.write(data_event).map_err(|e| e.to_string())?; } }), Fields::Named(ref fields) => { let enum_fields: TokenStream = fields .named .iter() .map(|field| YaSerdeField::new(field.clone())) .filter(|field| !field.is_attribute()) .map(|field| { let field_label = field.label(); 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(root_attributes); match field.get_type() { Field::FieldString | Field::FieldBool | Field::FieldU8 | Field::FieldI8 | Field::FieldU16 | Field::FieldI16 | Field::FieldU32 | Field::FieldI32 | Field::FieldF32 | Field::FieldU64 | Field::FieldI64 | Field::FieldF64 => Some({ quote! { match self { &#name::#label{ref #field_label, ..} => { let struct_start_event = XmlEvent::start_element(#field_label_name); writer.write(struct_start_event).map_err(|e| e.to_string())?; let string_value = #field_label.to_string(); let data_event = XmlEvent::characters(&string_value); writer.write(data_event).map_err(|e| e.to_string())?; let struct_end_event = XmlEvent::end_element(); writer.write(struct_end_event).map_err(|e| e.to_string())?; }, _ => {}, } } }), Field::FieldStruct { .. } => Some(quote! { match self { &#name::#label{ref #field_label, ..} => { writer.set_start_event_name(Some(#field_label_name.to_string())); writer.set_skip_start_end(false); #field_label.serialize(writer)?; }, _ => {} } }), Field::FieldVec { .. } => Some(quote! { match self { &#name::#label{ref #field_label, ..} => { for item in #field_label { writer.set_start_event_name(Some(#field_label_name.to_string())); writer.set_skip_start_end(false); item.serialize(writer)?; } }, _ => {} } }), Field::FieldOption { .. } => None, } }) .filter_map(|x| x) .collect(); Some(quote! { &#name::#label{..} => { #enum_fields } }) } Fields::Unnamed(ref fields) => { let enum_fields: TokenStream = fields .unnamed .iter() .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); writer.write(struct_start_event).map_err(|e| e.to_string())?; #action let struct_end_event = XmlEvent::end_element(); writer.write(struct_end_event).map_err(|e| e.to_string())?; } }; let write_string_chars = quote! { let data_event = XmlEvent::characters(item); writer.write(data_event).map_err(|e| e.to_string())?; }; let write_simple_type = write_element("e! { let s = item.to_string(); let data_event = XmlEvent::characters(&s); writer.write(data_event).map_err(|e| e.to_string())?; }); let serialize = quote! { writer.set_start_event_name(None); writer.set_skip_start_end(true); item.serialize(writer)?; }; let write_sub_type = |data_type| { write_element(match data_type { Field::FieldString => &write_string_chars, _ => &serialize, }) }; let match_field = |write: &TokenStream| { quote! { match self { &#name::#label(ref item) => { #write }, _ => {}, } } }; match field.get_type() { Field::FieldOption { data_type } => { let write = write_sub_type(*data_type); Some(match_field("e! { if let Some(item) = item { #write } })) } Field::FieldVec { data_type } => { let write = write_sub_type(*data_type); Some(match_field("e! { for item in item { #write } })) } Field::FieldStruct { .. } => Some(write_element(&match_field(&serialize))), Field::FieldString => Some(match_field(&write_element(&write_string_chars))), _simple_type => Some(match_field(&write_simple_type)), } }) .filter_map(|x| x) .collect(); Some(quote! { &#name::#label{..} => { #enum_fields } }) } } }) .filter_map(|x| x) .collect() }