continue to refactor code using common Field structure

This commit is contained in:
Marc-Antoine Arnaud 2020-04-22 18:18:11 +02:00
parent f69d5e75b3
commit 0872461c41
9 changed files with 280 additions and 320 deletions

View File

@ -37,6 +37,7 @@ fn basic_option_types() {
test_for_type!(Option::<f64>, Some(-12.5 as f64), Some("-12.5")); test_for_type!(Option::<f64>, Some(-12.5 as f64), Some("-12.5"));
test_for_type!(Option::<f64>, None, None); test_for_type!(Option::<f64>, None, None);
// TODO
// test_for_type!(Option::<Vec::<u8>>, None, None); // test_for_type!(Option::<Vec::<u8>>, None, None);
// test_for_type!(Option::<Vec::<u8>>, Some(vec![0]), Some("0")); // test_for_type!(Option::<Vec::<u8>>, Some(vec![0]), Some("0"));
// test_for_type!(Option::<Vec::<String>>, None, None); // test_for_type!(Option::<Vec::<String>>, None, None);

View File

@ -8,9 +8,18 @@ use yaserde::YaSerialize;
#[test] #[test]
fn skip_serializing_if_for_struct() { fn skip_serializing_if_for_struct() {
fn default_string_function() -> String {
"mask_default".to_string()
}
#[derive(YaSerialize, PartialEq, Debug)] #[derive(YaSerialize, PartialEq, Debug)]
#[yaserde(root = "base")] #[yaserde(root = "base")]
pub struct XmlStruct { 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")] #[yaserde(skip_serializing_if = "check_string_function")]
string_item: String, string_item: String,
#[yaserde(skip_serializing_if = "check_bool_function")] #[yaserde(skip_serializing_if = "check_bool_function")]
@ -40,6 +49,7 @@ fn skip_serializing_if_for_struct() {
} }
let model = XmlStruct { let model = XmlStruct {
string_with_default_item: "mask_default".to_string(),
string_item: "something".to_string(), string_item: "something".to_string(),
bool_item: true, bool_item: true,
f32_item: 0.0, f32_item: 0.0,

View File

@ -1,10 +1,10 @@
use crate::common::attribute::YaSerdeAttribute; use crate::common::attribute::YaSerdeAttribute;
use proc_macro2::{Ident, TokenStream};
use proc_macro2::Span; use proc_macro2::Span;
use proc_macro2::{Ident, TokenStream};
use std::fmt; use std::fmt;
use syn; use syn;
use syn::Type::Path;
use syn::spanned::Spanned; use syn::spanned::Spanned;
use syn::Type::Path;
#[derive(Debug)] #[derive(Debug)]
pub struct YaSerdeField { pub struct YaSerdeField {
@ -16,7 +16,7 @@ impl YaSerdeField {
pub fn new(syn_field: syn::Field) -> Self { pub fn new(syn_field: syn::Field) -> Self {
let attributes = YaSerdeAttribute::parse(&syn_field.attrs); let attributes = YaSerdeAttribute::parse(&syn_field.attrs);
YaSerdeField{ YaSerdeField {
syn_field, syn_field,
attributes, attributes,
} }
@ -30,29 +30,70 @@ impl YaSerdeField {
self.attributes.text 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<Ident> { pub fn label(&self) -> Option<Ident> {
self.syn_field.ident.clone() self.syn_field.ident.clone()
} }
pub fn get_value_label(&self) -> Option<syn::Ident> {
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 { pub fn renamed_label(&self, root_attributes: &YaSerdeAttribute) -> String {
let prefix = if root_attributes.default_namespace == self.attributes.prefix { let prefix = if root_attributes.default_namespace == self.attributes.prefix {
"".to_string() "".to_string()
} else { } else {
self.attributes self
.attributes
.prefix .prefix
.clone() .clone()
.map_or("".to_string(), |prefix| prefix + ":") .map_or("".to_string(), |prefix| prefix + ":")
}; };
let label = let label = self.renamed_label_without_namespace();
self.attributes
.rename
.clone()
.unwrap_or_else(|| self.label().as_ref().unwrap().to_string());
format!("{}{}", prefix, label) 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 { pub fn get_type(&self) -> Field {
Field::from(&self.syn_field) Field::from(&self.syn_field)
} }
@ -62,35 +103,64 @@ impl YaSerdeField {
} }
pub fn get_default_function(&self) -> Option<Ident> { pub fn get_default_function(&self) -> Option<Ident> {
self.attributes.default.as_ref().map(|default|{ self
Ident::new(&default, self.get_span()) .attributes
}) .default
.as_ref()
.map(|default| Ident::new(&default, self.get_span()))
} }
pub fn get_skip_serializing_if_function(&self) -> Option<Ident> { pub fn get_skip_serializing_if_function(&self) -> Option<Ident> {
self.attributes.skip_serializing_if.as_ref().map(|skip_serializing_if|{ self
Ident::new(&skip_serializing_if, self.get_span()) .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<TokenStream>,
setter: TokenStream,
) -> TokenStream {
let label = self.label(); let label = self.label();
if let Some(ref default_function) = self.get_default_function() {
quote! { let yaserde_inner_definition = builder
let yaserde_inner = #builder; .map(|builder| quote!(let yaserde_inner = #builder;))
let struct_start_event = .unwrap_or(quote!());
if self.#label != #default_function() {
#setter self
} else { .get_default_function()
struct_start_event .map(|default_function| {
}; quote! {
} #yaserde_inner_definition
} else { let struct_start_event =
quote! { if self.#label != #default_function() {
let yaserde_inner = #builder; #setter
} else {
struct_start_event
};
}
})
.unwrap_or(quote! {
#yaserde_inner_definition
let struct_start_event = #setter; let struct_start_event = #setter;
} })
}
} }
} }
@ -140,7 +210,6 @@ impl Field {
let label = attributes let label = attributes
.rename .rename
.clone()
.unwrap_or_else(|| token_field.ident.as_ref().unwrap().to_string()); .unwrap_or_else(|| token_field.ident.as_ref().unwrap().to_string());
format!("{}{}", prefix, label) format!("{}{}", prefix, label)

View File

@ -1,28 +1,24 @@
use proc_macro2::{Span, TokenStream}; use crate::common::YaSerdeField;
use syn::Ident; use proc_macro2::TokenStream;
pub fn build_default_value( pub fn build_default_value(
label: &Option<Ident>, field: &YaSerdeField,
field_type: &TokenStream, field_type: Option<TokenStream>,
value: &TokenStream, value: TokenStream,
default: &Option<String>,
) -> Option<TokenStream> { ) -> Option<TokenStream> {
let value = default let label = field.get_value_label();
.as_ref()
.map(|d| {
let default_function = Ident::new(
&d,
label
.as_ref()
.map_or(Span::call_site(), |ident| ident.span()),
);
quote!(#default_function()) let default_value = field
}) .get_default_function()
.map(|default_function| quote!(#default_function()))
.unwrap_or_else(|| quote!(#value)); .unwrap_or_else(|| quote!(#value));
let field_type = field_type
.map(|field_type| quote!(: #field_type))
.unwrap_or(quote!());
Some(quote! { Some(quote! {
#[allow(unused_mut)] #[allow(unused_mut)]
let mut #label : #field_type = #value; let mut #label #field_type = #default_value;
}) })
} }

View File

@ -1,11 +1,6 @@
use crate::common::{Field, YaSerdeAttribute}; use crate::common::{Field, YaSerdeAttribute, YaSerdeField};
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use syn::{ use syn::{DataEnum, Fields, Ident};
spanned::Spanned,
DataEnum,
Fields,
Ident,
};
pub fn parse( pub fn parse(
data_enum: &DataEnum, data_enum: &DataEnum,
@ -142,9 +137,10 @@ fn build_unnamed_field_visitors(fields: &syn::FieldsUnnamed) -> TokenStream {
fields fields
.unnamed .unnamed
.iter() .iter()
.map(|field| YaSerdeField::new(field.clone()))
.enumerate() .enumerate()
.map(|(idx, field)| { .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 = let make_visitor =
|visitor: &TokenStream, field_type: &TokenStream, fn_body: &TokenStream| { |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 } => { Field::FieldStruct { struct_name } => {
let struct_id: String = struct_name let struct_id: String = struct_name
.segments .segments
@ -208,9 +204,10 @@ fn build_unnamed_visitor_calls(
fields fields
.unnamed .unnamed
.iter() .iter()
.map(|field| YaSerdeField::new(field.clone()))
.enumerate() .enumerate()
.map(|(idx, field)| { .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 call_simple_type_visitor = |simple_type: Field, action| {
let visitor = simple_type.get_simple_type_visitor(); 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::FieldStruct { struct_name } => call_struct_visitor(struct_name, set_val),
Field::FieldOption { data_type } => match *data_type { Field::FieldOption { data_type } => match *data_type {
Field::FieldStruct { struct_name } => call_struct_visitor(struct_name, set_opt), Field::FieldStruct { struct_name } => call_struct_visitor(struct_name, set_opt),

View File

@ -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 crate::de::build_default_value::build_default_value;
use proc_macro2::{Span, TokenStream}; use proc_macro2::{Span, TokenStream};
use std::collections::BTreeMap; use syn::{DataStruct, Ident};
use syn::{
spanned::Spanned,
DataStruct,
Ident,
};
pub fn parse( pub fn parse(
data_struct: &DataStruct, data_struct: &DataStruct,
@ -17,9 +12,9 @@ pub fn parse(
let namespaces_matches: TokenStream = root_attributes let namespaces_matches: TokenStream = root_attributes
.namespaces .namespaces
.iter() .iter()
.map(|(p, ns)| { .map(|(prefix, namespace)| {
if root_attributes.prefix.as_ref() == Some(p) { if root_attributes.prefix.as_ref() == Some(prefix) {
Some(quote!(#ns => {})) Some(quote!(#namespace => {}))
} else { } else {
None None
} }
@ -30,63 +25,32 @@ pub fn parse(
let variables: TokenStream = data_struct let variables: TokenStream = data_struct
.fields .fields
.iter() .iter()
.map(|field| { .map(|field| YaSerdeField::new(field.clone()))
let label = &get_value_label(&field.ident); .map(|field| match field.get_type() {
let field_attrs = YaSerdeAttribute::parse(&field.attrs); Field::FieldStruct { struct_name } => build_default_value(
&field,
match Field::from(field) { Some(quote!(#struct_name)),
Field::FieldStruct { struct_name } => build_default_value( quote!(#struct_name::default()),
label, ),
&quote! {#struct_name}, Field::FieldOption { .. } => build_default_value(&field, None, quote!(None)),
&quote! {#struct_name::default()}, Field::FieldVec { data_type } => match *data_type {
&field_attrs.default, Field::FieldStruct { ref struct_name } => {
), build_default_value(&field, Some(quote!(Vec<#struct_name>)), quote!(vec![]))
Field::FieldOption { .. } => { }
if let Some(d) = &field_attrs.default { Field::FieldOption { .. } | Field::FieldVec { .. } => {
let default_function = Ident::new(&d, field.span()); unimplemented!();
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;
})
}
} }
Field::FieldVec { data_type } => match *data_type {
Field::FieldStruct { ref struct_name } => build_default_value(
label,
&quote! {Vec<#struct_name>},
&quote! {vec![]},
&field_attrs.default,
),
Field::FieldOption { .. } | Field::FieldVec { .. } => {
unimplemented!();
}
simple_type => {
let type_token: TokenStream = simple_type.into();
build_default_value(
label,
&quote! {Vec<#type_token>},
&quote! {vec![]},
&field_attrs.default,
)
}
},
simple_type => { simple_type => {
let type_token: TokenStream = simple_type.into(); let type_token: TokenStream = simple_type.into();
build_default_value( build_default_value(&field, Some(quote!(Vec<#type_token>)), quote!(vec![]))
label,
&type_token,
&quote! {#type_token::default()},
&field_attrs.default,
)
} }
},
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) .filter_map(|x| x)
@ -95,12 +59,8 @@ pub fn parse(
let field_visitors: TokenStream = data_struct let field_visitors: TokenStream = data_struct
.fields .fields
.iter() .iter()
.map(|field| YaSerdeField::new(field.clone()))
.map(|field| { .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_visitor = |struct_name: syn::Path| {
let struct_id: String = struct_name let struct_id: String = struct_name
.segments .segments
@ -108,7 +68,7 @@ pub fn parse(
.map(|s| s.ident.to_string()) .map(|s| s.ident.to_string())
.collect(); .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! { Some(quote! {
#[allow(non_snake_case, non_camel_case_types)] #[allow(non_snake_case, non_camel_case_types)]
@ -127,7 +87,7 @@ pub fn parse(
let simple_type_visitor = |simple_type: Field| { let simple_type_visitor = |simple_type: Field| {
let visitor = simple_type.get_simple_type_visitor(); 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(); let field_type: TokenStream = simple_type.into();
Some(quote! { 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::FieldStruct { struct_name } => struct_visitor(struct_name),
Field::FieldOption { data_type } => match *data_type { Field::FieldOption { data_type } => match *data_type {
Field::FieldStruct { struct_name } => struct_visitor(struct_name), Field::FieldStruct { struct_name } => struct_visitor(struct_name),
@ -164,19 +124,11 @@ pub fn parse(
let call_visitors: TokenStream = data_struct let call_visitors: TokenStream = data_struct
.fields .fields
.iter() .iter()
.map(|field| YaSerdeField::new(field.clone()))
.filter(|field| !field.is_attribute() || !field.is_flatten())
.map(|field| { .map(|field| {
let field_attrs = YaSerdeAttribute::parse(&field.attrs); let value_label = field.get_value_label();
let label = &field.ident; let label_name = field.renamed_label_without_namespace();
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 visit_struct = |struct_name: syn::Path, action: TokenStream| { let visit_struct = |struct_name: syn::Path, action: TokenStream| {
Some(quote! { Some(quote! {
@ -201,10 +153,8 @@ pub fn parse(
&field_type, &field_type,
&field_visitor, &field_visitor,
&action, &action,
&field_attrs, &field,
label, &root_attributes,
&root_attributes.namespaces,
field.span(),
) )
}; };
@ -214,7 +164,7 @@ pub fn parse(
simple_type => visit_simple(simple_type, action), 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::FieldStruct { struct_name } => visit_struct(struct_name, quote! {= value}),
Field::FieldOption { data_type } => visit_sub(data_type, quote! {= Some(value)}), Field::FieldOption { data_type } => visit_sub(data_type, quote! {= Some(value)}),
Field::FieldVec { data_type } => visit_sub(data_type, quote! {.push(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 let call_flatten_visitors: TokenStream = data_struct
.fields .fields
.iter() .iter()
.map(|field| YaSerdeField::new(field.clone()))
.filter(|field| !field.is_attribute() && field.is_flatten())
.map(|field| { .map(|field| {
let field_attrs = YaSerdeAttribute::parse(&field.attrs); let value_label = field.get_value_label();
let value_label = &get_value_label(&field.ident);
if field_attrs.attribute || !field_attrs.flatten { match field.get_type() {
return None;
}
match Field::from(field) {
Field::FieldStruct { .. } => Some(quote! { Field::FieldStruct { .. } => Some(quote! {
#value_label = yaserde::de::from_str(&unused_xml_elements)?; #value_label = yaserde::de::from_str(&unused_xml_elements)?;
}), }),
@ -243,9 +190,9 @@ pub fn parse(
Field::FieldStruct { .. } => Some(quote! { Field::FieldStruct { .. } => Some(quote! {
#value_label = yaserde::de::from_str(&unused_xml_elements).ok(); #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) .filter_map(|x| x)
@ -254,19 +201,12 @@ pub fn parse(
let attributes_loading: TokenStream = data_struct let attributes_loading: TokenStream = data_struct
.fields .fields
.iter() .iter()
.map(|field| YaSerdeField::new(field.clone()))
.filter(|field| field.is_attribute())
.map(|field| { .map(|field| {
let field_attrs = YaSerdeAttribute::parse(&field.attrs); let label = field.get_value_label();
if !field_attrs.attribute { let label_name = field.renamed_label_without_namespace();
return None; let visitor_label = build_visitor_ident(&label_name, field.get_span(), 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 visit = |action: &TokenStream, visitor: &TokenStream, visitor_label: &Ident| { let visit = |action: &TokenStream, visitor: &TokenStream, visitor_label: &Ident| {
Some(quote! { Some(quote! {
@ -294,7 +234,7 @@ pub fn parse(
visit( visit(
&action, &action,
&quote! {visit_str}, &quote! {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), simple_type => visit_simple(simple_type, action),
}; };
match Field::from(field) { match field.get_type() {
Field::FieldString => visit_string(), Field::FieldString => visit_string(),
Field::FieldOption { data_type } => visit_sub(data_type, quote! {= Some(value)}), Field::FieldOption { data_type } => visit_sub(data_type, quote! {= Some(value)}),
Field::FieldVec { .. } => unimplemented!(), Field::FieldVec { .. } => unimplemented!(),
@ -326,19 +266,19 @@ pub fn parse(
let set_text: TokenStream = data_struct let set_text: TokenStream = data_struct
.fields .fields
.iter() .iter()
.map(|field| YaSerdeField::new(field.clone()))
.map(|field| { .map(|field| {
let label = &get_value_label(&field.ident); let label = field.get_value_label();
let field_attrs = YaSerdeAttribute::parse(&field.attrs);
let set_text = |action: &TokenStream| { let set_text = |action: &TokenStream| {
if field_attrs.text { if field.is_text_content() {
Some(quote! {#label = #action;}) Some(quote! {#label = #action;})
} else { } else {
None None
} }
}; };
match Field::from(field) { match field.get_type() {
Field::FieldString => set_text(&quote! {text_content.to_owned()}), Field::FieldString => set_text(&quote! {text_content.to_owned()}),
Field::FieldStruct { .. } | Field::FieldOption { .. } | Field::FieldVec { .. } => None, Field::FieldStruct { .. } | Field::FieldOption { .. } | Field::FieldVec { .. } => None,
simple_type => { simple_type => {
@ -353,9 +293,10 @@ pub fn parse(
let struct_builder: TokenStream = data_struct let struct_builder: TokenStream = data_struct
.fields .fields
.iter() .iter()
.map(|field| YaSerdeField::new(field.clone()))
.map(|field| { .map(|field| {
let label = &field.ident; let label = &field.label();
let value_label = &get_value_label(&field.ident); let value_label = field.get_value_label();
quote! { #label: #value_label, } quote! { #label: #value_label, }
}) })
@ -471,33 +412,14 @@ fn build_call_visitor(
field_type: &TokenStream, field_type: &TokenStream,
visitor: &TokenStream, visitor: &TokenStream,
action: &TokenStream, action: &TokenStream,
field_attrs: &YaSerdeAttribute, field: &YaSerdeField,
label: &Option<Ident>, root_attributes: &YaSerdeAttribute,
namespaces: &BTreeMap<String, String>,
span: Span,
) -> Option<TokenStream> { ) -> Option<TokenStream> {
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 namespaces_matches = field.get_namespace_matching(root_attributes);
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();
Some(quote! { Some(quote! {
#label_name => { #label_name => {
@ -530,12 +452,6 @@ fn build_call_visitor(
}) })
} }
fn get_value_label(ident: &Option<syn::Ident>) -> Option<syn::Ident> {
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 { fn build_visitor_ident(label: &str, span: Span, struct_name: Option<&syn::Path>) -> Ident {
let struct_id = struct_name.map_or_else( let struct_id = struct_name.map_or_else(
|| "".to_string(), || "".to_string(),

View File

@ -1,5 +1,5 @@
use crate::common::YaSerdeAttribute; use crate::common::YaSerdeField;
use proc_macro2::{Ident, Span, TokenStream}; use proc_macro2::{Ident, TokenStream};
pub fn enclose_formatted_characters(label: &Ident, label_name: String) -> TokenStream { pub fn enclose_formatted_characters(label: &Ident, label_name: String) -> TokenStream {
enclose_xml_event(label_name, quote!(format!("{}", &self.#label))) enclose_xml_event(label_name, quote!(format!("{}", &self.#label)))
@ -13,7 +13,7 @@ pub fn enclose_characters(label: &Option<Ident>, label_name: String) -> TokenStr
enclose_xml_event(label_name, quote!(format!("{}", self.#label))) 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! { quote! {
let start_event = XmlEvent::start_element(#label_name); let start_event = XmlEvent::start_element(#label_name);
writer.write(start_event).map_err(|e| e.to_string())?; writer.write(start_event).map_err(|e| e.to_string())?;
@ -41,34 +41,23 @@ pub fn serialize_element(
}) })
} }
pub fn condition_generator(label: &Option<Ident>, attributes: &YaSerdeAttribute) -> TokenStream { pub fn condition_generator(label: &Option<Ident>, field: &YaSerdeField) -> TokenStream {
let mut conditions = None; let default_condition = field
.get_default_function()
.map(|default_function| quote!(self.#label != #default_function()));
if let Some(ref d) = attributes.default { field
let default_function = Ident::new( .get_skip_serializing_if_function()
&d, .map(|skip_if_function| {
label if let Some(prev_conditions) = &default_condition {
.as_ref() quote!(if !self.#skip_if_function(&self.#label) && #prev_conditions)
.map_or(Span::call_site(), |ident| ident.span()), } else {
); quote!(if !self.#skip_if_function(&self.#label))
}
conditions = Some(quote!(self.#label != #default_function())) })
} .unwrap_or_else(|| {
default_condition
if let Some(ref s) = attributes.skip_serializing_if { .map(|condition| quote!(if #condition))
let skip_if_function = Ident::new( .unwrap_or(quote!())
&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!())
} }

View File

@ -52,7 +52,6 @@ fn inner_enum_inspector(
.map(|field| YaSerdeField::new(field.clone())) .map(|field| YaSerdeField::new(field.clone()))
.filter(|field| !field.is_attribute()) .filter(|field| !field.is_attribute())
.map(|field| { .map(|field| {
let field_label = field.label(); let field_label = field.label();
if field.is_text_content() { if field.is_text_content() {
@ -132,11 +131,9 @@ fn inner_enum_inspector(
let enum_fields: TokenStream = fields let enum_fields: TokenStream = fields
.unnamed .unnamed
.iter() .iter()
.map(|token_field| { .map(|field| YaSerdeField::new(field.clone()))
if Field::is_attribute(token_field) { .filter(|field| !field.is_attribute())
return None; .map(|field| {
}
let write_element = |action: &TokenStream| { let write_element = |action: &TokenStream| {
quote! { quote! {
let struct_start_event = XmlEvent::start_element(#label_name); 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 } => { Field::FieldOption { data_type } => {
let write = write_sub_type(*data_type); let write = write_sub_type(*data_type);

View File

@ -2,7 +2,6 @@ use crate::common::{Field, YaSerdeAttribute, YaSerdeField};
use crate::ser::{element::*, implement_deserializer::implement_deserializer}; use crate::ser::{element::*, implement_deserializer::implement_deserializer};
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use syn::spanned::Spanned;
use syn::DataStruct; use syn::DataStruct;
use syn::Ident; use syn::Ident;
@ -33,27 +32,23 @@ pub fn serialize(
| Field::FieldI64 | Field::FieldI64
| Field::FieldU64 | Field::FieldU64
| Field::FieldF32 | Field::FieldF32
| Field::FieldF64 => { | Field::FieldF64 => Some(field.ser_wrap_default_attribute(
Some(field.ser_wrap_default_attribute( Some(quote!(self.#label.to_string())),
quote!(self.#label.to_string()), quote!({
quote!({ struct_start_event.attr(#label_name, &yaserde_inner)
struct_start_event.attr(#label_name, &yaserde_inner) }),
}) )),
))
}
Field::FieldOption { data_type } => match *data_type { Field::FieldOption { data_type } => match *data_type {
Field::FieldString => { Field::FieldString => Some(field.ser_wrap_default_attribute(
Some(field.ser_wrap_default_attribute( None,
quote!({}), quote!({
quote!({ if let Some(ref value) = self.#label {
if let Some(ref value) = self.#label { struct_start_event.attr(#label_name, value)
struct_start_event.attr(#label_name, value) } else {
} else { struct_start_event
struct_start_event }
} }),
}) )),
))
}
Field::FieldBool Field::FieldBool
| Field::FieldI8 | Field::FieldI8
| Field::FieldU8 | Field::FieldU8
@ -64,57 +59,51 @@ pub fn serialize(
| Field::FieldI64 | Field::FieldI64
| Field::FieldU64 | Field::FieldU64
| Field::FieldF32 | Field::FieldF32
| Field::FieldF64 => { | Field::FieldF64 => Some(field.ser_wrap_default_attribute(
Some(field.ser_wrap_default_attribute( Some(quote!(self.#label.map_or_else(|| String::new(), |v| v.to_string()))),
quote!(self.#label.map_or_else(|| String::new(), |v| v.to_string())), quote!({
quote!({ if let Some(ref value) = self.#label {
if let Some(ref value) = self.#label { struct_start_event.attr(#label_name, &yaserde_inner)
struct_start_event.attr(#label_name, &yaserde_inner) } else {
} else { struct_start_event
struct_start_event }
} }),
}) )),
))
}
Field::FieldVec { .. } => { Field::FieldVec { .. } => {
let item_ident = Ident::new("yaserde_item", field.get_span()); let item_ident = Ident::new("yaserde_item", field.get_span());
let inner = enclose_formatted_characters(&item_ident, label_name); let inner = enclose_formatted_characters(&item_ident, label_name);
Some(field.ser_wrap_default_attribute( Some(field.ser_wrap_default_attribute(
quote!({}), None,
quote!({ quote!({
if let Some(ref yaserde_list) = self.#label { if let Some(ref yaserde_list) = self.#label {
for yaserde_item in yaserde_list.iter() { for yaserde_item in yaserde_list.iter() {
#inner #inner
} }
} }
}) }),
)) ))
} }
Field::FieldStruct { .. } => { Field::FieldStruct { .. } => Some(field.ser_wrap_default_attribute(
Some(field.ser_wrap_default_attribute( Some(quote!(self.#label
quote!(self.#label
.as_ref() .as_ref()
.map_or_else(|| Ok(String::new()), |v| yaserde::ser::to_string_content(v))?), .map_or_else(|| Ok(String::new()), |v| yaserde::ser::to_string_content(v))?)),
quote!({ quote!({
if let Some(ref yaserde_struct) = self.#label { if let Some(ref yaserde_struct) = self.#label {
struct_start_event.attr(#label_name, &yaserde_inner) struct_start_event.attr(#label_name, &yaserde_inner)
} else { } else {
struct_start_event struct_start_event
} }
}) }),
)) )),
}
Field::FieldOption { .. } => unimplemented!(), Field::FieldOption { .. } => unimplemented!(),
}, },
Field::FieldStruct { .. } => { Field::FieldStruct { .. } => Some(field.ser_wrap_default_attribute(
Some(field.ser_wrap_default_attribute( Some(quote!(yaserde::ser::to_string_content(&self.#label)?)),
quote!(yaserde::ser::to_string_content(&self.#label)?), quote!({
quote!({ struct_start_event.attr(#label_name, &yaserde_inner)
struct_start_event.attr(#label_name, &yaserde_inner) }),
}) )),
))
}
Field::FieldVec { .. } => None, Field::FieldVec { .. } => None,
} }
}) })
@ -124,25 +113,21 @@ pub fn serialize(
let struct_inspector: TokenStream = data_struct let struct_inspector: TokenStream = data_struct
.fields .fields
.iter() .iter()
.map(|field| YaSerdeField::new(field.clone()))
.filter(|field| !field.is_attribute())
.map(|field| { .map(|field| {
let field_attrs = YaSerdeAttribute::parse(&field.attrs); let label = field.label();
if Field::is_attribute(field) { if field.is_text_content() {
return None;
}
let label = Field::label(field);
if Field::is_text_content(field) {
return Some(quote!( return Some(quote!(
let data_event = XmlEvent::characters(&self.#label); let data_event = XmlEvent::characters(&self.#label);
writer.write(data_event).map_err(|e| e.to_string())?; 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.get_type() {
match Field::from(field) {
Field::FieldString Field::FieldString
| Field::FieldBool | Field::FieldBool
| Field::FieldI8 | Field::FieldI8
@ -169,7 +154,7 @@ pub fn serialize(
| Field::FieldU64 | Field::FieldU64
| Field::FieldF32 | Field::FieldF32
| Field::FieldF64 => { | 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); let inner = enclose_formatted_characters_for_value(&item_ident, label_name);
Some(quote! { Some(quote! {
@ -181,7 +166,7 @@ pub fn serialize(
}) })
} }
Field::FieldVec { .. } => { 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); let inner = enclose_formatted_characters_for_value(&item_ident, label_name);
Some(quote! { Some(quote! {
@ -194,7 +179,7 @@ pub fn serialize(
} }
}) })
} }
Field::FieldStruct { .. } => Some(if field_attrs.flatten { Field::FieldStruct { .. } => Some(if field.is_flatten() {
quote! { quote! {
if let Some(ref item) = &self.#label { if let Some(ref item) = &self.#label {
writer.set_start_event_name(None); writer.set_start_event_name(None);
@ -214,7 +199,7 @@ pub fn serialize(
_ => unimplemented!(), _ => unimplemented!(),
}, },
Field::FieldStruct { .. } => { Field::FieldStruct { .. } => {
let (start_event, skip_start) = if field_attrs.flatten { let (start_event, skip_start) = if field.is_flatten() {
(quote!(None), true) (quote!(None), true)
} else { } else {
(quote!(Some(#label_name.to_string())), false) (quote!(Some(#label_name.to_string())), false)
@ -228,7 +213,7 @@ pub fn serialize(
} }
Field::FieldVec { data_type } => match *data_type { Field::FieldVec { data_type } => match *data_type {
Field::FieldString => { 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); let inner = enclose_formatted_characters_for_value(&item_ident, label_name);
Some(quote! { Some(quote! {
@ -248,7 +233,7 @@ pub fn serialize(
| Field::FieldU64 | Field::FieldU64
| Field::FieldF32 | Field::FieldF32
| Field::FieldF64 => { | 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); let inner = enclose_formatted_characters_for_value(&item_ident, label_name);
Some(quote! { Some(quote! {