diff --git a/yaserde/tests/de_flatten.rs b/yaserde/tests/de_flatten.rs new file mode 100644 index 0000000..d385430 --- /dev/null +++ b/yaserde/tests/de_flatten.rs @@ -0,0 +1,166 @@ +#[macro_use] +extern crate yaserde_derive; + +use std::io::Read; +use yaserde::de::from_str; +use yaserde::YaDeserialize; + +macro_rules! convert_and_validate { + ($content: expr, $struct: tt, $model: expr) => { + let loaded: Result<$struct, String> = from_str($content); + assert_eq!(loaded, Ok($model)); + }; +} + +#[test] +fn de_root_flatten_struct() { + #[derive(Default, PartialEq, Debug, YaDeserialize)] + #[yaserde(flatten)] + struct Content { + binary_data: String, + string_data: String, + } + + let content = r#" + + binary + string + "#; + + convert_and_validate!( + content, + Content, + Content { + binary_data: "binary".to_string(), + string_data: "string".to_string(), + } + ); +} + +#[test] +fn de_root_flatten_enum() { + #[derive(PartialEq, Debug, YaDeserialize)] + #[yaserde(flatten)] + pub enum Content { + Binary(Binary), + Data(Data), + Unknown, + } + + impl Default for Content { + fn default() -> Self { + Content::Unknown + } + } + + #[derive(Default, PartialEq, Debug, YaDeserialize)] + pub struct Binary { + binary_data: String, + } + + #[derive(Default, PartialEq, Debug, YaDeserialize)] + pub struct Data { + string_data: String, + } + + let content = r#" + + + binary + + "#; + + convert_and_validate!( + content, + Content, + Content::Binary(Binary { + binary_data: "binary".to_string(), + }) + ); +} + +#[test] +fn de_flatten() { + #[derive(Default, PartialEq, Debug, YaDeserialize)] + struct DateTime { + #[yaserde(flatten)] + date: Date, + time: String, + #[yaserde(flatten)] + kind: DateKind, + } + + #[derive(Default, PartialEq, Debug, YaDeserialize)] + struct Date { + year: i32, + month: i32, + day: i32, + #[yaserde(flatten)] + extra: Extra, + #[yaserde(flatten)] + optional_extra: Option, + } + + #[derive(Default, PartialEq, Debug, YaDeserialize)] + pub struct Extra { + week: i32, + century: i32, + } + + #[derive(Default, PartialEq, Debug, YaDeserialize)] + pub struct OptionalExtra { + lunar_day: i32, + } + + #[derive(PartialEq, Debug, YaDeserialize)] + pub enum DateKind { + #[yaserde(rename = "holidays")] + Holidays(Vec), + #[yaserde(rename = "working")] + Working, + } + + impl Default for DateKind { + fn default() -> Self { + DateKind::Working + } + }; + + let content = r#" + + + 2020 + 1 + 1 + 1 + 21 + 1 + + New Year's Day + Novy God Day + Polar Bear Swim Day + + "#; + convert_and_validate!( + content, + DateTime, + DateTime { + date: Date { + year: 2020, + month: 1, + day: 1, + extra: Extra { + week: 1, + century: 21, + }, + optional_extra: Some(OptionalExtra { lunar_day: 1 }), + }, + time: "10:40:03".to_string(), + kind: DateKind::Holidays(vec![ + "New Year's Day".into(), + "Novy God Day".into(), + "Polar Bear Swim Day".into() + ]) + } + ); +} diff --git a/yaserde/tests/deserializer.rs b/yaserde/tests/deserializer.rs index 21df4c0..dd212ce 100644 --- a/yaserde/tests/deserializer.rs +++ b/yaserde/tests/deserializer.rs @@ -691,92 +691,6 @@ fn de_custom() { ); } -#[test] -fn de_flatten() { - #[derive(Default, PartialEq, Debug, YaDeserialize)] - struct DateTime { - #[yaserde(flatten)] - date: Date, - time: String, - #[yaserde(flatten)] - kind: DateKind, - } - - #[derive(Default, PartialEq, Debug, YaDeserialize)] - struct Date { - year: i32, - month: i32, - day: i32, - #[yaserde(flatten)] - extra: Extra, - #[yaserde(flatten)] - optional_extra: Option, - } - - #[derive(Default, PartialEq, Debug, YaDeserialize)] - pub struct Extra { - week: i32, - century: i32, - } - - #[derive(Default, PartialEq, Debug, YaDeserialize)] - pub struct OptionalExtra { - lunar_day: i32, - } - - #[derive(PartialEq, Debug, YaDeserialize)] - pub enum DateKind { - #[yaserde(rename = "holidays")] - Holidays(Vec), - #[yaserde(rename = "working")] - Working, - } - - impl Default for DateKind { - fn default() -> Self { - DateKind::Working - } - }; - - let content = r#" - - - 2020 - 1 - 1 - 1 - 21 - 1 - - New Year's Day - Novy God Day - Polar Bear Swim Day - - "#; - convert_and_validate!( - content, - DateTime, - DateTime { - date: Date { - year: 2020, - month: 1, - day: 1, - extra: Extra { - week: 1, - century: 21, - }, - optional_extra: Some(OptionalExtra { lunar_day: 1 }), - }, - time: "10:40:03".to_string(), - kind: DateKind::Holidays(vec![ - "New Year's Day".into(), - "Novy God Day".into(), - "Polar Bear Swim Day".into() - ]) - } - ); -} - #[test] fn de_subitem_issue_12() { #[derive(Default, PartialEq, Debug, YaDeserialize)] diff --git a/yaserde/tests/ser_flatten.rs b/yaserde/tests/ser_flatten.rs index 850251a..0127ed1 100644 --- a/yaserde/tests/ser_flatten.rs +++ b/yaserde/tests/ser_flatten.rs @@ -21,8 +21,91 @@ macro_rules! convert_and_validate { } #[test] -fn ser_root_flatten_struct() { +fn ser_flatten() { + #[derive(Default, PartialEq, Debug, YaSerialize)] + struct DateTime { + #[yaserde(flatten)] + date: Date, + time: String, + #[yaserde(flatten)] + kind: DateKind, + } + #[derive(Default, PartialEq, Debug, YaSerialize)] + struct Date { + year: i32, + month: i32, + day: i32, + #[yaserde(flatten)] + extra: Extra, + #[yaserde(flatten)] + optional_extra: Option, + } + + #[derive(Default, PartialEq, Debug, YaSerialize)] + pub struct Extra { + week: i32, + century: i32, + } + + #[derive(Default, PartialEq, Debug, YaSerialize)] + pub struct OptionalExtra { + lunar_day: i32, + } + + #[derive(PartialEq, Debug, YaSerialize)] + pub enum DateKind { + #[yaserde(rename = "holidays")] + Holidays(Vec), + #[yaserde(rename = "working")] + Working, + } + + impl Default for DateKind { + fn default() -> Self { + DateKind::Working + } + }; + + let model = DateTime { + date: Date { + year: 2020, + month: 1, + day: 1, + extra: Extra { + week: 1, + century: 21, + }, + optional_extra: Some(OptionalExtra { lunar_day: 1 }), + }, + time: "10:40:03".to_string(), + kind: DateKind::Holidays(vec![ + "New Year's Day".into(), + "Novy God Day".into(), + "Polar Bear Swim Day".into(), + ]), + }; + + let content = r#" + + + 2020 + 1 + 1 + 1 + 21 + 1 + + New Year's Day + Novy God Day + Polar Bear Swim Day + "#; + + convert_and_validate!(model, content); +} + +#[test] +fn ser_root_flatten_struct() { #[derive(YaSerialize, PartialEq, Debug)] #[yaserde(flatten)] pub struct Content { @@ -30,7 +113,7 @@ fn ser_root_flatten_struct() { string_data: String, } - let model = Content{ + let model = Content { binary_data: "binary".to_string(), string_data: "string".to_string(), }; @@ -57,12 +140,17 @@ fn ser_root_flatten_enum() { string_data: String, } - let model = Content::Binary(Binary{binary_data: "binary".to_string()}); - let content = r#"binary"#; + 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"#; + let model = Content::Data(Data { + string_data: "string".to_string(), + }); + let content = + r#"string"#; convert_and_validate!(model, content); } diff --git a/yaserde/tests/serializer.rs b/yaserde/tests/serializer.rs index 0e1e8a1..c3ff11b 100644 --- a/yaserde/tests/serializer.rs +++ b/yaserde/tests/serializer.rs @@ -329,87 +329,3 @@ fn ser_custom() { let content = "2020110"; convert_and_validate!(model, content); } - -#[test] -fn ser_flatten() { - #[derive(Default, PartialEq, Debug, YaSerialize)] - struct DateTime { - #[yaserde(flatten)] - date: Date, - time: String, - #[yaserde(flatten)] - kind: DateKind, - } - - #[derive(Default, PartialEq, Debug, YaSerialize)] - struct Date { - year: i32, - month: i32, - day: i32, - #[yaserde(flatten)] - extra: Extra, - #[yaserde(flatten)] - optional_extra: Option, - } - - #[derive(Default, PartialEq, Debug, YaSerialize)] - pub struct Extra { - week: i32, - century: i32, - } - - #[derive(Default, PartialEq, Debug, YaSerialize)] - pub struct OptionalExtra { - lunar_day: i32, - } - - #[derive(PartialEq, Debug, YaSerialize)] - pub enum DateKind { - #[yaserde(rename = "holidays")] - Holidays(Vec), - #[yaserde(rename = "working")] - Working, - } - - impl Default for DateKind { - fn default() -> Self { - DateKind::Working - } - }; - - let model = DateTime { - date: Date { - year: 2020, - month: 1, - day: 1, - extra: Extra { - week: 1, - century: 21, - }, - optional_extra: Some(OptionalExtra { lunar_day: 1 }), - }, - time: "10:40:03".to_string(), - kind: DateKind::Holidays(vec![ - "New Year's Day".into(), - "Novy God Day".into(), - "Polar Bear Swim Day".into(), - ]), - }; - - let content = r#" - - - 2020 - 1 - 1 - 1 - 21 - 1 - - New Year's Day - Novy God Day - Polar Bear Swim Day - "#; - - convert_and_validate!(model, content); -} diff --git a/yaserde_derive/src/de/expand_enum.rs b/yaserde_derive/src/de/expand_enum.rs index 4fdb0ed..c43d246 100644 --- a/yaserde_derive/src/de/expand_enum.rs +++ b/yaserde_derive/src/de/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,7 +10,7 @@ pub fn parse( data_enum: &DataEnum, name: &Ident, root: &str, - _namespaces: &BTreeMap, + root_attributes: &YaSerdeAttribute, ) -> TokenStream { let match_to_enum: TokenStream = data_enum .variants @@ -20,6 +19,8 @@ pub fn parse( .filter_map(|f| f) .collect(); + let flatten = root_attributes.flatten; + quote! { use xml::reader::XmlEvent; use yaserde::Visitor; @@ -47,7 +48,7 @@ pub fn parse( match name.local_name.as_str() { #match_to_enum - named_element => { + _named_element => { let _root = reader.next_event(); } } @@ -68,6 +69,13 @@ pub fn parse( XmlEvent::Characters(ref text_content) => { let _root = reader.next_event(); } + XmlEvent::EndDocument => { + if #flatten { + break; + } + + return Err(format!("End of document, missing some content ?")) + } event => { return Err(format!("unknown event {:?}", event)) } diff --git a/yaserde_derive/src/de/expand_struct.rs b/yaserde_derive/src/de/expand_struct.rs index 1f1d51e..3c48215 100644 --- a/yaserde_derive/src/de/expand_struct.rs +++ b/yaserde_derive/src/de/expand_struct.rs @@ -11,13 +11,13 @@ pub fn parse( data_struct: &DataStruct, name: &Ident, root: &str, - prefix: &Option, - namespaces: &BTreeMap, + root_attributes: &YaSerdeAttribute, ) -> TokenStream { - let namespaces_matches: TokenStream = namespaces + let namespaces_matches: TokenStream = root_attributes + .namespaces .iter() .map(|(p, ns)| { - if prefix.as_ref() == Some(p) { + if root_attributes.prefix.as_ref() == Some(p) { Some(quote!(#ns => {})) } else { None @@ -199,7 +199,7 @@ pub fn parse( &action, &field_attrs, label, - &namespaces, + &root_attributes.namespaces, field.span(), ) }; @@ -368,6 +368,8 @@ pub fn parse( build_code_for_unused_xml_events(&call_flatten_visitors) }; + let flatten = root_attributes.flatten; + quote! { use xml::reader::{XmlEvent, EventReader}; use xml::writer::EventWriter; @@ -407,7 +409,6 @@ pub fn parse( loop { let event = reader.peek()?.to_owned(); - match event { XmlEvent::StartElement{ref name, ref attributes, ..} => { let mut skipped = false; @@ -443,6 +444,11 @@ pub fn parse( #write_unused depth -= 1; } + XmlEvent::EndDocument => { + if #flatten { + break; + } + } XmlEvent::Characters(ref text_content) => { #set_text let event = reader.next_event()?; diff --git a/yaserde_derive/src/de/mod.rs b/yaserde_derive/src/de/mod.rs index 4e3e8ab..84f1f17 100644 --- a/yaserde_derive/src/de/mod.rs +++ b/yaserde_derive/src/de/mod.rs @@ -16,16 +16,10 @@ pub fn expand_derive_deserialize(ast: &syn::DeriveInput) -> Result expand_struct::parse( - data_struct, - name, - &root, - &root_attrs.prefix, - &root_attrs.namespaces, - ), - syn::Data::Enum(ref data_enum) => { - expand_enum::parse(data_enum, name, &root, &root_attrs.namespaces) + syn::Data::Struct(ref data_struct) => { + expand_struct::parse(data_struct, name, &root, &root_attrs) } + syn::Data::Enum(ref data_enum) => expand_enum::parse(data_enum, name, &root, &root_attrs), syn::Data::Union(ref _data_union) => unimplemented!(), }; diff --git a/yaserde_derive/src/ser/expand_enum.rs b/yaserde_derive/src/ser/expand_enum.rs index f776d49..a357272 100644 --- a/yaserde_derive/src/ser/expand_enum.rs +++ b/yaserde_derive/src/ser/expand_enum.rs @@ -222,7 +222,8 @@ pub fn serialize( .filter_map(|x| x) .collect(); - let add_namespaces: TokenStream = root_attributes.namespaces + let add_namespaces: TokenStream = root_attributes + .namespaces .iter() .map(|(prefix, namespace)| { if let Some(dn) = &root_attributes.default_namespace { diff --git a/yaserde_derive/src/ser/expand_struct.rs b/yaserde_derive/src/ser/expand_struct.rs index 38c2ce0..83bbd19 100644 --- a/yaserde_derive/src/ser/expand_struct.rs +++ b/yaserde_derive/src/ser/expand_struct.rs @@ -203,7 +203,8 @@ pub fn serialize( .filter_map(|x| x) .collect(); - let add_namespaces: TokenStream = root_attributes.namespaces + let add_namespaces: TokenStream = root_attributes + .namespaces .iter() .map(|(prefix, namespace)| { if let Some(dn) = &root_attributes.default_namespace { diff --git a/yaserde_derive/src/ser/mod.rs b/yaserde_derive/src/ser/mod.rs index 8df059e..dec8dfa 100644 --- a/yaserde_derive/src/ser/mod.rs +++ b/yaserde_derive/src/ser/mod.rs @@ -18,7 +18,8 @@ pub fn expand_derive_serialize(ast: &syn::DeriveInput) -> Result Result expand_struct::serialize( - data_struct, - name, - &root, - &root_attrs, - ), - syn::Data::Enum(ref data_enum) => expand_enum::serialize( - data_enum, - name, - &root, - &root_attrs, - ), + syn::Data::Struct(ref data_struct) => { + expand_struct::serialize(data_struct, name, &root, &root_attrs) + } + syn::Data::Enum(ref data_enum) => expand_enum::serialize(data_enum, name, &root, &root_attrs), syn::Data::Union(ref _data_union) => unimplemented!(), };