diff --git a/yaserde/tests/ser_flatten.rs b/yaserde/tests/ser_flatten.rs new file mode 100644 index 0000000..850251a --- /dev/null +++ b/yaserde/tests/ser_flatten.rs @@ -0,0 +1,68 @@ +#[macro_use] +extern crate yaserde_derive; + +use std::io::Write; +use yaserde::ser::to_string; +use yaserde::YaSerialize; + +macro_rules! convert_and_validate { + ($model: expr, $content: expr) => { + let data: Result = to_string(&$model); + assert_eq!( + data, + Ok( + String::from($content) + .split("\n") + .map(|s| s.trim()) + .collect::() + ) + ); + }; +} + +#[test] +fn ser_root_flatten_struct() { + + #[derive(YaSerialize, PartialEq, Debug)] + #[yaserde(flatten)] + pub struct Content { + binary_data: String, + string_data: String, + } + + let model = Content{ + binary_data: "binary".to_string(), + string_data: "string".to_string(), + }; + let content = r#"binarystring"#; + convert_and_validate!(model, content); +} + +#[test] +fn ser_root_flatten_enum() { + #[derive(YaSerialize, PartialEq, Debug)] + #[yaserde(flatten)] + pub enum Content { + Binary(Binary), + Data(Data), + } + + #[derive(YaSerialize, PartialEq, Debug)] + pub struct Binary { + binary_data: String, + } + + #[derive(YaSerialize, PartialEq, Debug)] + pub struct Data { + string_data: String, + } + + let model = Content::Binary(Binary{binary_data: "binary".to_string()}); + let content = r#"binary"#; + convert_and_validate!(model, content); + + + let model = Content::Data(Data{string_data: "string".to_string()}); + let content = r#"string"#; + convert_and_validate!(model, content); +} diff --git a/yaserde_derive/src/ser/expand_enum.rs b/yaserde_derive/src/ser/expand_enum.rs index 2a63988..f776d49 100644 --- a/yaserde_derive/src/ser/expand_enum.rs +++ b/yaserde_derive/src/ser/expand_enum.rs @@ -1,7 +1,6 @@ use crate::attribute::*; use crate::field_type::*; use proc_macro2::TokenStream; -use std::collections::BTreeMap; use syn::spanned::Spanned; use syn::DataEnum; use syn::Fields; @@ -11,8 +10,7 @@ pub fn serialize( data_enum: &DataEnum, name: &Ident, root: &str, - namespaces: &BTreeMap, - default_namespace: &Option, + root_attributes: &YaSerdeAttribute, ) -> TokenStream { let write_enum_content: TokenStream = data_enum .variants @@ -224,10 +222,10 @@ pub fn serialize( .filter_map(|x| x) .collect(); - let add_namespaces: TokenStream = namespaces + let add_namespaces: TokenStream = root_attributes.namespaces .iter() .map(|(prefix, namespace)| { - if let Some(dn) = default_namespace { + if let Some(dn) = &root_attributes.default_namespace { if dn == prefix { return Some(quote!( .default_ns(#namespace) @@ -241,6 +239,8 @@ pub fn serialize( .filter_map(|x| x) .collect(); + let flatten = root_attributes.flatten; + quote! { use xml::writer::XmlEvent; @@ -250,7 +250,7 @@ pub fn serialize( -> Result<(), String> { let skip = writer.skip_start_end(); - if !skip { + 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())?; @@ -264,7 +264,7 @@ pub fn serialize( #write_enum_content } - if !skip { + if !#flatten && !skip { let struct_end_event = XmlEvent::end_element(); writer.write(struct_end_event).map_err(|e| e.to_string())?; } diff --git a/yaserde_derive/src/ser/expand_struct.rs b/yaserde_derive/src/ser/expand_struct.rs index 1411a03..38c2ce0 100644 --- a/yaserde_derive/src/ser/expand_struct.rs +++ b/yaserde_derive/src/ser/expand_struct.rs @@ -2,7 +2,6 @@ use crate::attribute::*; use crate::field_type::*; use crate::ser::element::*; use proc_macro2::TokenStream; -use std::collections::BTreeMap; use std::string::ToString; use syn::spanned::Spanned; use syn::DataStruct; @@ -12,8 +11,7 @@ pub fn serialize( data_struct: &DataStruct, name: &Ident, root: &str, - namespaces: &BTreeMap, - default_namespace: &Option, + root_attributes: &YaSerdeAttribute, ) -> TokenStream { let build_attributes: TokenStream = data_struct .fields @@ -26,7 +24,7 @@ pub fn serialize( let label = &field.ident; - let label_name = build_label_name(&field, &field_attrs, default_namespace); + let label_name = build_label_name(&field, &field_attrs, &root_attributes.default_namespace); get_field_type(field).and_then(|f| match f { FieldType::FieldTypeString @@ -205,10 +203,10 @@ pub fn serialize( .filter_map(|x| x) .collect(); - let add_namespaces: TokenStream = namespaces + let add_namespaces: TokenStream = root_attributes.namespaces .iter() .map(|(prefix, namespace)| { - if let Some(dn) = default_namespace { + if let Some(dn) = &root_attributes.default_namespace { if dn == prefix { return Some(quote!( .default_ns(#namespace) @@ -239,7 +237,7 @@ pub fn serialize( )); } - let label_name = build_label_name(&field, &field_attrs, default_namespace); + let label_name = build_label_name(&field, &field_attrs, &root_attributes.default_namespace); let conditions = condition_generator(label, &field_attrs); get_field_type(field).and_then(|f| match f { @@ -381,6 +379,8 @@ pub fn serialize( .filter_map(|x| x) .collect(); + let flatten = root_attributes.flatten; + quote! { use xml::writer::XmlEvent; @@ -390,7 +390,7 @@ pub fn serialize( -> Result<(), String> { let skip = writer.skip_start_end(); - if !skip { + 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 @@ -399,7 +399,7 @@ pub fn serialize( #struct_inspector - if !skip { + if !#flatten && !skip { let struct_end_event = XmlEvent::end_element(); writer.write(struct_end_event).map_err(|e| e.to_string())?; } diff --git a/yaserde_derive/src/ser/mod.rs b/yaserde_derive/src/ser/mod.rs index 68a1532..8df059e 100644 --- a/yaserde_derive/src/ser/mod.rs +++ b/yaserde_derive/src/ser/mod.rs @@ -2,7 +2,7 @@ pub mod element; pub mod expand_enum; pub mod expand_struct; -use crate::attribute; +use crate::attribute::YaSerdeAttribute; use proc_macro2::TokenStream; use syn; use syn::Ident; @@ -12,13 +12,13 @@ pub fn expand_derive_serialize(ast: &syn::DeriveInput) -> Result Result expand_enum::serialize( data_enum, name, &root, - &root_attrs.namespaces, - &root_attrs.default_namespace, + &root_attrs, ), syn::Data::Union(ref _data_union) => unimplemented!(), };