diff --git a/yaserde_derive/src/de/expand_struct.rs b/yaserde_derive/src/de/expand_struct.rs index 662ce85..428d0e9 100644 --- a/yaserde_derive/src/de/expand_struct.rs +++ b/yaserde_derive/src/de/expand_struct.rs @@ -2,7 +2,6 @@ use attribute::*; use de::build_default_value::build_default_value; use field_type::*; use proc_macro2::{Span, TokenStream}; -use quote::ToTokens; use std::collections::BTreeMap; use syn::spanned::Spanned; use syn::DataStruct; @@ -101,8 +100,6 @@ pub fn parse( .rename .unwrap_or_else(|| field.ident.as_ref().unwrap().to_string()); - let visitor_label = build_visitor_ident(&label_name, field.span(), None); - let struct_visitor = |struct_name: syn::Path| { let struct_id: String = struct_name .segments @@ -110,12 +107,12 @@ pub fn parse( .map(|s| s.ident.to_string()) .collect(); - let struct_ident = build_visitor_ident(&label_name, field.span(), Some(&struct_name)); + let visitor_label = build_visitor_ident(&label_name, field.span(), Some(&struct_name)); Some(quote! { #[allow(non_snake_case, non_camel_case_types)] - struct #struct_ident; - impl<'de> Visitor<'de> for #struct_ident { + struct #visitor_label; + impl<'de> Visitor<'de> for #visitor_label { type Value = #struct_name; fn visit_str(self, v: &str) -> Result { @@ -128,11 +125,21 @@ pub fn parse( }; let simple_type_visitor = |simple_type: FieldType| { - build_declare_visitor( - &get_simple_type_token(&simple_type), - &get_simple_type_visitor(&simple_type), - &visitor_label, - ) + let field_type = get_simple_type_token(&simple_type); + let visitor = get_simple_type_visitor(&simple_type); + let visitor_label = build_visitor_ident(&label_name, field.span(), None); + + Some(quote! { + #[allow(non_snake_case, non_camel_case_types)] + struct #visitor_label; + impl<'de> Visitor<'de> for #visitor_label { + type Value = #field_type; + + fn #visitor(self, v: &str) -> Result { + Ok(#field_type::from_str(v).unwrap()) + } + } + }) }; get_field_type(field).and_then(|f| match f { @@ -170,94 +177,40 @@ pub fn parse( .clone() .unwrap_or_else(|| label.as_ref().unwrap().to_string()); - get_field_type(field).and_then(|f| match f { - FieldType::FieldTypeStruct { struct_name } => Some(quote! { + let visit_struct = |struct_name: syn::Path, action: TokenStream| { + Some(quote! { #label_name => { reader.set_map_value(); - match #struct_name::deserialize(reader) { - Ok(parsed_item) => { - #value_label = parsed_item; - let _root = reader.next_event(); - }, - Err(msg) => { - return Err(msg); - }, - } + let value = #struct_name::deserialize(reader)?; + #value_label #action; + let _root = reader.next_event(); } - }), - FieldType::FieldTypeOption { data_type } => match *data_type { - FieldType::FieldTypeStruct { ref struct_name } => { - let struct_ident = Ident::new( - &format!("{}", struct_name.into_token_stream()), - field.span(), - ); - Some(quote! { - #label_name => { - reader.set_map_value(); - match #struct_ident::deserialize(reader) { - Ok(parsed_item) => { - #value_label = Some(parsed_item); - let _root = reader.next_event(); - }, - Err(msg) => { - return Err(msg); - }, - } - } - }) - } - FieldType::FieldTypeOption { .. } | FieldType::FieldTypeVec { .. } => unimplemented!(), - simple_type => build_call_visitor( - &get_simple_type_token(&simple_type), - &get_simple_type_visitor(&simple_type), - "e! {= Some(value)}, - &field_attrs, - label, - &namespaces, - field.span(), - ), - }, - FieldType::FieldTypeVec { data_type } => match *data_type { - FieldType::FieldTypeStruct { ref struct_name } => { - let struct_ident = Ident::new( - &format!("{}", struct_name.into_token_stream()), - field.span(), - ); - Some(quote! { - #label_name => { - reader.set_map_value(); - match #struct_ident::deserialize(reader) { - Ok(parsed_item) => { - #value_label.push(parsed_item); - let _root = reader.next_event(); - }, - Err(msg) => { - return Err(msg); - }, - } - } - }) - } - FieldType::FieldTypeOption { .. } | FieldType::FieldTypeVec { .. } => unimplemented!(), - simple_type => build_call_visitor( - &get_simple_type_token(&simple_type), - &get_simple_type_visitor(&simple_type), - "e! {.push(value)}, - &field_attrs, - label, - &namespaces, - field.span(), - ), - }, - simple_type => build_call_visitor( + }) + }; + + let visit_simple = |simple_type: FieldType, action: TokenStream| { + build_call_visitor( &get_simple_type_token(&simple_type), &get_simple_type_visitor(&simple_type), - "e! {= value}, + &action, &field_attrs, label, &namespaces, field.span(), - ), + ) + }; + + let visit_sub = |sub_type: Box, action: TokenStream| match *sub_type { + FieldType::FieldTypeOption { .. } | FieldType::FieldTypeVec { .. } => unimplemented!(), + FieldType::FieldTypeStruct { struct_name } => visit_struct(struct_name, action), + simple_type => visit_simple(simple_type, action), + }; + + get_field_type(field).and_then(|f| match f { + FieldType::FieldTypeStruct { struct_name } => visit_struct(struct_name, quote! {= value}), + FieldType::FieldTypeOption { data_type } => visit_sub(data_type, quote! {= Some(value)}), + FieldType::FieldTypeVec { data_type } => visit_sub(data_type, quote! {.push(value)}), + simple_type => visit_simple(simple_type, quote! {= value}), }) }) .filter_map(|x| x) @@ -307,54 +260,56 @@ pub fn parse( let visitor_label = build_visitor_ident(&label_name, field.span(), None); - get_field_type(field).and_then(|f| match f { - FieldType::FieldTypeString => Some(quote! { + let visit = |action: &TokenStream, visitor: &TokenStream, visitor_label: &Ident| { + Some(quote! { + for attr in attributes { + if attr.name.local_name == #label_name { + let visitor = #visitor_label{}; + let value = visitor.#visitor(&attr.value)?; + #label #action; + } + } + }) + }; + + let visit_string = || { + Some(quote! { for attr in attributes { if attr.name.local_name == #label_name { #label = attr.value.to_owned(); } } - }), - FieldType::FieldTypeOption { data_type } => match *data_type { - FieldType::FieldTypeOption { .. } | FieldType::FieldTypeVec { .. } => unimplemented!(), - FieldType::FieldTypeStruct { struct_name } => build_call_visitor_for_attribute( - label, - &label_name, - "e! {= Some(value) }, - "e! {visit_str}, - &build_visitor_ident(&label_name, field.span(), Some(&struct_name)), - ), - simple_type => { - let visitor = get_simple_type_visitor(&simple_type); + }) + }; - build_call_visitor_for_attribute( - label, - &label_name, - "e! {= Some(value)}, - &visitor, - &visitor_label, - ) - } - }, - FieldType::FieldTypeStruct { struct_name } => build_call_visitor_for_attribute( - label, - &label_name, - "e! {= value }, + let visit_struct = |struct_name: syn::Path, action: TokenStream| { + visit( + &action, "e! {visit_str}, &build_visitor_ident(&label_name, field.span(), Some(&struct_name)), - ), - FieldType::FieldTypeVec { .. } => None, - simple_type => { - let visitor = get_simple_type_visitor(&simple_type); + ) + }; - build_call_visitor_for_attribute( - label, - &label_name, - "e! {= value}, - &visitor, - &visitor_label, - ) - } + let visit_simple = |simple_type: FieldType, action: TokenStream| { + visit( + &action, + &get_simple_type_visitor(&simple_type), + &visitor_label, + ) + }; + + let visit_sub = |sub_type: Box, action: TokenStream| match *sub_type { + FieldType::FieldTypeOption { .. } | FieldType::FieldTypeVec { .. } => unimplemented!(), + FieldType::FieldTypeStruct { struct_name } => visit_struct(struct_name, action), + simple_type => visit_simple(simple_type, action), + }; + + get_field_type(field).and_then(|f| match f { + FieldType::FieldTypeString => visit_string(), + FieldType::FieldTypeOption { data_type } => visit_sub(data_type, quote! {= Some(value)}), + FieldType::FieldTypeVec { .. } => unimplemented!(), + FieldType::FieldTypeStruct { struct_name } => visit_struct(struct_name, quote! {= value}), + simple_type => visit_simple(simple_type, quote! {= value}), }) }) .filter_map(|x| x) @@ -367,21 +322,22 @@ pub fn parse( let label = &get_value_label(&field.ident); let field_attrs = YaSerdeAttribute::parse(&field.attrs); - get_field_type(field).and_then(|f| match f { - FieldType::FieldTypeString => { - build_set_text_to_value(&field_attrs, label, "e! {text_content.to_owned()}) + let set_text = |action: &TokenStream| { + if field_attrs.text { + Some(quote! {#label = #action;}) + } else { + None } + }; + + get_field_type(field).and_then(|f| match f { + FieldType::FieldTypeString => set_text("e! {text_content.to_owned()}), FieldType::FieldTypeStruct { .. } | FieldType::FieldTypeOption { .. } | FieldType::FieldTypeVec { .. } => None, simple_type => { let type_token = get_simple_type_token(&simple_type); - - build_set_text_to_value( - &field_attrs, - label, - "e! {#type_token::from_str(text_content).unwrap()}, - ) + set_text("e! {#type_token::from_str(text_content).unwrap()}) } }) }) @@ -499,24 +455,6 @@ pub fn parse( } } -fn build_declare_visitor( - field_type: &TokenStream, - visitor: &TokenStream, - visitor_label: &Ident, -) -> Option { - Some(quote! { - #[allow(non_snake_case, non_camel_case_types)] - struct #visitor_label; - impl<'de> Visitor<'de> for #visitor_label { - type Value = #field_type; - - fn #visitor(self, v: &str) -> Result { - Ok(#field_type::from_str(v).unwrap()) - } - } - }) -} - fn build_call_visitor( field_type: &TokenStream, visitor: &TokenStream, @@ -585,40 +523,6 @@ fn build_call_visitor( }) } -fn build_call_visitor_for_attribute( - label: &Option, - label_name: &str, - action: &TokenStream, - visitor: &TokenStream, - visitor_label: &Ident, -) -> Option { - Some(quote! { - for attr in attributes { - if attr.name.local_name == #label_name { - let visitor = #visitor_label{}; - match visitor.#visitor(&attr.value) { - Ok(value) => {#label #action;} - Err(msg) => {return Err(msg);} - } - } - } - }) -} - -fn build_set_text_to_value( - field_attrs: &YaSerdeAttribute, - label: &Option, - action: &TokenStream, -) -> Option { - if field_attrs.text { - Some(quote! { - #label = #action; - }) - } else { - None - } -} - fn get_value_label(ident: &Option) -> Option { ident .clone() diff --git a/yaserde_derive/src/ser/expand_struct.rs b/yaserde_derive/src/ser/expand_struct.rs index 5ab2f59..88d29f5 100644 --- a/yaserde_derive/src/ser/expand_struct.rs +++ b/yaserde_derive/src/ser/expand_struct.rs @@ -44,32 +44,18 @@ pub fn serialize( 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, &*{ - use std::mem; - unsafe { - let content = format!("{}", self.#label); - let ret : &'static str = mem::transmute(&content as &str); - mem::forget(content); - ret - } - }) + struct_start_event.attr(#label_name, &content) } else { struct_start_event }; }) } else { Some(quote! { - let struct_start_event = struct_start_event.attr(#label_name, &*{ - use std::mem; - unsafe { - let content = format!("{}", self.#label); - let ret : &'static str = mem::transmute(&content as &str); - mem::forget(content); - ret - } - }); + let content = self.#label.to_string(); + let struct_start_event = struct_start_event.attr(#label_name, &content); }) } } @@ -114,18 +100,11 @@ pub fn serialize( 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, &*{ - use std::mem; - unsafe { - let content = format!("{}", value); - let ret : &'static str = mem::transmute(&content as &str); - mem::forget(content); - ret - } - }) + struct_start_event.attr(#label_name, &content) } else { struct_start_event } @@ -135,17 +114,10 @@ pub fn serialize( }) } 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, &*{ - use std::mem; - unsafe { - let content = format!("{}", value); - let ret : &'static str = mem::transmute(&content as &str); - mem::forget(content); - ret - } - }) + struct_start_event.attr(#label_name, &content) } else { struct_start_event }; @@ -180,21 +152,12 @@ pub fn serialize( if let Some(ref d) = field_attrs.default { let default_function = Ident::new(&d, field.span()); 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 { if *value != #default_function() { - struct_start_event.attr(#label_name, &*{ - use std::mem; - match yaserde::ser::to_string_content(value) { - Ok(value) => { - unsafe { - let ret : &'static str = mem::transmute(&value as &str); - mem::forget(value); - ret - } - }, - Err(msg) => return Err("Unable to serialize content".to_owned()), - } - }) + struct_start_event.attr(#label_name, &content) } else { struct_start_event } @@ -204,20 +167,11 @@ pub fn serialize( }) } 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, &*{ - use std::mem; - match yaserde::ser::to_string_content(value) { - Ok(value) => { - unsafe { - let ret : &'static str = mem::transmute(&value as &str); - mem::forget(value); - ret - } - }, - Err(msg) => return Err("Unable to serialize content".to_owned()), - } - }) + struct_start_event.attr(#label_name, &content) } else { struct_start_event }; @@ -230,40 +184,18 @@ pub fn serialize( 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, &*{ - use std::mem; - match yaserde::ser::to_string_content(&self.#label) { - Ok(value) => { - unsafe { - let ret : &'static str = mem::transmute(&value as &str); - mem::forget(value); - ret - } - }, - Err(msg) => return Err("Unable to serialize content".to_owned()), - } - }) + struct_start_event.attr(#label_name, &content) } else { struct_start_event }; }) } else { Some(quote! { - let struct_start_event = struct_start_event.attr(#label_name, &*{ - use std::mem; - match yaserde::ser::to_string_content(&self.#label) { - Ok(value) => { - unsafe { - let ret : &'static str = mem::transmute(&value as &str); - mem::forget(value); - ret - } - }, - Err(msg) => return Err("Unable to serialize content".to_owned()), - } - }); + let content = yaserde::ser::to_string_content(&self.#label)?; + let struct_start_event = struct_start_event.attr(#label_name, &content); }) } }