diff --git a/yaserde/src/lib.rs b/yaserde/src/lib.rs index 8796731..6eedc66 100644 --- a/yaserde/src/lib.rs +++ b/yaserde/src/lib.rs @@ -137,3 +137,76 @@ fn default_visitor() { test_type!(visit_u64, "Unexpected u64 \"\""); test_type!(visit_str, "Unexpected str \"\""); } + +#[doc(hidden)] +mod testing { + #[macro_export] + macro_rules! test_for_type { + ($type:ty, $value:expr, $content:expr) => {{ + #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] + #[yaserde(rename = "data")] + pub struct Data { + item: $type, + } + + let model = Data { item: $value }; + + let content = if let Some(str_value) = $content { + String::from("") + str_value + "" + } else { + String::from("") + }; + + serialize_and_validate!(model, content); + deserialize_and_validate!(&content, model, Data); + }}; + } + + #[macro_export] + macro_rules! test_for_attribute_type { + ($type: ty, $value: expr, $content: expr) => {{ + #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] + #[yaserde(rename = "data")] + pub struct Data { + #[yaserde(attribute)] + item: $type, + } + let model = Data { item: $value }; + + let content = if let Some(str_value) = $content { + "" + } else { + "".to_string() + }; + + serialize_and_validate!(model, content); + deserialize_and_validate!(&content, model, Data); + }}; + } + + #[macro_export] + macro_rules! deserialize_and_validate { + ($content: expr, $model: expr, $struct: tt) => { + let loaded: Result<$struct, String> = yaserde::de::from_str($content); + assert_eq!(loaded, Ok($model)); + }; + } + + #[macro_export] + macro_rules! serialize_and_validate { + ($model: expr, $content: expr) => { + let data: Result = yaserde::ser::to_string(&$model); + + let content = String::from(r#""#) + &$content; + assert_eq!( + data, + Ok( + String::from(content) + .split("\n") + .map(|s| s.trim()) + .collect::() + ) + ); + }; + } +} diff --git a/yaserde/tests/de_default.rs b/yaserde/tests/de_default.rs deleted file mode 100644 index bb0c406..0000000 --- a/yaserde/tests/de_default.rs +++ /dev/null @@ -1,93 +0,0 @@ -#[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_default_field_string() { - fn default_string() -> String { - "my_default_value".to_string() - } - - #[derive(YaDeserialize, PartialEq, Debug)] - #[yaserde(root = "base")] - pub struct XmlStruct { - #[yaserde(default = "default_string")] - background: String, - } - - let content = ""; - convert_and_validate!( - content, - XmlStruct, - XmlStruct { - background: "my_default_value".to_string(), - } - ); -} - -#[test] -fn de_default_field_boolean() { - fn default_boolean() -> bool { - true - } - - #[derive(YaDeserialize, PartialEq, Debug)] - #[yaserde(root = "base")] - pub struct XmlStruct { - #[yaserde(default = "default_boolean")] - background: bool, - } - - let content = ""; - convert_and_validate!(content, XmlStruct, XmlStruct { background: true }); -} - -#[test] -fn de_default_field_number() { - fn default_number() -> u8 { - 6 - } - - #[derive(YaDeserialize, PartialEq, Debug)] - #[yaserde(root = "base")] - pub struct XmlStruct { - #[yaserde(default = "default_number")] - background: u8, - } - - let content = ""; - convert_and_validate!(content, XmlStruct, XmlStruct { background: 6 }); -} - -#[test] -fn de_default_attribute_string() { - fn default_string() -> String { - "my_default_value".to_string() - } - - #[derive(YaDeserialize, PartialEq, Debug)] - #[yaserde(root = "base")] - pub struct XmlStruct { - #[yaserde(attribute, default = "default_string")] - background: String, - } - - let content = ""; - convert_and_validate!( - content, - XmlStruct, - XmlStruct { - background: "my_default_value".to_string(), - } - ); -} diff --git a/yaserde/tests/de_flatten.rs b/yaserde/tests/de_flatten.rs deleted file mode 100644 index d385430..0000000 --- a/yaserde/tests/de_flatten.rs +++ /dev/null @@ -1,166 +0,0 @@ -#[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/de_namespace.rs b/yaserde/tests/de_namespace.rs deleted file mode 100644 index dd3d94c..0000000 --- a/yaserde/tests/de_namespace.rs +++ /dev/null @@ -1,144 +0,0 @@ -#[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_struct_namespace() { - #[derive(YaDeserialize, PartialEq, Debug)] - #[yaserde( - root = "book", - prefix = "ns", - namespace = "ns: http://www.sample.com/ns/domain", - namespace = "ns2: http://www.sample.com/ns/domain_2" - )] - pub struct Book { - #[yaserde(prefix = "ns")] - author: String, - #[yaserde(prefix = "ns2")] - title: String, - } - - let content = r#" - - Antoine de Saint-Exupéry - Little prince - - "#; - convert_and_validate!( - content, - Book, - Book { - author: String::from("Antoine de Saint-Exupéry"), - title: String::from("Little prince"), - } - ); - - let content = r#" - - Antoine de Saint-Exupéry - Little prince - - "#; - convert_and_validate!( - content, - Book, - Book { - author: String::from("Antoine de Saint-Exupéry"), - title: String::from("Little prince"), - } - ); - - let content = r#" - - Antoine de Saint-Exupéry - Little prince - - "#; - convert_and_validate!( - content, - Book, - Book { - author: String::from("Antoine de Saint-Exupéry"), - title: String::from("Little prince"), - } - ); - - let content = r#" - - Antoine de Saint-Exupéry - Little prince - "#; - let loaded: Result = from_str(content); - assert_eq!( - loaded, - Err("bad namespace for book, found http://www.sample.com/ns/domain2".to_string()) - ); -} - -#[test] -fn de_struct_namespace_nested() { - #[derive(YaDeserialize, Default, PartialEq, Debug)] - #[yaserde(prefix = "nsa", namespace = "nsa: http://www.sample.com/ns/a")] - struct A { - #[yaserde(prefix = "nsa")] - alpha: i32, - } - - #[derive(YaDeserialize, Default, PartialEq, Debug)] - #[yaserde(prefix = "nsb", namespace = "nsb: http://www.sample.com/ns/b")] - struct B { - // Note that name `nested` resides in `nsb` though it has a type from `nsa` - #[yaserde(prefix = "nsb")] - nested: A, - } - - convert_and_validate!( - r#" - - - - 32 - - - "#, - B, - B { - nested: A { alpha: 32 } - } - ); -} - -#[test] -fn de_enum_namespace() { - #[derive(YaDeserialize, PartialEq, Debug)] - #[yaserde( - root = "root", - prefix = "ns", - namespace = "ns: http://www.sample.com/ns/domain" - )] - pub enum XmlStruct { - #[yaserde(prefix = "ns")] - Item, - } - - impl Default for XmlStruct { - fn default() -> XmlStruct { - XmlStruct::Item - } - } - - let content = "ns:Item"; - convert_and_validate!(content, XmlStruct, XmlStruct::Item); -} diff --git a/yaserde/tests/de_option.rs b/yaserde/tests/de_option.rs deleted file mode 100644 index a986ce4..0000000 --- a/yaserde/tests/de_option.rs +++ /dev/null @@ -1,144 +0,0 @@ -#[macro_use] -extern crate yaserde_derive; - -use std::io::Read; -use yaserde::de::from_str; -use yaserde::YaDeserialize; - -macro_rules! convert_and_validate { - ($type: ty, $value: expr, $content: expr) => {{ - #[derive(YaDeserialize, PartialEq, Debug)] - #[yaserde(root = "data")] - pub struct Data { - item: Option<$type>, - } - - let model = Data { item: $value }; - - let source = if let Some(content) = $content { - String::from("") - + content - + "" - } else { - String::from("") - }; - - let loaded: Result = from_str(&source); - assert_eq!(loaded, Ok(model)); - }}; -} - -macro_rules! convert_and_validate_for_attribute { - ($type: ty, $value: expr, $content: expr) => {{ - #[derive(YaDeserialize, PartialEq, Debug)] - #[yaserde(root = "data")] - pub struct Data { - #[yaserde(attribute)] - item: Option<$type>, - } - - let model = Data { item: $value }; - - let source = if let Some(content) = $content { - String::from("" - } else { - String::from("") - }; - - let loaded: Result = from_str(&source); - assert_eq!(loaded, Ok(model)); - }}; -} - -#[test] -fn de_option() { - convert_and_validate!(String, Some("test".to_string()), Some("test")); - convert_and_validate!(String, None, None); - convert_and_validate!(bool, Some(true), Some("true")); - convert_and_validate!(bool, None, None); - convert_and_validate!(u8, Some(12 as u8), Some("12")); - convert_and_validate!(u8, None, None); - convert_and_validate!(i8, Some(12 as i8), Some("12")); - convert_and_validate!(i8, Some(-12 as i8), Some("-12")); - convert_and_validate!(i8, None, None); - convert_and_validate!(u16, Some(12 as u16), Some("12")); - convert_and_validate!(u16, None, None); - convert_and_validate!(i16, Some(12 as i16), Some("12")); - convert_and_validate!(i16, Some(-12 as i16), Some("-12")); - convert_and_validate!(i16, None, None); - convert_and_validate!(u32, Some(12 as u32), Some("12")); - convert_and_validate!(u32, None, None); - convert_and_validate!(i32, Some(12 as i32), Some("12")); - convert_and_validate!(i32, Some(-12 as i32), Some("-12")); - convert_and_validate!(i32, None, None); - convert_and_validate!(u64, Some(12 as u64), Some("12")); - convert_and_validate!(u64, None, None); - convert_and_validate!(i64, Some(12 as i64), Some("12")); - convert_and_validate!(i64, Some(-12 as i64), Some("-12")); - convert_and_validate!(i64, None, None); - convert_and_validate!(f32, Some(-12.5_f32 as f32), Some("-12.5")); - convert_and_validate!(f32, None, None); - convert_and_validate!(f64, Some(-12.5 as f64), Some("-12.5")); - convert_and_validate!(f64, None, None); - - convert_and_validate_for_attribute!(String, Some("test".to_string()), Some("test")); - convert_and_validate_for_attribute!(String, None, None); - convert_and_validate_for_attribute!(bool, Some(true), Some("true")); - convert_and_validate_for_attribute!(bool, None, None); - convert_and_validate_for_attribute!(u8, Some(12 as u8), Some("12")); - convert_and_validate_for_attribute!(u8, None, None); - convert_and_validate_for_attribute!(i8, Some(12 as i8), Some("12")); - convert_and_validate_for_attribute!(i8, Some(-12 as i8), Some("-12")); - convert_and_validate_for_attribute!(i8, None, None); - convert_and_validate_for_attribute!(u16, Some(12 as u16), Some("12")); - convert_and_validate_for_attribute!(u16, None, None); - convert_and_validate_for_attribute!(i16, Some(12 as i16), Some("12")); - convert_and_validate_for_attribute!(i16, Some(-12 as i16), Some("-12")); - convert_and_validate_for_attribute!(i16, None, None); - convert_and_validate_for_attribute!(u32, Some(12 as u32), Some("12")); - convert_and_validate_for_attribute!(u32, None, None); - convert_and_validate_for_attribute!(i32, Some(12 as i32), Some("12")); - convert_and_validate_for_attribute!(i32, Some(-12 as i32), Some("-12")); - convert_and_validate_for_attribute!(i32, None, None); - convert_and_validate_for_attribute!(u64, Some(12 as u64), Some("12")); - convert_and_validate_for_attribute!(u64, None, None); - convert_and_validate_for_attribute!(i64, Some(12 as i64), Some("12")); - convert_and_validate_for_attribute!(i64, Some(-12 as i64), Some("-12")); - convert_and_validate_for_attribute!(i64, None, None); - convert_and_validate_for_attribute!(f32, Some(-12.5 as f32), Some("-12.5")); - convert_and_validate_for_attribute!(f32, None, None); - convert_and_validate_for_attribute!(f64, Some(-12.5 as f64), Some("-12.5")); - convert_and_validate_for_attribute!(f64, None, None); -} - -#[test] -fn de_option_struct() { - #[derive(YaDeserialize, Debug, PartialEq)] - struct Test { - field: SubTest, - } - - #[derive(YaDeserialize, Debug, PartialEq)] - struct SubTest { - content: Option, - } - - impl Default for SubTest { - fn default() -> Self { - SubTest { content: None } - } - } - - convert_and_validate!( - Test, - Some(Test { - field: SubTest { - content: Some("value".to_string()) - } - }), - Some("value") - ); - convert_and_validate!(Test, None, None); -} diff --git a/yaserde/tests/de_type.rs b/yaserde/tests/de_type.rs deleted file mode 100644 index b8775da..0000000 --- a/yaserde/tests/de_type.rs +++ /dev/null @@ -1,81 +0,0 @@ -#[macro_use] -extern crate yaserde_derive; - -use std::io::Read; -use yaserde::de::from_str; -use yaserde::YaDeserialize; - -macro_rules! convert_and_validate { - ($type:ty, $value:expr, $content:expr) => {{ - #[derive(YaDeserialize, PartialEq, Debug)] - #[yaserde(root = "data")] - pub struct Data { - item: $type, - } - - let model = Data { item: $value }; - - let content = String::from("") - + $content - + ""; - - let loaded: Result = from_str(&content); - assert_eq!(loaded, Ok(model)); - }}; -} - -macro_rules! convert_and_validate_for_attribute { - ($type:ty, $value:expr, $content:expr) => {{ - #[derive(YaDeserialize, PartialEq, Debug)] - #[yaserde(root = "data")] - pub struct Data { - #[yaserde(attribute)] - item: $type, - } - - let model = Data { item: $value }; - - let content = - String::from(""; - - let loaded: Result = from_str(&content); - assert_eq!(loaded, Ok(model)); - }}; -} - -#[test] -fn de_type() { - convert_and_validate!(String, "test".to_string(), "test"); - convert_and_validate!(bool, true, "true"); - convert_and_validate!(u8, 12 as u8, "12"); - convert_and_validate!(i8, 12 as i8, "12"); - convert_and_validate!(i8, -12 as i8, "-12"); - convert_and_validate!(u16, 12 as u16, "12"); - convert_and_validate!(i16, 12 as i16, "12"); - convert_and_validate!(i16, -12 as i16, "-12"); - convert_and_validate!(u32, 12 as u32, "12"); - convert_and_validate!(i32, 12 as i32, "12"); - convert_and_validate!(i32, -12 as i32, "-12"); - convert_and_validate!(u64, 12 as u64, "12"); - convert_and_validate!(i64, 12 as i64, "12"); - convert_and_validate!(i64, -12 as i64, "-12"); - convert_and_validate!(f32, -12.5_f32 as f32, "-12.5"); - convert_and_validate!(f64, -12.5 as f64, "-12.5"); - - convert_and_validate_for_attribute!(String, "test".to_string(), "test"); - convert_and_validate_for_attribute!(bool, true, "true"); - convert_and_validate_for_attribute!(u8, 12 as u8, "12"); - convert_and_validate_for_attribute!(i8, 12 as i8, "12"); - convert_and_validate_for_attribute!(i8, -12 as i8, "-12"); - convert_and_validate_for_attribute!(u16, 12 as u16, "12"); - convert_and_validate_for_attribute!(i16, 12 as i16, "12"); - convert_and_validate_for_attribute!(i16, -12 as i16, "-12"); - convert_and_validate_for_attribute!(u32, 12 as u32, "12"); - convert_and_validate_for_attribute!(i32, 12 as i32, "12"); - convert_and_validate_for_attribute!(i32, -12 as i32, "-12"); - convert_and_validate_for_attribute!(u64, 12 as u64, "12"); - convert_and_validate_for_attribute!(i64, 12 as i64, "12"); - convert_and_validate_for_attribute!(i64, -12 as i64, "-12"); - convert_and_validate_for_attribute!(f32, -12.5 as f32, "-12.5"); - convert_and_validate_for_attribute!(f64, -12.5 as f64, "-12.5"); -} diff --git a/yaserde/tests/default.rs b/yaserde/tests/default.rs new file mode 100644 index 0000000..c4ba308 --- /dev/null +++ b/yaserde/tests/default.rs @@ -0,0 +1,112 @@ +#[macro_use] +extern crate yaserde; +#[macro_use] +extern crate yaserde_derive; + +use std::io::{Read, Write}; +use yaserde::{YaDeserialize, YaSerialize}; + +#[test] +fn default_field_string() { + fn default_string() -> String { + "my_default_value".to_string() + } + + #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] + #[yaserde(rename = "base")] + pub struct XmlStruct { + #[yaserde(default = "default_string")] + background: String, + } + + let model = XmlStruct { + background: "my_default_value".to_string(), + }; + + let content = ""; + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, XmlStruct); + + let content = "my_value"; + let model = XmlStruct { + background: "my_value".to_string(), + }; + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, XmlStruct); +} + +#[test] +fn default_field_boolean() { + fn default_boolean() -> bool { + true + } + + #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] + #[yaserde(rename = "base")] + pub struct XmlStruct { + #[yaserde(default = "default_boolean")] + background: bool, + } + + let content = ""; + let model = XmlStruct { background: true }; + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, XmlStruct); + + let content = "false"; + let model = XmlStruct { background: false }; + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, XmlStruct); +} + +#[test] +fn default_field_number() { + fn default_number() -> u8 { + 6 + } + + #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] + #[yaserde(rename = "base")] + pub struct XmlStruct { + #[yaserde(default = "default_number")] + background: u8, + } + + let content = ""; + let model = XmlStruct { background: 6 }; + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, XmlStruct); + + let content = "4"; + let model = XmlStruct { background: 4 }; + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, XmlStruct); +} + +#[test] +fn default_attribute_string() { + fn default_string() -> String { + "my_default_value".to_string() + } + + #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] + #[yaserde(rename = "base")] + pub struct XmlStruct { + #[yaserde(attribute, default = "default_string")] + background: String, + } + + let content = ""; + let model = XmlStruct { + background: "my_default_value".to_string(), + }; + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, XmlStruct); + + let content = r#""#; + let model = XmlStruct { + background: "black".to_string(), + }; + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, XmlStruct); +} diff --git a/yaserde/tests/enum.rs b/yaserde/tests/enum.rs new file mode 100644 index 0000000..cca4edf --- /dev/null +++ b/yaserde/tests/enum.rs @@ -0,0 +1,300 @@ +#[macro_use] +extern crate yaserde; +#[macro_use] +extern crate yaserde_derive; + +use std::io::{Read, Write}; +use yaserde::{YaDeserialize, YaSerialize}; + +#[test] +fn basic_enum() { + #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] + #[yaserde(rename = "base")] + pub struct XmlStruct { + color: Color, + } + + #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] + #[yaserde(rename = "color")] + pub enum Color { + White, + Black, + #[yaserde(rename = "custom")] + Custom { + enabled: String, + u8_value: u8, + i8_value: i8, + u16_value: u16, + i16_value: i16, + u32_value: u32, + i32_value: i32, + u64_value: u64, + i64_value: i64, + f32_value: f32, + f64_value: f64, + color: RGBColor, + alpha: Alpha, + alphas: Vec, + }, + } + + impl Default for Color { + fn default() -> Color { + Color::White + } + } + + assert_eq!(Color::default(), Color::White); + + #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] + pub struct RGBColor { + red: String, + green: String, + blue: String, + } + + #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] + pub enum Alpha { + Transparent, + Opaque, + } + + impl Default for Alpha { + fn default() -> Alpha { + Alpha::Transparent + } + } + + let model = XmlStruct { + color: Color::Black, + }; + + let content = "Black"; + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, XmlStruct); + + let model = XmlStruct { + color: Color::Custom { + enabled: "true".to_string(), + u8_value: 8, + i8_value: -8, + u16_value: 16, + i16_value: -16, + u32_value: 32, + i32_value: -32, + u64_value: 64, + i64_value: -64, + f32_value: 32.0, + f64_value: 64.0, + color: RGBColor { + red: "0".to_string(), + green: "128".to_string(), + blue: "255".to_string(), + }, + alpha: Alpha::Opaque, + alphas: vec![Alpha::Opaque, Alpha::Transparent], + }, + }; + + let content = r#" + +true +8 +-8 +16 +-16 +32 +-32 +64 +-64 +32 +64 +0128255 +Opaque +Opaque +Transparent + +"#; + + serialize_and_validate!(model, content); + // TODO + // deserialize_and_validate!(content, model, XmlStruct); +} + +#[test] +fn attribute_enum() { + #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] + #[yaserde(rename = "base")] + pub struct XmlStruct { + #[yaserde(attribute)] + color: Color, + } + + #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] + #[yaserde(rename = "color")] + pub enum Color { + #[yaserde(rename = "pink")] + Pink, + } + + impl Default for Color { + fn default() -> Color { + Color::Pink + } + } + + let model = XmlStruct { color: Color::Pink }; + + let content = r#""#; + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, XmlStruct); +} + +#[test] +fn unnamed_enum() { + #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] + #[yaserde(rename = "base")] + pub struct XmlStruct { + color: Enum, + } + + #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] + pub struct OtherStruct { + fi: i32, + se: i32, + } + + #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] + pub enum Enum { + Simple, + Field(String), + FullPath(std::string::String), + Integer(i32), + UserStruct(OtherStruct), + OptionString(Option), + OptionUserStruct(Option), + Strings(Vec), + Ints(Vec), + Structs(Vec), + #[yaserde(rename = "renamed")] + ToRename(u32), + #[yaserde(rename = "renamed.with.dots")] + ToRenameDots(u32), + } + + impl Default for Enum { + fn default() -> Enum { + Enum::Simple + } + } + + let model = XmlStruct { + color: Enum::Field(String::from("some_text")), + }; + + let content = "some_text"; + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, XmlStruct); + + let model = XmlStruct { + color: Enum::FullPath(String::from("some_text")), + }; + + let content = "some_text"; + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, XmlStruct); + + let model = XmlStruct { + color: Enum::Integer(56), + }; + + let content = "56"; + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, XmlStruct); + + let model = XmlStruct { + color: Enum::UserStruct(OtherStruct { fi: 24, se: 42 }), + }; + + let content = "2442"; + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, XmlStruct); + + let model = XmlStruct { + color: Enum::OptionString(Some(String::from("some_text"))), + }; + + let content = "some_text"; + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, XmlStruct); + + let model = XmlStruct { + color: Enum::OptionString(None), + }; + + let content = ""; + serialize_and_validate!(model, content); + // TODO + // deserialize_and_validate!(content, model, XmlStruct); + + let model = XmlStruct { + color: Enum::OptionUserStruct(Some(OtherStruct { fi: 12, se: 23 })), + }; + + let content = + "1223"; + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, XmlStruct); + + let model = XmlStruct { + color: Enum::OptionUserStruct(None), + }; + + let content = ""; + serialize_and_validate!(model, content); + // TODO + // deserialize_and_validate!(content, model, XmlStruct); + + let model = XmlStruct { + color: Enum::Strings(vec![String::from("abc"), String::from("def")]), + }; + + let content = "abcdef"; + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, XmlStruct); + + let model = XmlStruct { + color: Enum::Ints(vec![23, 45]), + }; + + let content = "2345"; + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, XmlStruct); + + let model = XmlStruct { + color: Enum::Structs(vec![ + OtherStruct { fi: 12, se: 23 }, + OtherStruct { fi: 34, se: 45 }, + ]), + }; + + let content = "12233445"; + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, XmlStruct); + + let model = XmlStruct { + color: Enum::ToRename(87), + }; + + let content = "87"; + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, XmlStruct); + + let model = XmlStruct { + color: Enum::ToRenameDots(84), + }; + + let content = "84"; + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, XmlStruct); +} diff --git a/yaserde/tests/ser_flatten.rs b/yaserde/tests/flatten.rs similarity index 62% rename from yaserde/tests/ser_flatten.rs rename to yaserde/tests/flatten.rs index 0127ed1..71274d6 100644 --- a/yaserde/tests/ser_flatten.rs +++ b/yaserde/tests/flatten.rs @@ -1,28 +1,15 @@ #[macro_use] +extern crate yaserde; +#[macro_use] extern crate yaserde_derive; -use std::io::Write; -use yaserde::ser::to_string; -use yaserde::YaSerialize; +use std::io::{Read, Write}; -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::() - ) - ); - }; -} +use yaserde::{YaDeserialize, YaSerialize}; #[test] -fn ser_flatten() { - #[derive(Default, PartialEq, Debug, YaSerialize)] +fn basic_flatten() { + #[derive(Default, PartialEq, Debug, YaDeserialize, YaSerialize)] struct DateTime { #[yaserde(flatten)] date: Date, @@ -31,7 +18,7 @@ fn ser_flatten() { kind: DateKind, } - #[derive(Default, PartialEq, Debug, YaSerialize)] + #[derive(Default, PartialEq, Debug, YaDeserialize, YaSerialize)] struct Date { year: i32, month: i32, @@ -42,18 +29,18 @@ fn ser_flatten() { optional_extra: Option, } - #[derive(Default, PartialEq, Debug, YaSerialize)] + #[derive(Default, PartialEq, Debug, YaDeserialize, YaSerialize)] pub struct Extra { week: i32, century: i32, } - #[derive(Default, PartialEq, Debug, YaSerialize)] + #[derive(Default, PartialEq, Debug, YaDeserialize, YaSerialize)] pub struct OptionalExtra { lunar_day: i32, } - #[derive(PartialEq, Debug, YaSerialize)] + #[derive(PartialEq, Debug, YaDeserialize, YaSerialize)] pub enum DateKind { #[yaserde(rename = "holidays")] Holidays(Vec), @@ -87,7 +74,6 @@ fn ser_flatten() { }; let content = r#" - 2020 1 @@ -101,12 +87,13 @@ fn ser_flatten() { Polar Bear Swim Day "#; - convert_and_validate!(model, content); + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, DateTime); } #[test] -fn ser_root_flatten_struct() { - #[derive(YaSerialize, PartialEq, Debug)] +fn root_flatten_struct() { + #[derive(YaDeserialize, YaSerialize, PartialEq, Debug)] #[yaserde(flatten)] pub struct Content { binary_data: String, @@ -117,12 +104,15 @@ fn ser_root_flatten_struct() { binary_data: "binary".to_string(), string_data: "string".to_string(), }; - let content = r#"binarystring"#; - convert_and_validate!(model, content); + + let content = "binarystring"; + + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, Content); } #[test] -fn ser_root_flatten_enum() { +fn root_flatten_enum() { #[derive(YaSerialize, PartialEq, Debug)] #[yaserde(flatten)] pub enum Content { @@ -143,14 +133,14 @@ fn ser_root_flatten_enum() { let model = Content::Binary(Binary { binary_data: "binary".to_string(), }); - let content = - r#"binary"#; - convert_and_validate!(model, content); + + let content = "binary"; + serialize_and_validate!(model, content); let model = Content::Data(Data { string_data: "string".to_string(), }); - let content = - r#"string"#; - convert_and_validate!(model, content); + + let content = "string"; + serialize_and_validate!(model, content); } diff --git a/yaserde/tests/namespace.rs b/yaserde/tests/namespace.rs new file mode 100644 index 0000000..dd53c9e --- /dev/null +++ b/yaserde/tests/namespace.rs @@ -0,0 +1,442 @@ +#[macro_use] +extern crate yaserde; +#[macro_use] +extern crate yaserde_derive; + +use std::io::{Read, Write}; +use yaserde::{YaDeserialize, YaSerialize}; + +#[test] +fn struct_simple_namespace() { + #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] + #[yaserde( + rename = "book", + prefix = "ns", + namespace = "ns: http://www.sample.com/ns/domain" + )] + pub struct Book { + #[yaserde(prefix = "ns")] + author: String, + #[yaserde(prefix = "ns")] + title: String, + } + + let content = r#" + + Antoine de Saint-Exupéry + Little prince + + "#; + + let model = Book { + author: String::from("Antoine de Saint-Exupéry"), + title: String::from("Little prince"), + }; + + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, Book); +} + +#[test] +fn struct_multiple_namespaces() { + #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] + #[yaserde( + rename = "book", + prefix = "ns", + namespace = "ns: http://www.sample.com/ns/domain", + namespace = "ns2: http://www.sample.com/ns/domain_2" + )] + pub struct Book { + #[yaserde(prefix = "ns")] + author: String, + #[yaserde(prefix = "ns2")] + title: String, + } + + let content = r#" + + Antoine de Saint-Exupéry + Little prince + + "#; + + let model = Book { + author: String::from("Antoine de Saint-Exupéry"), + title: String::from("Little prince"), + }; + + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, Book); +} + +#[test] +fn struct_partial_namespace() { + #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] + #[yaserde( + rename = "book", + prefix = "ns", + namespace = "ns: http://www.sample.com/ns/domain" + )] + pub struct Book { + author: String, + #[yaserde(prefix = "ns")] + title: String, + } + + let content = r#" + + Antoine de Saint-Exupéry + Little prince + + "#; + + let model = Book { + author: String::from("Antoine de Saint-Exupéry"), + title: String::from("Little prince"), + }; + + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, Book); +} + +#[test] +fn struct_sub_namespace_definition() { + #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] + #[yaserde( + rename = "book", + prefix = "ns", + namespace = "ns: http://www.sample.com/ns/domain", + namespace = "ns2: http://www.sample.com/ns/domain_2" + )] + pub struct Book { + #[yaserde(prefix = "ns")] + author: String, + #[yaserde(prefix = "ns2", namespace = "ns2: http://www.sample.com/ns/domain_2")] + title: String, + } + + let content = r#" + + Antoine de Saint-Exupéry + Little prince + + "#; + + let model = Book { + author: String::from("Antoine de Saint-Exupéry"), + title: String::from("Little prince"), + }; + + // TODO support namespace for attribute to specify local namespace + // serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, Book); +} + +#[test] +fn struct_namespace_nested() { + #[derive(Debug, Default, PartialEq, YaDeserialize, YaSerialize)] + #[yaserde(prefix = "nsa", namespace = "nsa: http://www.sample.com/ns/a")] + struct A { + #[yaserde(prefix = "nsa")] + alpha: i32, + } + + #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] + #[yaserde(prefix = "nsb", namespace = "nsb: http://www.sample.com/ns/b")] + struct B { + // Note that name `nested` resides in `nsb` though it has a type from `nsa` + #[yaserde(prefix = "nsb")] + nested: A, + } + + let content = r#" + + + 32 + + + "#; + + let model = B { + nested: A { alpha: 32 }, + }; + + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, B); +} + +#[test] +fn struct_namespace_nested_defined_at_root() { + #[derive(Debug, Default, PartialEq, YaDeserialize, YaSerialize)] + #[yaserde(prefix = "nsa", namespace = "nsa: http://www.sample.com/ns/a")] + struct A { + #[yaserde(prefix = "nsa")] + alpha: i32, + } + + #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] + #[yaserde( + prefix = "nsb", + namespace = "nsb: http://www.sample.com/ns/b" + namespace = "nsa: http://www.sample.com/ns/a" + )] + struct B { + // Note that name `nested` resides in `nsb` though it has a type from `nsa` + #[yaserde(prefix = "nsb")] + nested: A, + } + + let content = r#" + + + 32 + + + "#; + + let model = B { + nested: A { alpha: 32 }, + }; + + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, B); +} + +#[test] +fn struct_attribute_namespace() { + #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] + #[yaserde( + rename = "root", + namespace = "ns1: http://www.sample.com/ns/domain1", + namespace = "ns2: http://www.sample.com/ns/domain2" + )] + pub struct XmlStruct { + #[yaserde(prefix = "ns1")] + item_1: String, + #[yaserde(attribute, prefix = "ns2")] + item_2: String, + } + + let model = XmlStruct { + item_1: "something 1".to_string(), + item_2: "something 2".to_string(), + }; + + let content = r#" + + something 1 + + "#; + + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, XmlStruct); +} + +#[test] +fn struct_implicit_default_namespace() { + #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] + #[yaserde( + rename = "tt", + namespace = "http://www.w3.org/ns/ttml", + namespace = "ttm: http://www.w3.org/ns/ttml#metadata" + )] + pub struct XmlStruct { + item: String, + } + + let model = XmlStruct { + item: "something".to_string(), + }; + + let content = r#"something"#; + serialize_and_validate!(model, content); + // TODO + // deserialize_and_validate!(content, model, XmlStruct); +} + +#[test] +fn struct_explicit_default_namespace() { + #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] + #[yaserde( + rename = "tt", + default_namespace = "ttml", + namespace = "ttml: http://www.w3.org/ns/ttml", + namespace = "ttm: http://www.w3.org/ns/ttml#metadata" + )] + pub struct XmlStruct { + item: String, + } + + let model = XmlStruct { + item: "something".to_string(), + }; + + let content = r#"something"#; + serialize_and_validate!(model, content); + // TODO + // deserialize_and_validate!(content, model, XmlStruct); +} + +#[test] +fn struct_default_namespace_via_attribute_with_prefix() { + #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] + #[yaserde( + rename = "tt", + prefix = "TTML", + default_namespace = "TTML", + namespace = "TTML: http://www.w3.org/ns/ttml", + namespace = "ttm: http://www.w3.org/ns/ttml#metadata" + )] + pub struct XmlStruct { + #[yaserde(prefix = "TTML")] + item: String, + } + + let model = XmlStruct { + item: "something".to_string(), + }; + + let content = r#"something"#; + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, XmlStruct); +} + +#[test] +fn enum_namespace() { + #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] + #[yaserde( + rename = "root", + prefix = "ns", + namespace = "ns: http://www.sample.com/ns/domain" + )] + pub enum XmlStruct { + #[yaserde(prefix = "ns")] + Item, + } + + impl Default for XmlStruct { + fn default() -> XmlStruct { + XmlStruct::Item + } + } + + let content = r#" + + ns:Item + + "#; + + let model = XmlStruct::Item; + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, XmlStruct); +} + +#[test] +fn enum_multi_namespaces() { + #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] + #[yaserde( + rename = "root", + namespace = "ns1: http://www.sample.com/ns/domain1", + namespace = "ns2: http://www.sample.com/ns/domain2" + )] + pub enum XmlStruct { + #[yaserde(prefix = "ns1")] + Item1, + #[yaserde(prefix = "ns2")] + Item2, + } + + impl Default for XmlStruct { + fn default() -> XmlStruct { + XmlStruct::Item1 + } + } + + let model = XmlStruct::Item1; + let content = r#" + + ns1:Item1 + + "#; + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, XmlStruct); + + let model = XmlStruct::Item2; + let content = r#" + + ns2:Item2 + + "#; + serialize_and_validate!(model, content); + // TODO + // deserialize_and_validate!(content, model, XmlStruct); +} + +#[test] +fn enum_attribute_namespace() { + #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] + #[yaserde( + rename = "root", + prefix = "ns", + namespace = "ns: http://www.sample.com/ns/domain" + )] + pub enum XmlStruct { + #[yaserde(prefix = "ns")] + Item, + #[yaserde(prefix = "ns")] + ItemWithField(String), + } + + impl Default for XmlStruct { + fn default() -> XmlStruct { + XmlStruct::Item + } + } + + let content = r#" + + ns:Item + + "#; + + let model = XmlStruct::Item; + serialize_and_validate!(model, content); + deserialize_and_validate!(content, model, XmlStruct); + + let model = XmlStruct::ItemWithField("Value".to_string()); + + let content = r#"Value"#; + serialize_and_validate!(model, content); + // TODO + // deserialize_and_validate!(content, model, XmlStruct); +} + +#[test] +fn struct_bad_namespace() { + #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] + #[yaserde( + rename = "book", + prefix = "ns", + namespace = "ns: http://www.sample.com/ns/domain", + namespace = "ns2: http://www.sample.com/ns/domain_2" + )] + pub struct Book { + #[yaserde(prefix = "ns")] + author: String, + #[yaserde(prefix = "ns2", namespace = "ns2: http://www.sample.com/ns/domain_2")] + title: String, + } + + let content = r#" + + Antoine de Saint-Exupéry + Little prince + + "#; + + let loaded: Result = yaserde::de::from_str(content); + assert_eq!( + loaded, + Err("bad namespace for book, found http://www.sample.com/ns/domain2".to_string()) + ); +} diff --git a/yaserde/tests/option.rs b/yaserde/tests/option.rs new file mode 100644 index 0000000..cc9a4bd --- /dev/null +++ b/yaserde/tests/option.rs @@ -0,0 +1,104 @@ +#[macro_use] +extern crate yaserde; +#[macro_use] +extern crate yaserde_derive; + +use std::io::{Read, Write}; +use yaserde::{YaDeserialize, YaSerialize}; + +#[test] +fn basic_option_types() { + test_for_type!(Option::, Some("test".to_string()), Some("test")); + test_for_type!(Option::, None, None); + test_for_type!(Option::, Some(true), Some("true")); + test_for_type!(Option::, None, None); + test_for_type!(Option::, Some(12 as u8), Some("12")); + test_for_type!(Option::, None, None); + test_for_type!(Option::, Some(12 as i8), Some("12")); + test_for_type!(Option::, Some(-12 as i8), Some("-12")); + test_for_type!(Option::, None, None); + test_for_type!(Option::, Some(12 as u16), Some("12")); + test_for_type!(Option::, None, None); + test_for_type!(Option::, Some(12 as i16), Some("12")); + test_for_type!(Option::, Some(-12 as i16), Some("-12")); + test_for_type!(Option::, None, None); + test_for_type!(Option::, Some(12 as u32), Some("12")); + test_for_type!(Option::, None, None); + test_for_type!(Option::, Some(12 as i32), Some("12")); + test_for_type!(Option::, Some(-12 as i32), Some("-12")); + test_for_type!(Option::, None, None); + test_for_type!(Option::, Some(12 as u64), Some("12")); + test_for_type!(Option::, None, None); + test_for_type!(Option::, Some(12 as i64), Some("12")); + test_for_type!(Option::, Some(-12 as i64), Some("-12")); + test_for_type!(Option::, None, None); + test_for_type!(Option::, Some(-12.5 as f32), Some("-12.5")); + test_for_type!(Option::, None, None); + test_for_type!(Option::, Some(-12.5 as f64), Some("-12.5")); + test_for_type!(Option::, None, None); + + // TODO + // test_for_type!(Option::>, None, None); + // test_for_type!(Option::>, Some(vec![0]), Some("0")); + // test_for_type!(Option::>, None, None); + // test_for_type!(Option::>, Some(vec!["test".to_string()]), Some("test")); + + test_for_attribute_type!(Option::, Some("test".to_string()), Some("test")); + test_for_attribute_type!(Option::, None, None); + test_for_attribute_type!(Option::, Some(true), Some("true")); + test_for_attribute_type!(Option::, None, None); + test_for_attribute_type!(Option::, Some(12 as u8), Some("12")); + test_for_attribute_type!(Option::, None, None); + test_for_attribute_type!(Option::, Some(12 as i8), Some("12")); + test_for_attribute_type!(Option::, Some(-12 as i8), Some("-12")); + test_for_attribute_type!(Option::, None, None); + test_for_attribute_type!(Option::, Some(12 as u16), Some("12")); + test_for_attribute_type!(Option::, None, None); + test_for_attribute_type!(Option::, Some(12 as i16), Some("12")); + test_for_attribute_type!(Option::, Some(-12 as i16), Some("-12")); + test_for_attribute_type!(Option::, None, None); + test_for_attribute_type!(Option::, Some(12 as u32), Some("12")); + test_for_attribute_type!(Option::, None, None); + test_for_attribute_type!(Option::, Some(12 as i32), Some("12")); + test_for_attribute_type!(Option::, Some(-12 as i32), Some("-12")); + test_for_attribute_type!(Option::, None, None); + test_for_attribute_type!(Option::, Some(12 as u64), Some("12")); + test_for_attribute_type!(Option::, None, None); + test_for_attribute_type!(Option::, Some(12 as i64), Some("12")); + test_for_attribute_type!(Option::, Some(-12 as i64), Some("-12")); + test_for_attribute_type!(Option::, None, None); + test_for_attribute_type!(Option::, Some(-12.5 as f32), Some("-12.5")); + test_for_attribute_type!(Option::, None, None); + test_for_attribute_type!(Option::, Some(-12.5 as f64), Some("-12.5")); + test_for_attribute_type!(Option::, None, None); +} + +#[test] +fn option_struct() { + #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] + struct Test { + field: SubTest, + } + + #[derive(Debug, PartialEq, YaDeserialize, YaSerialize)] + struct SubTest { + content: Option, + } + + impl Default for SubTest { + fn default() -> Self { + SubTest { content: None } + } + } + + test_for_type!( + Option::, + Some(Test { + field: SubTest { + content: Some("value".to_string()) + } + }), + Some("value") + ); + test_for_type!(Option::, None, None); +} diff --git a/yaserde/tests/ser_default.rs b/yaserde/tests/ser_default.rs deleted file mode 100644 index b461a7e..0000000 --- a/yaserde/tests/ser_default.rs +++ /dev/null @@ -1,103 +0,0 @@ -#[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))); - }; -} - -#[test] -fn ser_default_field_string() { - fn default_string() -> String { - "my_default_value".to_string() - } - - #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde(root = "base")] - pub struct XmlStruct { - #[yaserde(default = "default_string")] - background: String, - } - - let content = ""; - convert_and_validate!( - XmlStruct { - background: "my_default_value".to_string(), - }, - content - ); - let content = - "my_value"; - convert_and_validate!( - XmlStruct { - background: "my_value".to_string(), - }, - content - ); -} - -#[test] -fn ser_default_field_boolean() { - fn default_boolean() -> bool { - true - } - - #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde(root = "base")] - pub struct XmlStruct { - #[yaserde(default = "default_boolean")] - background: bool, - } - - let content = ""; - convert_and_validate!(XmlStruct { background: true }, content); - - let content = - "false"; - convert_and_validate!(XmlStruct { background: false }, content); -} - -#[test] -fn ser_default_field_number() { - fn default_number() -> u8 { - 6 - } - - #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde(root = "base")] - pub struct XmlStruct { - #[yaserde(default = "default_number")] - background: u8, - } - - let content = ""; - convert_and_validate!(XmlStruct { background: 6 }, content); -} - -#[test] -fn ser_default_attribute_string() { - fn default_string() -> String { - "my_default_value".to_string() - } - - #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde(root = "base")] - pub struct XmlStruct { - #[yaserde(attribute, default = "default_string")] - background: String, - } - - let content = ""; - convert_and_validate!( - XmlStruct { - background: "my_default_value".to_string(), - }, - content - ); -} diff --git a/yaserde/tests/ser_enum.rs b/yaserde/tests/ser_enum.rs deleted file mode 100644 index c5c38e3..0000000 --- a/yaserde/tests/ser_enum.rs +++ /dev/null @@ -1,285 +0,0 @@ -#[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_enum() { - #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde(root = "base")] - pub struct XmlStruct { - color: Color, - } - - #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde(root = "color")] - pub enum Color { - White, - Black, - #[yaserde(rename = "custom")] - Custom { - enabled: String, - u8_value: u8, - i8_value: i8, - u16_value: u16, - i16_value: i16, - u32_value: u32, - i32_value: i32, - u64_value: u64, - i64_value: i64, - f32_value: f32, - f64_value: f64, - color: RGBColor, - alpha: Alpha, - alphas: Vec, - }, - } - - impl Default for Color { - fn default() -> Color { - Color::White - } - } - - assert_eq!(Color::default(), Color::White); - - #[derive(YaSerialize, PartialEq, Debug)] - pub struct RGBColor { - red: String, - green: String, - blue: String, - } - - #[derive(YaSerialize, PartialEq, Debug)] - pub enum Alpha { - Transparent, - Opaque, - } - - let model = XmlStruct { - color: Color::Black, - }; - - let content = r#"Black"#; - convert_and_validate!(model, content); - - let model = XmlStruct { - color: Color::Custom { - enabled: "true".to_string(), - u8_value: 8, - i8_value: -8, - u16_value: 16, - i16_value: -16, - u32_value: 32, - i32_value: -32, - u64_value: 64, - i64_value: -64, - f32_value: 32.0, - f64_value: 64.0, - color: RGBColor { - red: "0".to_string(), - green: "128".to_string(), - blue: "255".to_string(), - }, - alpha: Alpha::Opaque, - alphas: vec![Alpha::Opaque, Alpha::Transparent], - }, - }; - - let content = r#" - -true -8 --8 -16 --16 -32 --32 -64 --64 -32 -64 -0128255 -Opaque -Opaque -Transparent - -"#; - - convert_and_validate!(model, content); -} - -#[test] -fn ser_attribute_enum() { - #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde(root = "base")] - pub struct XmlStruct { - #[yaserde(attribute)] - color: Color, - } - - #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde(root = "color")] - pub enum Color { - #[yaserde(rename = "pink")] - Pink, - } - - let model = XmlStruct { color: Color::Pink }; - - let content = r#""#; - convert_and_validate!(model, content); -} - -#[test] -fn ser_unnamed_enum() { - #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde(root = "base")] - pub struct XmlStruct { - color: Enum, - } - - #[derive(YaSerialize, PartialEq, Debug, Default)] - pub struct OtherStruct { - fi: i32, - se: i32, - } - - #[derive(YaSerialize, PartialEq, Debug)] - pub enum Enum { - Simple, - Field(String), - FullPath(std::string::String), - Integer(i32), - UserStruct(OtherStruct), - OptionString(Option), - OptionUserStruct(Option), - Strings(Vec), - Ints(Vec), - Structs(Vec), - #[yaserde(rename = "renamed")] - ToRename(u32), - #[yaserde(rename = "renamed.with.dots")] - ToRenameDots(u32), - } - - impl Default for Enum { - fn default() -> Enum { - Enum::Simple - } - } - - let model = XmlStruct { - color: Enum::Field(String::from("some_text")), - }; - - let content = - r#"some_text"#; - convert_and_validate!(model, content); - - let model = XmlStruct { - color: Enum::FullPath(String::from("some_text")), - }; - - let content = r#"some_text"#; - convert_and_validate!(model, content); - - let model = XmlStruct { - color: Enum::Integer(56), - }; - - let content = - r#"56"#; - convert_and_validate!(model, content); - - let model = XmlStruct { - color: Enum::UserStruct(OtherStruct { fi: 24, se: 42 }), - }; - - let content = r#"2442"#; - convert_and_validate!(model, content); - - let model = XmlStruct { - color: Enum::OptionString(Some(String::from("some_text"))), - }; - - let content = r#"some_text"#; - convert_and_validate!(model, content); - - let model = XmlStruct { - color: Enum::OptionString(None), - }; - - let content = r#""#; - convert_and_validate!(model, content); - - let model = XmlStruct { - color: Enum::OptionUserStruct(Some(OtherStruct { fi: 12, se: 23 })), - }; - - let content = r#"1223"#; - convert_and_validate!(model, content); - - let model = XmlStruct { - color: Enum::OptionUserStruct(None), - }; - - let content = r#""#; - convert_and_validate!(model, content); - - let model = XmlStruct { - color: Enum::Strings(vec![String::from("abc"), String::from("def")]), - }; - - let content = r#"abcdef"#; - convert_and_validate!(model, content); - - let model = XmlStruct { - color: Enum::Ints(vec![23, 45]), - }; - - let content = r#"2345"#; - convert_and_validate!(model, content); - - let model = XmlStruct { - color: Enum::Structs(vec![ - OtherStruct { fi: 12, se: 23 }, - OtherStruct { fi: 34, se: 45 }, - ]), - }; - - let content = r#"12233445"#; - convert_and_validate!(model, content); - - let model = XmlStruct { - color: Enum::ToRename(87), - }; - - let content = - r#"87"#; - convert_and_validate!(model, content); - - let model = XmlStruct { - color: Enum::ToRenameDots(84), - }; - - let content = r#"84"#; - convert_and_validate!(model, content); -} diff --git a/yaserde/tests/ser_namespace.rs b/yaserde/tests/ser_namespace.rs deleted file mode 100644 index 5af32e8..0000000 --- a/yaserde/tests/ser_namespace.rs +++ /dev/null @@ -1,235 +0,0 @@ -#[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_struct_namespace() { - #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde( - root = "root", - prefix = "ns", - namespace = "ns: http://www.sample.com/ns/domain" - )] - pub struct XmlStruct { - #[yaserde(prefix = "ns")] - item: String, - } - - let model = XmlStruct { - item: "something".to_string(), - }; - - let content = "something"; - convert_and_validate!(model, content); -} - -#[test] -fn ser_enum_namespace() { - #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde( - root = "root", - prefix = "ns", - namespace = "ns: http://www.sample.com/ns/domain" - )] - pub enum XmlStruct { - #[yaserde(prefix = "ns")] - Item, - #[yaserde(prefix = "ns")] - ItemWithField(String), - } - - let model = XmlStruct::Item; - - let content = "ns:Item"; - convert_and_validate!(model, content); - - let model = XmlStruct::ItemWithField("Value".to_string()); - - let content = "Value"; - convert_and_validate!(model, content); -} - -#[test] -fn ser_struct_multi_namespace() { - #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde( - root = "root", - namespace = "ns1: http://www.sample.com/ns/domain1", - namespace = "ns2: http://www.sample.com/ns/domain2" - )] - pub struct XmlStruct { - #[yaserde(prefix = "ns1")] - item_1: String, - #[yaserde(prefix = "ns2")] - item_2: String, - } - - let model = XmlStruct { - item_1: "something 1".to_string(), - item_2: "something 2".to_string(), - }; - - let content = "something 1something 2"; - convert_and_validate!(model, content); -} - -#[test] -fn ser_enum_multi_namespace() { - #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde( - root = "root", - namespace = "ns1: http://www.sample.com/ns/domain1", - namespace = "ns2: http://www.sample.com/ns/domain2" - )] - pub enum XmlStruct { - #[yaserde(prefix = "ns1")] - Item1, - #[yaserde(prefix = "ns2")] - Item2, - } - - let model1 = XmlStruct::Item1; - let content = "ns1:Item1"; - convert_and_validate!(model1, content); - let model2 = XmlStruct::Item2; - let content = "ns2:Item2"; - convert_and_validate!(model2, content); -} - -#[test] -fn ser_struct_attribute_namespace() { - #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde( - root = "root", - namespace = "ns1: http://www.sample.com/ns/domain1", - namespace = "ns2: http://www.sample.com/ns/domain2" - )] - pub struct XmlStruct { - #[yaserde(prefix = "ns1")] - item_1: String, - #[yaserde(attribute, prefix = "ns2")] - item_2: String, - } - - let model = XmlStruct { - item_1: "something 1".to_string(), - item_2: "something 2".to_string(), - }; - - let content = "something 1"; - convert_and_validate!(model, content); -} - -#[test] -fn ser_struct_default_namespace() { - #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde( - root = "tt", - namespace = "http://www.w3.org/ns/ttml", - namespace = "ttm: http://www.w3.org/ns/ttml#metadata" - )] - pub struct XmlStruct { - item: String, - } - - let model = XmlStruct { - item: "something".to_string(), - }; - - let content = "something"; - convert_and_validate!(model, content); -} - -#[test] -fn ser_struct_default_namespace_via_attribute() { - #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde( - root = "tt", - default_namespace = "ttml", - namespace = "ttml: http://www.w3.org/ns/ttml", - namespace = "ttm: http://www.w3.org/ns/ttml#metadata" - )] - pub struct XmlStruct { - item: String, - } - - let model = XmlStruct { - item: "something".to_string(), - }; - - let content = "something"; - convert_and_validate!(model, content); -} - -#[test] -fn ser_struct_default_namespace_via_attribute_with_prefix() { - #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde( - root = "tt", - prefix = "TTML", - default_namespace = "TTML", - namespace = "TTML: http://www.w3.org/ns/ttml", - namespace = "ttm: http://www.w3.org/ns/ttml#metadata" - )] - pub struct XmlStruct { - #[yaserde(prefix = "TTML")] - item: String, - } - - let model = XmlStruct { - item: "something".to_string(), - }; - - let content = "something"; - convert_and_validate!(model, content); -} - -#[test] -fn ser_struct_namespace_nested() { - #[derive(YaSerialize, Default, PartialEq, Debug)] - #[yaserde(prefix = "nsa", namespace = "nsa: http://www.sample.com/ns/a")] - struct A { - #[yaserde(prefix = "nsa")] - alpha: i32, - } - - #[derive(YaSerialize, Default, PartialEq, Debug)] - #[yaserde(prefix = "nsb", namespace = "nsb: http://www.sample.com/ns/b")] - struct B { - // Note that name `nested` resides in `nsb` though it has a type from `nsa` - #[yaserde(prefix = "nsb")] - nested: A, - } - - convert_and_validate!( - B { - nested: A { alpha: 32 } - }, - r#" - - - - 32 - - - "# - ); -} diff --git a/yaserde/tests/ser_option.rs b/yaserde/tests/ser_option.rs deleted file mode 100644 index 26f1c08..0000000 --- a/yaserde/tests/ser_option.rs +++ /dev/null @@ -1,147 +0,0 @@ -#[macro_use] -extern crate yaserde_derive; - -use std::io::Write; -use yaserde::ser::to_string; -use yaserde::YaSerialize; - -macro_rules! convert_and_validate { - ($type: ty, $value: expr, $content: expr) => {{ - #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde(root = "data")] - pub struct Data { - item: Option<$type>, - } - let model = Data { item: $value }; - - let data: Result = to_string(&model); - - let content = if let Some(str_value) = $content { - "".to_string() + str_value + "" - } else { - "".to_string() - }; - - let content = String::from("") + &content; - assert_eq!(data, Ok(content)); - }}; -} - -macro_rules! convert_and_validate_as_attribute { - ($type: ty, $value: expr, $content: expr) => {{ - #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde(root = "data")] - pub struct Data { - #[yaserde(attribute)] - item: Option<$type>, - } - let model = Data { item: $value }; - - let data: Result = to_string(&model); - - let content = if let Some(str_value) = $content { - "" - } else { - "".to_string() - }; - - let content = String::from("") + &content; - assert_eq!(data, Ok(content)); - }}; -} - -#[test] -fn ser_option() { - convert_and_validate!(String, Some("test".to_string()), Some("test")); - convert_and_validate!(String, None, None); - convert_and_validate!(bool, Some(true), Some("true")); - convert_and_validate!(bool, None, None); - convert_and_validate!(u8, Some(12 as u8), Some("12")); - convert_and_validate!(u8, None, None); - convert_and_validate!(i8, Some(12 as i8), Some("12")); - convert_and_validate!(i8, Some(-12 as i8), Some("-12")); - convert_and_validate!(i8, None, None); - convert_and_validate!(u16, Some(12 as u16), Some("12")); - convert_and_validate!(u16, None, None); - convert_and_validate!(i16, Some(12 as i16), Some("12")); - convert_and_validate!(i16, Some(-12 as i16), Some("-12")); - convert_and_validate!(i16, None, None); - convert_and_validate!(u32, Some(12 as u32), Some("12")); - convert_and_validate!(u32, None, None); - convert_and_validate!(i32, Some(12 as i32), Some("12")); - convert_and_validate!(i32, Some(-12 as i32), Some("-12")); - convert_and_validate!(i32, None, None); - convert_and_validate!(u64, Some(12 as u64), Some("12")); - convert_and_validate!(u64, None, None); - convert_and_validate!(i64, Some(12 as i64), Some("12")); - convert_and_validate!(i64, Some(-12 as i64), Some("-12")); - convert_and_validate!(i64, None, None); - convert_and_validate!(f32, Some(-12.5 as f32), Some("-12.5")); - convert_and_validate!(f32, None, None); - convert_and_validate!(f64, Some(-12.5 as f64), Some("-12.5")); - convert_and_validate!(f64, None, None); - - convert_and_validate!(Vec, None, None); - convert_and_validate!(Vec, Some(vec![0]), Some("0")); - convert_and_validate!(Vec, None, None); - convert_and_validate!(Vec, Some(vec!["test".to_string()]), Some("test")); - - convert_and_validate_as_attribute!(String, Some("test".to_string()), Some("test")); - convert_and_validate_as_attribute!(String, None, None); - convert_and_validate_as_attribute!(bool, Some(true), Some("true")); - convert_and_validate_as_attribute!(bool, None, None); - convert_and_validate_as_attribute!(u8, Some(12 as u8), Some("12")); - convert_and_validate_as_attribute!(u8, None, None); - convert_and_validate_as_attribute!(i8, Some(12 as i8), Some("12")); - convert_and_validate_as_attribute!(i8, Some(-12 as i8), Some("-12")); - convert_and_validate_as_attribute!(i8, None, None); - convert_and_validate_as_attribute!(u16, Some(12 as u16), Some("12")); - convert_and_validate_as_attribute!(u16, None, None); - convert_and_validate_as_attribute!(i16, Some(12 as i16), Some("12")); - convert_and_validate_as_attribute!(i16, Some(-12 as i16), Some("-12")); - convert_and_validate_as_attribute!(i16, None, None); - convert_and_validate_as_attribute!(u32, Some(12 as u32), Some("12")); - convert_and_validate_as_attribute!(u32, None, None); - convert_and_validate_as_attribute!(i32, Some(12 as i32), Some("12")); - convert_and_validate_as_attribute!(i32, Some(-12 as i32), Some("-12")); - convert_and_validate_as_attribute!(i32, None, None); - convert_and_validate_as_attribute!(u64, Some(12 as u64), Some("12")); - convert_and_validate_as_attribute!(u64, None, None); - convert_and_validate_as_attribute!(i64, Some(12 as i64), Some("12")); - convert_and_validate_as_attribute!(i64, Some(-12 as i64), Some("-12")); - convert_and_validate_as_attribute!(i64, None, None); - convert_and_validate_as_attribute!(f32, Some(-12.5 as f32), Some("-12.5")); - convert_and_validate_as_attribute!(f32, None, None); - convert_and_validate_as_attribute!(f64, Some(-12.5 as f64), Some("-12.5")); - convert_and_validate_as_attribute!(f64, None, None); -} - -#[test] -fn de_option_struct() { - #[derive(YaSerialize, Debug, PartialEq)] - struct Test { - field: SubTest, - } - - #[derive(YaSerialize, Debug, PartialEq)] - struct SubTest { - content: Option, - } - - impl Default for SubTest { - fn default() -> Self { - SubTest { content: None } - } - } - - convert_and_validate!( - Test, - Some(Test { - field: SubTest { - content: Some("value".to_string()) - } - }), - Some("value") - ); - convert_and_validate!(Test, None, None); -} diff --git a/yaserde/tests/ser_type.rs b/yaserde/tests/ser_type.rs deleted file mode 100644 index 1506cc2..0000000 --- a/yaserde/tests/ser_type.rs +++ /dev/null @@ -1,83 +0,0 @@ -#[macro_use] -extern crate yaserde_derive; - -use std::io::Write; -use yaserde::ser::to_string; -use yaserde::YaSerialize; - -macro_rules! convert_and_validate { - ($type: ty, $value: expr, $content: expr) => {{ - #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde(root = "data")] - pub struct Data { - item: $type, - } - let model = Data { item: $value }; - - let data: Result = to_string(&model); - let content = if $content == "" { - String::from("") - } else { - String::from("") - + $content - + "" - }; - assert_eq!(data, Ok(content)); - }}; -} - -macro_rules! convert_and_validate_as_attribute { - ($type: ty, $value: expr, $content: expr) => {{ - #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde(root = "data")] - pub struct Data { - #[yaserde(attribute)] - item: $type, - } - let model = Data { item: $value }; - - let data: Result = to_string(&model); - let content = - String::from(""; - assert_eq!(data, Ok(content)); - }}; -} - -#[test] -fn ser_type() { - convert_and_validate!(String, "test".to_string(), "test"); - convert_and_validate!(bool, true, "true"); - convert_and_validate!(u8, 12 as u8, "12"); - convert_and_validate!(i8, 12 as i8, "12"); - convert_and_validate!(i8, -12 as i8, "-12"); - convert_and_validate!(u16, 12 as u16, "12"); - convert_and_validate!(i16, 12 as i16, "12"); - convert_and_validate!(i16, -12 as i16, "-12"); - convert_and_validate!(u32, 12 as u32, "12"); - convert_and_validate!(i32, 12 as i32, "12"); - convert_and_validate!(i32, -12 as i32, "-12"); - convert_and_validate!(u64, 12 as u64, "12"); - convert_and_validate!(i64, 12 as i64, "12"); - convert_and_validate!(i64, -12 as i64, "-12"); - convert_and_validate!(f32, -12.5 as f32, "-12.5"); - convert_and_validate!(f64, -12.5 as f64, "-12.5"); - convert_and_validate!(Vec, vec![], ""); - convert_and_validate!(Vec, vec!["test".to_string()], "test"); - - convert_and_validate_as_attribute!(String, "test".to_string(), "test"); - convert_and_validate_as_attribute!(bool, true, "true"); - convert_and_validate_as_attribute!(u8, 12 as u8, "12"); - convert_and_validate_as_attribute!(i8, 12 as i8, "12"); - convert_and_validate_as_attribute!(i8, -12 as i8, "-12"); - convert_and_validate_as_attribute!(u16, 12 as u16, "12"); - convert_and_validate_as_attribute!(i16, 12 as i16, "12"); - convert_and_validate_as_attribute!(i16, -12 as i16, "-12"); - convert_and_validate_as_attribute!(u32, 12 as u32, "12"); - convert_and_validate_as_attribute!(i32, 12 as i32, "12"); - convert_and_validate_as_attribute!(i32, -12 as i32, "-12"); - convert_and_validate_as_attribute!(u64, 12 as u64, "12"); - convert_and_validate_as_attribute!(i64, 12 as i64, "12"); - convert_and_validate_as_attribute!(i64, -12 as i64, "-12"); - convert_and_validate_as_attribute!(f32, -12.5 as f32, "-12.5"); - convert_and_validate_as_attribute!(f64, -12.5 as f64, "-12.5"); -} diff --git a/yaserde/tests/serializer.rs b/yaserde/tests/serializer.rs index c3ff11b..01b7921 100644 --- a/yaserde/tests/serializer.rs +++ b/yaserde/tests/serializer.rs @@ -1,29 +1,15 @@ #[macro_use] +extern crate yaserde; +#[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_basic() { #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde(root = "base")] + #[yaserde(rename = "base")] pub struct XmlStruct { item: String, } @@ -32,14 +18,14 @@ fn ser_basic() { item: "something".to_string(), }; - let content = "something"; - convert_and_validate!(model, content); + let content = "something"; + serialize_and_validate!(model, content); } #[test] fn ser_list_of_items() { #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde(root = "base")] + #[yaserde(rename = "base")] pub struct XmlStruct { items: Vec, } @@ -48,17 +34,17 @@ fn ser_list_of_items() { items: vec!["something1".to_string(), "something2".to_string()], }; - let content = "something1something2"; - convert_and_validate!(model, content); + let content = "something1something2"; + serialize_and_validate!(model, content); #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde(root = "base")] + #[yaserde(rename = "base")] pub struct XmlStructOfStruct { items: Vec, } #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde(root = "items")] + #[yaserde(rename = "items")] pub struct SubStruct { field: String, } @@ -74,14 +60,15 @@ fn ser_list_of_items() { ], }; - let content = "something1something2"; - convert_and_validate!(model2, content); + let content = + "something1something2"; + serialize_and_validate!(model2, content); } #[test] fn ser_attributes() { #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde(root = "base")] + #[yaserde(rename = "base")] pub struct XmlStruct { #[yaserde(attribute)] item: String, @@ -89,7 +76,7 @@ fn ser_attributes() { } #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde(root = "sub")] + #[yaserde(rename = "sub")] pub struct SubStruct { #[yaserde(attribute)] subitem: String, @@ -117,8 +104,8 @@ fn ser_attributes() { }, }; - let content = ""; - convert_and_validate!(model, content); + let content = r#""#; + serialize_and_validate!(model, content); } #[test] @@ -158,24 +145,20 @@ fn ser_attributes_complex() { } } - convert_and_validate!( + serialize_and_validate!( Struct { attr_option_string: None, attr_option_enum: None, }, - r#" - - - "# + "" ); - convert_and_validate!( + serialize_and_validate!( Struct { attr_option_string: Some("some value".to_string()), attr_option_enum: Some(other_mod::AttrEnum::Variant2), }, r#" - "# ); @@ -184,7 +167,7 @@ fn ser_attributes_complex() { #[test] fn ser_rename() { #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde(root = "base")] + #[yaserde(rename = "base")] pub struct XmlStruct { #[yaserde(attribute, rename = "Item")] item: String, @@ -195,7 +178,7 @@ fn ser_rename() { } #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde(root = "sub")] + #[yaserde(rename = "sub")] pub struct SubStruct { #[yaserde(attribute, rename = "sub_item")] subitem: String, @@ -224,14 +207,14 @@ fn ser_rename() { version: "2.0.2".into(), }; - let content = "2.0.2"; - convert_and_validate!(model, content); + let content = r#"2.0.2"#; + serialize_and_validate!(model, content); } #[test] fn ser_text_content_with_attributes() { #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde(root = "base")] + #[yaserde(rename = "base")] pub struct XmlStruct { #[yaserde(attribute, rename = "Item")] item: String, @@ -240,7 +223,7 @@ fn ser_text_content_with_attributes() { } #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde(root = "sub")] + #[yaserde(rename = "sub")] pub struct SubStruct { #[yaserde(attribute, rename = "sub_item")] subitem: String, @@ -273,14 +256,14 @@ fn ser_text_content_with_attributes() { }, }; - let content = "text_content"; - convert_and_validate!(model, content); + let content = r#"text_content"#; + serialize_and_validate!(model, content); } #[test] fn ser_name_issue_21() { #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde(root = "base")] + #[yaserde(rename = "base")] pub struct XmlStruct { name: String, } @@ -289,8 +272,8 @@ fn ser_name_issue_21() { name: "something".to_string(), }; - let content = "something"; - convert_and_validate!(model, content); + let content = "something"; + serialize_and_validate!(model, content); } #[test] @@ -326,6 +309,6 @@ fn ser_custom() { month: 1, day: Day { value: 5 }, }; - let content = "2020110"; - convert_and_validate!(model, content); + let content = "2020110"; + serialize_and_validate!(model, content); } diff --git a/yaserde/tests/ser_skip.rs b/yaserde/tests/skip_if.rs similarity index 68% rename from yaserde/tests/ser_skip.rs rename to yaserde/tests/skip_if.rs index 53c6be0..e7c853e 100644 --- a/yaserde/tests/ser_skip.rs +++ b/yaserde/tests/skip_if.rs @@ -1,30 +1,25 @@ #[macro_use] +extern crate yaserde; +#[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_skip_serializing_if_for_struct() { +fn skip_serializing_if_for_struct() { + fn default_string_function() -> String { + "mask_default".to_string() + } + #[derive(YaSerialize, PartialEq, Debug)] - #[yaserde(root = "base")] + #[yaserde(rename = "base")] 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")] string_item: String, #[yaserde(skip_serializing_if = "check_bool_function")] @@ -54,12 +49,13 @@ fn ser_skip_serializing_if_for_struct() { } let model = XmlStruct { + string_with_default_item: "mask_default".to_string(), string_item: "something".to_string(), bool_item: true, f32_item: 0.0, option_string_item: Some("something".to_string()), }; - let content = ""; - convert_and_validate!(model, content); + let content = ""; + serialize_and_validate!(model, content); } diff --git a/yaserde/tests/types.rs b/yaserde/tests/types.rs new file mode 100644 index 0000000..de5e2d4 --- /dev/null +++ b/yaserde/tests/types.rs @@ -0,0 +1,46 @@ +#[macro_use] +extern crate yaserde; +#[macro_use] +extern crate yaserde_derive; + +use std::io::{Read, Write}; +use yaserde::{YaDeserialize, YaSerialize}; + +#[test] +fn ser_type() { + test_for_type!(String, "test".to_string(), Some("test")); + test_for_type!(bool, true, Some("true")); + test_for_type!(u8, 12 as u8, Some("12")); + test_for_type!(i8, 12 as i8, Some("12")); + test_for_type!(i8, -12 as i8, Some("-12")); + test_for_type!(u16, 12 as u16, Some("12")); + test_for_type!(i16, 12 as i16, Some("12")); + test_for_type!(i16, -12 as i16, Some("-12")); + test_for_type!(u32, 12 as u32, Some("12")); + test_for_type!(i32, 12 as i32, Some("12")); + test_for_type!(i32, -12 as i32, Some("-12")); + test_for_type!(u64, 12 as u64, Some("12")); + test_for_type!(i64, 12 as i64, Some("12")); + test_for_type!(i64, -12 as i64, Some("-12")); + test_for_type!(f32, -12.5 as f32, Some("-12.5")); + test_for_type!(f64, -12.5 as f64, Some("-12.5")); + test_for_type!(Vec::, vec![], None); + test_for_type!(Vec::, vec!["test".to_string()], Some("test")); + + test_for_attribute_type!(String, "test".to_string(), Some("test")); + test_for_attribute_type!(bool, true, Some("true")); + test_for_attribute_type!(u8, 12 as u8, Some("12")); + test_for_attribute_type!(i8, 12 as i8, Some("12")); + test_for_attribute_type!(i8, -12 as i8, Some("-12")); + test_for_attribute_type!(u16, 12 as u16, Some("12")); + test_for_attribute_type!(i16, 12 as i16, Some("12")); + test_for_attribute_type!(i16, -12 as i16, Some("-12")); + test_for_attribute_type!(u32, 12 as u32, Some("12")); + test_for_attribute_type!(i32, 12 as i32, Some("12")); + test_for_attribute_type!(i32, -12 as i32, Some("-12")); + test_for_attribute_type!(u64, 12 as u64, Some("12")); + test_for_attribute_type!(i64, 12 as i64, Some("12")); + test_for_attribute_type!(i64, -12 as i64, Some("-12")); + test_for_attribute_type!(f32, -12.5 as f32, Some("-12.5")); + test_for_attribute_type!(f64, -12.5 as f64, Some("-12.5")); +} diff --git a/yaserde_derive/src/attribute.rs b/yaserde_derive/src/common/attribute.rs similarity index 85% rename from yaserde_derive/src/attribute.rs rename to yaserde_derive/src/common/attribute.rs index 6504dad..2896bab 100644 --- a/yaserde_derive/src/attribute.rs +++ b/yaserde_derive/src/common/attribute.rs @@ -1,6 +1,4 @@ -use proc_macro2::token_stream::IntoIter; -use proc_macro2::Delimiter; -use proc_macro2::TokenTree; +use proc_macro2::{token_stream::IntoIter, Delimiter, TokenStream, TokenTree}; use std::collections::BTreeMap; use syn::Attribute; @@ -12,7 +10,6 @@ pub struct YaSerdeAttribute { pub flatten: bool, pub namespaces: BTreeMap, pub prefix: Option, - pub root: Option, pub rename: Option, pub skip_serializing_if: Option, pub text: bool, @@ -41,7 +38,6 @@ impl YaSerdeAttribute { let mut namespaces = BTreeMap::new(); let mut prefix = None; let mut rename = None; - let mut root = None; let mut skip_serializing_if = None; let mut text = false; @@ -84,9 +80,6 @@ impl YaSerdeAttribute { "rename" => { rename = get_value(&mut attr_iter); } - "root" => { - root = get_value(&mut attr_iter); - } "skip_serializing_if" => { skip_serializing_if = get_value(&mut attr_iter); } @@ -110,11 +103,49 @@ impl YaSerdeAttribute { namespaces, prefix, rename, - root, skip_serializing_if, text, } } + + pub fn get_namespace_matching( + &self, + prefix: &Option, + element_namespace: TokenStream, + element_name: TokenStream, + take_root_prefix: bool, + ) -> TokenStream { + let configured_prefix = if take_root_prefix { + self.prefix.clone() + } else { + prefix.clone() + }; + + let namespaces_matches: TokenStream = self + .namespaces + .iter() + .map(|(prefix, namespace)| { + if configured_prefix == Some(prefix.to_string()) { + Some(quote!(#namespace => {})) + } else { + None + } + }) + .filter_map(|x| x) + .collect(); + + quote!( + if let Some(namespace) = #element_namespace { + match namespace.as_str() { + #namespaces_matches + bad_namespace => { + let msg = format!("bad namespace for {}, found {}", #element_name, bad_namespace); + return Err(msg); + } + } + } + ) + } } #[test] @@ -130,7 +161,6 @@ fn parse_empty_attributes() { flatten: false, namespaces: BTreeMap::new(), prefix: None, - root: None, rename: None, skip_serializing_if: None, text: false, @@ -180,7 +210,6 @@ fn parse_attributes() { flatten: false, namespaces: BTreeMap::new(), prefix: None, - root: None, rename: None, skip_serializing_if: None, text: false, @@ -205,7 +234,6 @@ fn parse_attributes_with_values() { arguments: PathArguments::None, }); - // #[()] let attributes = vec![Attribute { pound_token: Pound { spans: [Span::call_site()], @@ -234,7 +262,6 @@ fn parse_attributes_with_values() { flatten: true, namespaces, prefix: None, - root: None, rename: None, skip_serializing_if: None, text: false, diff --git a/yaserde_derive/src/common/field.rs b/yaserde_derive/src/common/field.rs new file mode 100644 index 0000000..0a00087 --- /dev/null +++ b/yaserde_derive/src/common/field.rs @@ -0,0 +1,295 @@ +use crate::common::attribute::YaSerdeAttribute; +use proc_macro2::Span; +use proc_macro2::{Ident, TokenStream}; +use std::fmt; +use syn; +use syn::spanned::Spanned; +use syn::Type::Path; + +#[derive(Debug)] +pub struct YaSerdeField { + syn_field: syn::Field, + attributes: YaSerdeAttribute, +} + +impl YaSerdeField { + pub fn new(syn_field: syn::Field) -> Self { + let attributes = YaSerdeAttribute::parse(&syn_field.attrs); + + YaSerdeField { + syn_field, + attributes, + } + } + + pub fn is_attribute(&self) -> bool { + self.attributes.attribute + } + + pub fn is_text_content(&self) -> bool { + 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 { + self.syn_field.ident.clone() + } + + pub fn get_value_label(&self) -> Option { + 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 { + let prefix = if root_attributes.default_namespace == self.attributes.prefix { + "".to_string() + } else { + self + .attributes + .prefix + .clone() + .map_or("".to_string(), |prefix| prefix + ":") + }; + + let label = self.renamed_label_without_namespace(); + + 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 { + Field::from(&self.syn_field) + } + + pub fn get_span(&self) -> Span { + self.syn_field.span() + } + + pub fn get_default_function(&self) -> Option { + self + .attributes + .default + .as_ref() + .map(|default| Ident::new(&default, self.get_span())) + } + + pub fn get_skip_serializing_if_function(&self) -> Option { + self + .attributes + .skip_serializing_if + .as_ref() + .map(|skip_serializing_if| Ident::new(&skip_serializing_if, self.get_span())) + } + + pub fn get_namespace_matching( + &self, + root_attributes: &YaSerdeAttribute, + element_namespace: TokenStream, + element_name: TokenStream, + ) -> TokenStream { + root_attributes.get_namespace_matching( + &self.attributes.prefix, + element_namespace, + element_name, + false, + ) + } + + pub fn ser_wrap_default_attribute( + &self, + builder: Option, + setter: TokenStream, + ) -> TokenStream { + let label = self.label(); + + let yaserde_inner_definition = builder + .map(|builder| quote!(let yaserde_inner = #builder;)) + .unwrap_or(quote!()); + + self + .get_default_function() + .map(|default_function| { + quote! { + #yaserde_inner_definition + let struct_start_event = + if self.#label != #default_function() { + #setter + } else { + struct_start_event + }; + } + }) + .unwrap_or(quote! { + #yaserde_inner_definition + let struct_start_event = #setter; + }) + } +} + +#[derive(Debug)] +pub enum Field { + FieldString, + FieldBool, + FieldI8, + FieldU8, + FieldI16, + FieldU16, + FieldI32, + FieldU32, + FieldI64, + FieldU64, + FieldF32, + FieldF64, + FieldOption { data_type: Box }, + FieldVec { data_type: Box }, + FieldStruct { struct_name: syn::Path }, +} + +impl Field { + pub fn get_simple_type_visitor(&self) -> TokenStream { + let ident = format_ident!("visit_{}", self.to_string()); + quote! {#ident} + } +} + +impl From<&syn::Path> for Field { + fn from(path: &syn::Path) -> Self { + let result = if let Some(segment) = path.segments.last() { + match segment.ident.to_string().as_str() { + "String" => Some(Field::FieldString), + "bool" => Some(Field::FieldBool), + "i8" => Some(Field::FieldI8), + "u8" => Some(Field::FieldU8), + "i16" => Some(Field::FieldI16), + "u16" => Some(Field::FieldU16), + "i32" => Some(Field::FieldI32), + "u32" => Some(Field::FieldU32), + "i64" => Some(Field::FieldI64), + "u64" => Some(Field::FieldU64), + "f32" => Some(Field::FieldF32), + "f64" => Some(Field::FieldF64), + "Option" => Some(Field::FieldOption { + data_type: Box::new(Field::from(segment)), + }), + "Vec" => Some(Field::FieldVec { + data_type: Box::new(Field::from(segment)), + }), + _ => None, + } + } else { + None + }; + + result.unwrap_or_else(|| Field::FieldStruct { + struct_name: path.clone(), + }) + } +} + +impl From<&syn::Field> for Field { + fn from(field: &syn::Field) -> Self { + match field.ty { + Path(ref path) => Field::from(&path.path), + _ => panic!("unable to match {:?}", field.ty), + } + } +} + +impl From<&syn::PathSegment> for Field { + fn from(path_segment: &syn::PathSegment) -> Self { + if let syn::PathArguments::AngleBracketed(ref args) = path_segment.arguments { + if let Some(tt) = args.args.first() { + if let syn::GenericArgument::Type(ref argument) = *tt { + if let Path(ref path) = *argument { + return Field::from(&path.path); + } + } + } + } + unimplemented!() + } +} + +impl Into for Field { + fn into(self) -> proc_macro2::TokenStream { + match self { + Field::FieldString => quote! {String}, + Field::FieldBool => quote! {bool}, + Field::FieldI8 => quote! {i8}, + Field::FieldU8 => quote! {u8}, + Field::FieldI16 => quote! {i16}, + Field::FieldU16 => quote! {u16}, + Field::FieldI32 => quote! {i32}, + Field::FieldU32 => quote! {u32}, + Field::FieldI64 => quote! {i64}, + Field::FieldU64 => quote! {u64}, + Field::FieldF32 => quote! {f32}, + Field::FieldF64 => quote! {f64}, + _ => panic!("Not a simple type: {:?}", self), + } + } +} + +impl Into for &Field { + fn into(self) -> String { + match self { + Field::FieldString => "str".to_string(), + Field::FieldBool => "bool".to_string(), + Field::FieldI8 => "i8".to_string(), + Field::FieldU8 => "u8".to_string(), + Field::FieldI16 => "i16".to_string(), + Field::FieldU16 => "u16".to_string(), + Field::FieldI32 => "i32".to_string(), + Field::FieldU32 => "u32".to_string(), + Field::FieldI64 => "i64".to_string(), + Field::FieldU64 => "u64".to_string(), + Field::FieldF32 => "f32".to_string(), + Field::FieldF64 => "f64".to_string(), + _ => panic!("Not a simple type: {:?}", self), + } + } +} + +impl fmt::Display for Field { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let string_representation: String = self.into(); + write!(f, "{}", string_representation) + } +} diff --git a/yaserde_derive/src/common/mod.rs b/yaserde_derive/src/common/mod.rs new file mode 100644 index 0000000..cee0625 --- /dev/null +++ b/yaserde_derive/src/common/mod.rs @@ -0,0 +1,5 @@ +mod attribute; +mod field; + +pub use attribute::YaSerdeAttribute; +pub use field::{Field, YaSerdeField}; diff --git a/yaserde_derive/src/de/build_default_value.rs b/yaserde_derive/src/de/build_default_value.rs index 22a024e..cd1484d 100644 --- a/yaserde_derive/src/de/build_default_value.rs +++ b/yaserde_derive/src/de/build_default_value.rs @@ -1,28 +1,24 @@ -use proc_macro2::{Span, TokenStream}; -use syn::Ident; +use crate::common::YaSerdeField; +use proc_macro2::TokenStream; pub fn build_default_value( - label: &Option, - field_type: &TokenStream, - value: &TokenStream, - default: &Option, + field: &YaSerdeField, + field_type: Option, + value: TokenStream, ) -> Option { - let value = default - .as_ref() - .map(|d| { - let default_function = Ident::new( - &d, - label - .as_ref() - .map_or(Span::call_site(), |ident| ident.span()), - ); + let label = field.get_value_label(); - quote!(#default_function()) - }) + let default_value = field + .get_default_function() + .map(|default_function| quote!(#default_function())) .unwrap_or_else(|| quote!(#value)); + let field_type = field_type + .map(|field_type| quote!(: #field_type)) + .unwrap_or(quote!()); + Some(quote! { #[allow(unused_mut)] - let mut #label : #field_type = #value; + let mut #label #field_type = #default_value; }) } diff --git a/yaserde_derive/src/de/expand_enum.rs b/yaserde_derive/src/de/expand_enum.rs index c43d246..76a110d 100644 --- a/yaserde_derive/src/de/expand_enum.rs +++ b/yaserde_derive/src/de/expand_enum.rs @@ -1,10 +1,6 @@ -use crate::attribute::*; -use crate::field_type::*; +use crate::common::{Field, YaSerdeAttribute, YaSerdeField}; use proc_macro2::TokenStream; -use syn::spanned::Spanned; -use syn::DataEnum; -use syn::Fields; -use syn::Ident; +use syn::{DataEnum, Fields, Ident}; pub fn parse( data_enum: &DataEnum, @@ -141,9 +137,10 @@ fn build_unnamed_field_visitors(fields: &syn::FieldsUnnamed) -> TokenStream { fields .unnamed .iter() + .map(|field| YaSerdeField::new(field.clone())) .enumerate() .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 = |visitor: &TokenStream, field_type: &TokenStream, fn_body: &TokenStream| { @@ -160,9 +157,9 @@ fn build_unnamed_field_visitors(fields: &syn::FieldsUnnamed) -> TokenStream { }) }; - let simple_type_visitor = |simple_type| { - let field_type = get_simple_type_token(&simple_type); - let visitor = get_simple_type_visitor(&simple_type); + let simple_type_visitor = |simple_type: Field| { + let visitor = simple_type.get_simple_type_visitor(); + let field_type = simple_type.into(); make_visitor( &visitor, @@ -171,8 +168,8 @@ fn build_unnamed_field_visitors(fields: &syn::FieldsUnnamed) -> TokenStream { ) }; - get_field_type(field).and_then(|f| match f { - FieldType::FieldTypeStruct { struct_name } => { + match field.get_type() { + Field::FieldStruct { struct_name } => { let struct_id: String = struct_name .segments .iter() @@ -189,14 +186,12 @@ fn build_unnamed_field_visitors(fields: &syn::FieldsUnnamed) -> TokenStream { }, ) } - FieldType::FieldTypeOption { data_type } | FieldType::FieldTypeVec { data_type } => { - match *data_type { - FieldType::FieldTypeStruct { .. } => None, - simple_type => simple_type_visitor(simple_type), - } - } + Field::FieldOption { data_type } | Field::FieldVec { data_type } => match *data_type { + Field::FieldStruct { .. } => None, + simple_type => simple_type_visitor(simple_type), + }, simple_type => simple_type_visitor(simple_type), - }) + } }) .filter_map(|f| f) .collect() @@ -209,13 +204,14 @@ fn build_unnamed_visitor_calls( fields .unnamed .iter() + .map(|field| YaSerdeField::new(field.clone())) .enumerate() .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, action| { - let field_type = get_simple_type_token(&simple_type); - let visitor = get_simple_type_visitor(&simple_type); + let call_simple_type_visitor = |simple_type: Field, action| { + let visitor = simple_type.get_simple_type_visitor(); + let field_type: TokenStream = simple_type.into(); let label_name = format!("field_{}", idx); @@ -279,19 +275,19 @@ fn build_unnamed_visitor_calls( } }; - get_field_type(field).and_then(|f| match f { - FieldType::FieldTypeStruct { struct_name } => call_struct_visitor(struct_name, set_val), - FieldType::FieldTypeOption { data_type } => match *data_type { - FieldType::FieldTypeStruct { struct_name } => call_struct_visitor(struct_name, set_opt), + match field.get_type() { + Field::FieldStruct { struct_name } => call_struct_visitor(struct_name, set_val), + Field::FieldOption { data_type } => match *data_type { + Field::FieldStruct { struct_name } => call_struct_visitor(struct_name, set_opt), simple_type => call_simple_type_visitor(simple_type, set_opt), }, - FieldType::FieldTypeVec { data_type } => match *data_type { - FieldType::FieldTypeStruct { struct_name } => call_struct_visitor(struct_name, set_vec), + Field::FieldVec { data_type } => match *data_type { + Field::FieldStruct { struct_name } => call_struct_visitor(struct_name, set_vec), simple_type => call_simple_type_visitor(simple_type, set_vec), }, simple_type => call_simple_type_visitor(simple_type, set_val), - }) + } }) .filter_map(|f| f) .collect() diff --git a/yaserde_derive/src/de/expand_struct.rs b/yaserde_derive/src/de/expand_struct.rs index 3c48215..bd9c718 100644 --- a/yaserde_derive/src/de/expand_struct.rs +++ b/yaserde_derive/src/de/expand_struct.rs @@ -1,11 +1,7 @@ -use crate::attribute::*; +use crate::common::{Field, YaSerdeAttribute, YaSerdeField}; use crate::de::build_default_value::build_default_value; -use crate::field_type::*; use proc_macro2::{Span, TokenStream}; -use std::collections::BTreeMap; -use syn::spanned::Spanned; -use syn::DataStruct; -use syn::Ident; +use syn::{DataStruct, Ident}; pub fn parse( data_struct: &DataStruct, @@ -13,79 +9,43 @@ pub fn parse( root: &str, root_attributes: &YaSerdeAttribute, ) -> TokenStream { - let namespaces_matches: TokenStream = root_attributes - .namespaces - .iter() - .map(|(p, ns)| { - if root_attributes.prefix.as_ref() == Some(p) { - Some(quote!(#ns => {})) - } else { - None - } - }) - .filter_map(|x| x) - .collect(); + let namespaces_matching = root_attributes.get_namespace_matching( + &None, + quote!(struct_namespace), + quote!(named_element), + true, + ); let variables: TokenStream = data_struct .fields .iter() - .map(|field| { - let label = &get_value_label(&field.ident); - let field_attrs = YaSerdeAttribute::parse(&field.attrs); - - get_field_type(field).and_then(|f| match f { - FieldType::FieldTypeStruct { struct_name } => build_default_value( - label, - "e! {#struct_name}, - "e! {#struct_name::default()}, - &field_attrs.default, - ), - FieldType::FieldTypeOption { .. } => { - if let Some(d) = &field_attrs.default { - let default_function = Ident::new(&d, field.span()); - - 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; - }) - } + .map(|field| YaSerdeField::new(field.clone())) + .map(|field| match field.get_type() { + Field::FieldStruct { struct_name } => build_default_value( + &field, + Some(quote!(#struct_name)), + quote!(#struct_name::default()), + ), + Field::FieldOption { .. } => build_default_value(&field, None, quote!(None)), + Field::FieldVec { data_type } => match *data_type { + Field::FieldStruct { ref struct_name } => { + build_default_value(&field, Some(quote!(Vec<#struct_name>)), quote!(vec![])) + } + Field::FieldOption { .. } | Field::FieldVec { .. } => { + unimplemented!(); } - FieldType::FieldTypeVec { data_type } => match *data_type { - FieldType::FieldTypeStruct { ref struct_name } => build_default_value( - label, - "e! {Vec<#struct_name>}, - "e! {vec![]}, - &field_attrs.default, - ), - FieldType::FieldTypeOption { .. } | FieldType::FieldTypeVec { .. } => { - unimplemented!(); - } - simple_type => { - let type_token = get_simple_type_token(&simple_type); - - build_default_value( - label, - "e! {Vec<#type_token>}, - "e! {vec![]}, - &field_attrs.default, - ) - } - }, simple_type => { - let type_token = get_simple_type_token(&simple_type); - build_default_value( - label, - &type_token, - "e! {#type_token::default()}, - &field_attrs.default, - ) + let type_token: TokenStream = simple_type.into(); + + build_default_value(&field, Some(quote!(Vec<#type_token>)), quote!(vec![])) } - }) + }, + 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) .collect(); @@ -93,12 +53,8 @@ pub fn parse( let field_visitors: TokenStream = data_struct .fields .iter() + .map(|field| YaSerdeField::new(field.clone())) .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_id: String = struct_name .segments @@ -106,7 +62,7 @@ pub fn parse( .map(|s| s.ident.to_string()) .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! { #[allow(non_snake_case, non_camel_case_types)] @@ -123,10 +79,10 @@ pub fn parse( }) }; - let simple_type_visitor = |simple_type: FieldType| { - 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); + let simple_type_visitor = |simple_type: Field| { + let visitor = simple_type.get_simple_type_visitor(); + let visitor_label = field.get_visitor_ident(None); + let field_type: TokenStream = simple_type.into(); Some(quote! { #[allow(non_snake_case, non_camel_case_types)] @@ -141,20 +97,20 @@ pub fn parse( }) }; - get_field_type(field).and_then(|f| match f { - FieldType::FieldTypeStruct { struct_name } => struct_visitor(struct_name), - FieldType::FieldTypeOption { data_type } => match *data_type { - FieldType::FieldTypeStruct { struct_name } => struct_visitor(struct_name), - FieldType::FieldTypeOption { .. } | FieldType::FieldTypeVec { .. } => None, + match field.get_type() { + Field::FieldStruct { struct_name } => struct_visitor(struct_name), + Field::FieldOption { data_type } => match *data_type { + Field::FieldStruct { struct_name } => struct_visitor(struct_name), + Field::FieldOption { .. } | Field::FieldVec { .. } => None, simple_type => simple_type_visitor(simple_type), }, - FieldType::FieldTypeVec { data_type } => match *data_type { - FieldType::FieldTypeStruct { struct_name } => struct_visitor(struct_name), - FieldType::FieldTypeOption { .. } | FieldType::FieldTypeVec { .. } => None, + Field::FieldVec { data_type } => match *data_type { + Field::FieldStruct { struct_name } => struct_visitor(struct_name), + Field::FieldOption { .. } | Field::FieldVec { .. } => None, simple_type => simple_type_visitor(simple_type), }, simple_type => simple_type_visitor(simple_type), - }) + } }) .filter_map(|x| x) .collect(); @@ -162,19 +118,11 @@ pub fn parse( let call_visitors: TokenStream = data_struct .fields .iter() + .map(|field| YaSerdeField::new(field.clone())) + .filter(|field| !field.is_attribute() || !field.is_flatten()) .map(|field| { - let field_attrs = YaSerdeAttribute::parse(&field.attrs); - let label = &field.ident; - 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 value_label = field.get_value_label(); + let label_name = field.renamed_label_without_namespace(); let visit_struct = |struct_name: syn::Path, action: TokenStream| { Some(quote! { @@ -192,30 +140,30 @@ pub fn parse( }) }; - let visit_simple = |simple_type: FieldType, action: TokenStream| { + let visit_simple = |simple_type: Field, action: TokenStream| { + let field_visitor = simple_type.get_simple_type_visitor(); + let field_type: TokenStream = simple_type.into(); build_call_visitor( - &get_simple_type_token(&simple_type), - &get_simple_type_visitor(&simple_type), + &field_type, + &field_visitor, &action, - &field_attrs, - label, - &root_attributes.namespaces, - field.span(), + &field, + &root_attributes, ) }; - 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), + let visit_sub = |sub_type: Box, action: TokenStream| match *sub_type { + Field::FieldOption { .. } | Field::FieldVec { .. } => unimplemented!(), + Field::FieldStruct { 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)}), + match field.get_type() { + Field::FieldStruct { struct_name } => visit_struct(struct_name, quote! {= value}), + Field::FieldOption { data_type } => visit_sub(data_type, quote! {= Some(value)}), + Field::FieldVec { data_type } => visit_sub(data_type, quote! {.push(value)}), simple_type => visit_simple(simple_type, quote! {= value}), - }) + } }) .filter_map(|x| x) .collect(); @@ -223,26 +171,23 @@ pub fn parse( let call_flatten_visitors: TokenStream = data_struct .fields .iter() + .map(|field| YaSerdeField::new(field.clone())) + .filter(|field| !field.is_attribute() && field.is_flatten()) .map(|field| { - let field_attrs = YaSerdeAttribute::parse(&field.attrs); - let value_label = &get_value_label(&field.ident); + let value_label = field.get_value_label(); - if field_attrs.attribute || !field_attrs.flatten { - return None; - } - - get_field_type(field).and_then(|f| match f { - FieldType::FieldTypeStruct { .. } => Some(quote! { + match field.get_type() { + Field::FieldStruct { .. } => Some(quote! { #value_label = yaserde::de::from_str(&unused_xml_elements)?; }), - FieldType::FieldTypeOption { data_type } => match *data_type { - FieldType::FieldTypeStruct { .. } => Some(quote! { + Field::FieldOption { data_type } => match *data_type { + Field::FieldStruct { .. } => Some(quote! { #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) .collect(); @@ -250,19 +195,12 @@ pub fn parse( let attributes_loading: TokenStream = data_struct .fields .iter() + .map(|field| YaSerdeField::new(field.clone())) + .filter(|field| field.is_attribute()) .map(|field| { - let field_attrs = YaSerdeAttribute::parse(&field.attrs); - if !field_attrs.attribute { - return 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 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 visit = |action: &TokenStream, visitor: &TokenStream, visitor_label: &Ident| { Some(quote! { @@ -290,31 +228,31 @@ pub fn parse( visit( &action, "e! {visit_str}, - &build_visitor_ident(&label_name, field.span(), Some(&struct_name)), + &build_visitor_ident(&label_name, field.get_span(), Some(&struct_name)), ) }; - let visit_simple = |simple_type: FieldType, action: TokenStream| { + let visit_simple = |simple_type: Field, action: TokenStream| { visit( &action, - &get_simple_type_visitor(&simple_type), + &simple_type.get_simple_type_visitor(), &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), + let visit_sub = |sub_type: Box, action: TokenStream| match *sub_type { + Field::FieldOption { .. } | Field::FieldVec { .. } => unimplemented!(), + Field::FieldStruct { 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}), + match field.get_type() { + Field::FieldString => visit_string(), + Field::FieldOption { data_type } => visit_sub(data_type, quote! {= Some(value)}), + Field::FieldVec { .. } => unimplemented!(), + Field::FieldStruct { struct_name } => visit_struct(struct_name, quote! {= value}), simple_type => visit_simple(simple_type, quote! {= value}), - }) + } }) .filter_map(|x| x) .collect(); @@ -322,28 +260,26 @@ pub fn parse( let set_text: TokenStream = data_struct .fields .iter() + .map(|field| YaSerdeField::new(field.clone())) .map(|field| { - let label = &get_value_label(&field.ident); - let field_attrs = YaSerdeAttribute::parse(&field.attrs); + let label = field.get_value_label(); let set_text = |action: &TokenStream| { - if field_attrs.text { + if field.is_text_content() { 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, + match field.get_type() { + Field::FieldString => set_text("e! {text_content.to_owned()}), + Field::FieldStruct { .. } | Field::FieldOption { .. } | Field::FieldVec { .. } => None, simple_type => { - let type_token = get_simple_type_token(&simple_type); + let type_token: TokenStream = simple_type.into(); set_text("e! {#type_token::from_str(text_content).unwrap()}) } - }) + } }) .filter_map(|x| x) .collect(); @@ -351,15 +287,13 @@ pub fn parse( let struct_builder: TokenStream = data_struct .fields .iter() + .map(|field| YaSerdeField::new(field.clone())) .map(|field| { - let label = &field.ident; - let value_label = &get_value_label(&field.ident); + let label = &field.label(); + let value_label = field.get_value_label(); - get_field_type(field).map(|_| { - quote! { #label: #value_label, } - }) + quote! { #label: #value_label, } }) - .filter_map(|x| x) .collect(); let (init_unused, write_unused, visit_unused) = if call_flatten_visitors.is_empty() { @@ -390,15 +324,7 @@ pub fn parse( debug!("Struct: start to parse {:?}", named_element); if reader.depth() == 0 { - if let Some(ref namespace) = struct_namespace { - match namespace.as_str() { - #namespaces_matches - bad_ns => { - let msg = format!("bad namespace for {}, found {}", named_element, bad_ns); - return Err(msg); - } - } - } + #namespaces_matching } #variables @@ -472,47 +398,24 @@ fn build_call_visitor( field_type: &TokenStream, visitor: &TokenStream, action: &TokenStream, - field_attrs: &YaSerdeAttribute, - label: &Option, - namespaces: &BTreeMap, - span: Span, + field: &YaSerdeField, + root_attributes: &YaSerdeAttribute, ) -> Option { - 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 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(); + let namespaces_matching = field.get_namespace_matching( + root_attributes, + quote!(name.namespace.as_ref()), + quote!(name.local_name.as_str()), + ); Some(quote! { #label_name => { let visitor = #visitor_label{}; - if let Some(namespace) = name.namespace.as_ref() { - match namespace.as_str() { - #namespaces_matches - bad_ns => { - let msg = format!("bad field namespace for {}, found {}", name.local_name.as_str(), bad_ns); - return Err(msg); - } - } - } + #namespaces_matching let result = reader.read_inner_value::<#field_type, _>(|reader| { if let Ok(XmlEvent::Characters(s)) = reader.peek() { @@ -531,12 +434,6 @@ fn build_call_visitor( }) } -fn get_value_label(ident: &Option) -> Option { - 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 { let struct_id = struct_name.map_or_else( || "".to_string(), diff --git a/yaserde_derive/src/de/mod.rs b/yaserde_derive/src/de/mod.rs index 84f1f17..a6df2b3 100644 --- a/yaserde_derive/src/de/mod.rs +++ b/yaserde_derive/src/de/mod.rs @@ -2,7 +2,7 @@ pub mod build_default_value; pub mod expand_enum; pub mod expand_struct; -use crate::attribute; +use crate::common::YaSerdeAttribute; use proc_macro2::TokenStream; use syn; use syn::Ident; @@ -12,14 +12,19 @@ pub fn expand_derive_deserialize(ast: &syn::DeriveInput) -> Result { - expand_struct::parse(data_struct, name, &root, &root_attrs) + expand_struct::parse(data_struct, name, &root_name, &root_attributes) + } + syn::Data::Enum(ref data_enum) => { + expand_enum::parse(data_enum, name, &root_name, &root_attributes) } - 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/field_type.rs b/yaserde_derive/src/field_type.rs deleted file mode 100644 index b9b55c6..0000000 --- a/yaserde_derive/src/field_type.rs +++ /dev/null @@ -1,102 +0,0 @@ -use syn; -use syn::Type::Path; - -#[derive(Debug)] -pub enum FieldType { - FieldTypeString, - FieldTypeBool, - FieldTypeI8, - FieldTypeU8, - FieldTypeI16, - FieldTypeU16, - FieldTypeI32, - FieldTypeU32, - FieldTypeI64, - FieldTypeU64, - FieldTypeF32, - FieldTypeF64, - FieldTypeOption { data_type: Box }, - FieldTypeVec { data_type: Box }, - FieldTypeStruct { struct_name: syn::Path }, -} - -impl FieldType { - fn from_ident(path: &syn::Path) -> Option { - match path.segments.last() { - Some(t) => match t.ident.to_string().as_str() { - "String" => Some(FieldType::FieldTypeString), - "bool" => Some(FieldType::FieldTypeBool), - "i8" => Some(FieldType::FieldTypeI8), - "u8" => Some(FieldType::FieldTypeU8), - "i16" => Some(FieldType::FieldTypeI16), - "u16" => Some(FieldType::FieldTypeU16), - "i32" => Some(FieldType::FieldTypeI32), - "u32" => Some(FieldType::FieldTypeU32), - "i64" => Some(FieldType::FieldTypeI64), - "u64" => Some(FieldType::FieldTypeU64), - "f32" => Some(FieldType::FieldTypeF32), - "f64" => Some(FieldType::FieldTypeF64), - "Option" => get_sub_type(t).map(|data_type| FieldType::FieldTypeOption { - data_type: Box::new(FieldType::from_ident(&data_type).unwrap()), - }), - "Vec" => get_sub_type(t).map(|data_type| FieldType::FieldTypeVec { - data_type: Box::new(FieldType::from_ident(&data_type).unwrap()), - }), - _ => Some(FieldType::FieldTypeStruct { - struct_name: path.clone(), - }), - }, - _ => None, - } - } -} - -pub fn get_field_type(field: &syn::Field) -> Option { - match field.ty { - Path(ref path) => FieldType::from_ident(&path.path), - _ => None, - } -} - -fn get_sub_type(t: &syn::PathSegment) -> Option { - if let syn::PathArguments::AngleBracketed(ref args) = t.arguments { - if let Some(tt) = args.args.first() { - if let syn::GenericArgument::Type(ref argument) = *tt { - if let Path(ref path) = *argument { - return Some(path.path.clone()); - } - } - } - } - - None -} - -pub fn get_simple_type_token(field_type: &FieldType) -> proc_macro2::TokenStream { - match field_type { - FieldType::FieldTypeString => quote! {String}, - FieldType::FieldTypeBool => quote! {bool}, - FieldType::FieldTypeI8 => quote! {i8}, - FieldType::FieldTypeU8 => quote! {u8}, - FieldType::FieldTypeI16 => quote! {i16}, - FieldType::FieldTypeU16 => quote! {u16}, - FieldType::FieldTypeI32 => quote! {i32}, - FieldType::FieldTypeU32 => quote! {u32}, - FieldType::FieldTypeI64 => quote! {i64}, - FieldType::FieldTypeU64 => quote! {u64}, - FieldType::FieldTypeF32 => quote! {f32}, - FieldType::FieldTypeF64 => quote! {f64}, - _ => panic!("Not a simple type: {:?}", field_type), - } -} - -pub fn get_simple_type_visitor(field_type: &FieldType) -> proc_macro2::TokenStream { - let ident = format_ident!( - "visit_{}", - get_simple_type_token(field_type) - .to_string() - .replace("String", "str") - ); - - quote! {#ident} -} diff --git a/yaserde_derive/src/lib.rs b/yaserde_derive/src/lib.rs index 527a439..7fd17fa 100644 --- a/yaserde_derive/src/lib.rs +++ b/yaserde_derive/src/lib.rs @@ -6,9 +6,8 @@ extern crate proc_macro2; extern crate quote; extern crate syn; -mod attribute; +mod common; mod de; -mod field_type; mod ser; use proc_macro::TokenStream; diff --git a/yaserde_derive/src/ser/element.rs b/yaserde_derive/src/ser/element.rs index 313be33..d00e832 100644 --- a/yaserde_derive/src/ser/element.rs +++ b/yaserde_derive/src/ser/element.rs @@ -1,5 +1,5 @@ -use crate::attribute::*; -use proc_macro2::{Ident, Span, TokenStream}; +use crate::common::YaSerdeField; +use proc_macro2::{Ident, TokenStream}; pub fn enclose_formatted_characters(label: &Ident, label_name: String) -> TokenStream { enclose_xml_event(label_name, quote!(format!("{}", &self.#label))) @@ -13,7 +13,7 @@ pub fn enclose_characters(label: &Option, label_name: String) -> TokenStr 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! { let start_event = XmlEvent::start_element(#label_name); writer.write(start_event).map_err(|e| e.to_string())?; @@ -41,34 +41,23 @@ pub fn serialize_element( }) } -pub fn condition_generator(label: &Option, attributes: &YaSerdeAttribute) -> TokenStream { - let mut conditions = None; +pub fn condition_generator(label: &Option, field: &YaSerdeField) -> TokenStream { + let default_condition = field + .get_default_function() + .map(|default_function| quote!(self.#label != #default_function())); - if let Some(ref d) = attributes.default { - let default_function = Ident::new( - &d, - label - .as_ref() - .map_or(Span::call_site(), |ident| ident.span()), - ); - - conditions = Some(quote!(self.#label != #default_function())) - } - - if let Some(ref s) = attributes.skip_serializing_if { - let skip_if_function = Ident::new( - &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!()) + field + .get_skip_serializing_if_function() + .map(|skip_if_function| { + if let Some(prev_conditions) = &default_condition { + quote!(if !self.#skip_if_function(&self.#label) && #prev_conditions) + } else { + quote!(if !self.#skip_if_function(&self.#label)) + } + }) + .unwrap_or_else(|| { + default_condition + .map(|condition| quote!(if #condition)) + .unwrap_or(quote!()) + }) } diff --git a/yaserde_derive/src/ser/expand_enum.rs b/yaserde_derive/src/ser/expand_enum.rs index fb42821..eb9521c 100644 --- a/yaserde_derive/src/ser/expand_enum.rs +++ b/yaserde_derive/src/ser/expand_enum.rs @@ -1,8 +1,6 @@ -use crate::attribute::*; -use crate::field_type::*; +use crate::common::{Field, YaSerdeAttribute, YaSerdeField}; use crate::ser::{implement_deserializer::implement_deserializer, label::build_label_name}; use proc_macro2::TokenStream; -use syn::spanned::Spanned; use syn::DataEnum; use syn::Fields; use syn::Ident; @@ -51,39 +49,33 @@ fn inner_enum_inspector( let enum_fields: TokenStream = fields .named .iter() + .map(|field| YaSerdeField::new(field.clone())) + .filter(|field| !field.is_attribute()) .map(|field| { - let field_attrs = YaSerdeAttribute::parse(&field.attrs); - if field_attrs.attribute { - return None; - } + let field_label = field.label(); - let field_label = &field.ident; - if field_attrs.text { + 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 renamed_field_label = match field_attrs.rename { - Some(value) => Some(Ident::new(&value.replace("\"", ""), field.span())), - None => field.ident.clone(), - }; - let field_label_name = renamed_field_label.unwrap().to_string(); + let field_label_name = field.renamed_label(root_attributes); - match get_field_type(field) { - Some(FieldType::FieldTypeString) - | Some(FieldType::FieldTypeBool) - | Some(FieldType::FieldTypeU8) - | Some(FieldType::FieldTypeI8) - | Some(FieldType::FieldTypeU16) - | Some(FieldType::FieldTypeI16) - | Some(FieldType::FieldTypeU32) - | Some(FieldType::FieldTypeI32) - | Some(FieldType::FieldTypeF32) - | Some(FieldType::FieldTypeU64) - | Some(FieldType::FieldTypeI64) - | Some(FieldType::FieldTypeF64) => Some({ + 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, ..} => { @@ -101,7 +93,7 @@ fn inner_enum_inspector( } } }), - Some(FieldType::FieldTypeStruct { .. }) => Some(quote! { + Field::FieldStruct { .. } => Some(quote! { match self { &#name::#label{ref #field_label, ..} => { writer.set_start_event_name(Some(#field_label_name.to_string())); @@ -111,7 +103,7 @@ fn inner_enum_inspector( _ => {} } }), - Some(FieldType::FieldTypeVec { .. }) => Some(quote! { + Field::FieldVec { .. } => Some(quote! { match self { &#name::#label{ref #field_label, ..} => { for item in #field_label { @@ -123,7 +115,7 @@ fn inner_enum_inspector( _ => {} } }), - _ => None, + Field::FieldOption { .. } => None, } }) .filter_map(|x| x) @@ -139,12 +131,9 @@ fn inner_enum_inspector( let enum_fields: TokenStream = fields .unnamed .iter() + .map(|field| YaSerdeField::new(field.clone())) + .filter(|field| !field.is_attribute()) .map(|field| { - let field_attrs = YaSerdeAttribute::parse(&field.attrs); - if field_attrs.attribute { - return None; - } - let write_element = |action: &TokenStream| { quote! { let struct_start_event = XmlEvent::start_element(#label_name); @@ -176,7 +165,7 @@ fn inner_enum_inspector( let write_sub_type = |data_type| { write_element(match data_type { - FieldType::FieldTypeString => &write_string_chars, + Field::FieldString => &write_string_chars, _ => &serialize, }) }; @@ -192,8 +181,8 @@ fn inner_enum_inspector( } }; - match get_field_type(field) { - Some(FieldType::FieldTypeOption { data_type }) => { + match field.get_type() { + Field::FieldOption { data_type } => { let write = write_sub_type(*data_type); Some(match_field("e! { @@ -202,7 +191,7 @@ fn inner_enum_inspector( } })) } - Some(FieldType::FieldTypeVec { data_type }) => { + Field::FieldVec { data_type } => { let write = write_sub_type(*data_type); Some(match_field("e! { @@ -211,14 +200,9 @@ fn inner_enum_inspector( } })) } - Some(FieldType::FieldTypeStruct { .. }) => { - Some(write_element(&match_field(&serialize))) - } - Some(FieldType::FieldTypeString) => { - Some(match_field(&write_element(&write_string_chars))) - } - Some(_simple_type) => Some(match_field(&write_simple_type)), - _ => None, + 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) diff --git a/yaserde_derive/src/ser/expand_struct.rs b/yaserde_derive/src/ser/expand_struct.rs index 16bfed5..1201df4 100644 --- a/yaserde_derive/src/ser/expand_struct.rs +++ b/yaserde_derive/src/ser/expand_struct.rs @@ -1,10 +1,7 @@ -use crate::attribute::*; -use crate::field_type::*; -use crate::ser::{ - element::*, implement_deserializer::implement_deserializer, label::build_label_name, -}; +use crate::common::{Field, YaSerdeAttribute, YaSerdeField}; + +use crate::ser::{element::*, implement_deserializer::implement_deserializer}; use proc_macro2::TokenStream; -use syn::spanned::Spanned; use syn::DataStruct; use syn::Ident; @@ -17,193 +14,98 @@ pub fn serialize( let build_attributes: TokenStream = data_struct .fields .iter() + .map(|field| YaSerdeField::new(field.clone())) + .filter(|field| field.is_attribute()) .map(|field| { - let field_attrs = YaSerdeAttribute::parse(&field.attrs); - if !field_attrs.attribute { - return None; - } + let label = field.label(); + let label_name = field.renamed_label(root_attributes); - let label = &field.ident; - - let label_name = build_label_name( - &label.as_ref().unwrap(), - &field_attrs, - &root_attributes.default_namespace, - ); - - get_field_type(field).and_then(|f| match f { - FieldType::FieldTypeString - | FieldType::FieldTypeBool - | FieldType::FieldTypeI8 - | FieldType::FieldTypeU8 - | FieldType::FieldTypeI16 - | FieldType::FieldTypeU16 - | FieldType::FieldTypeI32 - | FieldType::FieldTypeU32 - | FieldType::FieldTypeI64 - | FieldType::FieldTypeU64 - | FieldType::FieldTypeF32 - | FieldType::FieldTypeF64 => { - 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, &content) - } else { - struct_start_event - }; - }) - } else { - Some(quote! { - let content = self.#label.to_string(); - let struct_start_event = struct_start_event.attr(#label_name, &content); - }) - } - } - FieldType::FieldTypeOption { data_type } => match *data_type { - FieldType::FieldTypeString => { - if let Some(ref d) = field_attrs.default { - let default_function = Ident::new(&d, field.span()); - Some(quote! { - let struct_start_event = - if self.#label != #default_function() { - if let Some(ref value) = self.#label { - struct_start_event.attr(#label_name, &value) - } else { - struct_start_event - } - } else { - struct_start_event - }; - }) - } else { - Some(quote! { - let struct_start_event = - if let Some(ref value) = self.#label { - struct_start_event.attr(#label_name, &value) - } else { - struct_start_event - }; - }) - } - } - FieldType::FieldTypeBool - | FieldType::FieldTypeI8 - | FieldType::FieldTypeU8 - | FieldType::FieldTypeI16 - | FieldType::FieldTypeU16 - | FieldType::FieldTypeI32 - | FieldType::FieldTypeU32 - | FieldType::FieldTypeI64 - | FieldType::FieldTypeU64 - | FieldType::FieldTypeF32 - | FieldType::FieldTypeF64 => { - 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, &content) - } else { - struct_start_event - } - } else { - struct_start_event - }; - }) - } 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, &content) - } else { - struct_start_event - }; - }) - } - } - FieldType::FieldTypeVec { .. } => { - let item_ident = Ident::new("yaserde_item", field.span()); + match field.get_type() { + Field::FieldString + | Field::FieldBool + | Field::FieldI8 + | Field::FieldU8 + | Field::FieldI16 + | Field::FieldU16 + | Field::FieldI32 + | Field::FieldU32 + | Field::FieldI64 + | Field::FieldU64 + | Field::FieldF32 + | Field::FieldF64 => Some(field.ser_wrap_default_attribute( + Some(quote!(self.#label.to_string())), + quote!({ + struct_start_event.attr(#label_name, &yaserde_inner) + }), + )), + Field::FieldOption { data_type } => match *data_type { + Field::FieldString => Some(field.ser_wrap_default_attribute( + None, + quote!({ + if let Some(ref value) = self.#label { + struct_start_event.attr(#label_name, value) + } else { + struct_start_event + } + }), + )), + Field::FieldBool + | Field::FieldI8 + | Field::FieldU8 + | Field::FieldI16 + | Field::FieldU16 + | Field::FieldI32 + | Field::FieldU32 + | Field::FieldI64 + | Field::FieldU64 + | Field::FieldF32 + | Field::FieldF64 => Some(field.ser_wrap_default_attribute( + Some(quote!(self.#label.map_or_else(|| String::new(), |v| v.to_string()))), + quote!({ + if let Some(ref value) = self.#label { + struct_start_event.attr(#label_name, &yaserde_inner) + } else { + struct_start_event + } + }), + )), + Field::FieldVec { .. } => { + let item_ident = Ident::new("yaserde_item", field.get_span()); let inner = enclose_formatted_characters(&item_ident, label_name); - if let Some(ref d) = field_attrs.default { - let default_function = Ident::new(&d, field.span()); - - Some(quote! { - if self.#label != #default_function() { - if let Some(ref yaserde_list) = self.#label { - for yaserde_item in yaserde_list.iter() { - #inner - } + Some(field.ser_wrap_default_attribute( + None, + quote!({ + if let Some(ref yaserde_list) = self.#label { + for yaserde_item in yaserde_list.iter() { + #inner } } - }) - } else { - Some(quote! { - for yaserde_item in &self.#label { - #inner - } - }) - } + }), + )) } - FieldType::FieldTypeStruct { .. } => { - if let Some(ref d) = field_attrs.default { - let default_function = Ident::new(&d, field.span()); - Some(quote! { - let content = self.#label + Field::FieldStruct { .. } => Some(field.ser_wrap_default_attribute( + Some(quote!(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, &content) - } else { - struct_start_event - } - } else { - struct_start_event - }; - }) - } 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, &content) - } else { - struct_start_event - }; - }) - } - } - _ => unimplemented!(), + .map_or_else(|| Ok(String::new()), |v| yaserde::ser::to_string_content(v))?)), + quote!({ + if let Some(ref yaserde_struct) = self.#label { + struct_start_event.attr(#label_name, &yaserde_inner) + } else { + struct_start_event + } + }), + )), + Field::FieldOption { .. } => unimplemented!(), }, - FieldType::FieldTypeStruct { .. } => { - 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, &content) - } else { - struct_start_event - }; - }) - } else { - Some(quote! { - let content = yaserde::ser::to_string_content(&self.#label)?; - let struct_start_event = struct_start_event.attr(#label_name, &content); - }) - } - } - _ => None, - }) + Field::FieldStruct { .. } => Some(field.ser_wrap_default_attribute( + Some(quote!(yaserde::ser::to_string_content(&self.#label)?)), + quote!({ + struct_start_event.attr(#label_name, &yaserde_inner) + }), + )), + Field::FieldVec { .. } => None, + } }) .filter_map(|x| x) .collect(); @@ -211,54 +113,48 @@ pub fn serialize( let struct_inspector: TokenStream = data_struct .fields .iter() + .map(|field| YaSerdeField::new(field.clone())) + .filter(|field| !field.is_attribute()) .map(|field| { - let field_attrs = YaSerdeAttribute::parse(&field.attrs); - if field_attrs.attribute { - return None; - } - - let label = &field.ident; - if field_attrs.text { + let label = field.label(); + if field.is_text_content() { return Some(quote!( let data_event = XmlEvent::characters(&self.#label); writer.write(data_event).map_err(|e| e.to_string())?; )); } - let label_name = build_label_name( - &label.as_ref().unwrap(), - &field_attrs, - &root_attributes.default_namespace, - ); - let conditions = condition_generator(label, &field_attrs); + let label_name = field.renamed_label(root_attributes); + let conditions = condition_generator(&label, &field); - get_field_type(field).and_then(|f| match f { - FieldType::FieldTypeString - | FieldType::FieldTypeBool - | FieldType::FieldTypeI8 - | FieldType::FieldTypeU8 - | FieldType::FieldTypeI16 - | FieldType::FieldTypeU16 - | FieldType::FieldTypeI32 - | FieldType::FieldTypeU32 - | FieldType::FieldTypeI64 - | FieldType::FieldTypeU64 - | FieldType::FieldTypeF32 - | FieldType::FieldTypeF64 => serialize_element(label, label_name, &conditions), - FieldType::FieldTypeOption { data_type } => match *data_type { - FieldType::FieldTypeString - | FieldType::FieldTypeBool - | FieldType::FieldTypeI8 - | FieldType::FieldTypeU8 - | FieldType::FieldTypeI16 - | FieldType::FieldTypeU16 - | FieldType::FieldTypeI32 - | FieldType::FieldTypeU32 - | FieldType::FieldTypeI64 - | FieldType::FieldTypeU64 - | FieldType::FieldTypeF32 - | FieldType::FieldTypeF64 => { - let item_ident = Ident::new("yaserde_item", field.span()); + match field.get_type() { + Field::FieldString + | Field::FieldBool + | Field::FieldI8 + | Field::FieldU8 + | Field::FieldI16 + | Field::FieldU16 + | Field::FieldI32 + | Field::FieldU32 + | Field::FieldI64 + | Field::FieldU64 + | Field::FieldF32 + | Field::FieldF64 => serialize_element(&label, label_name, &conditions), + + Field::FieldOption { data_type } => match *data_type { + Field::FieldString + | Field::FieldBool + | Field::FieldI8 + | Field::FieldU8 + | Field::FieldI16 + | Field::FieldU16 + | Field::FieldI32 + | Field::FieldU32 + | Field::FieldI64 + | Field::FieldU64 + | Field::FieldF32 + | Field::FieldF64 => { + let item_ident = Ident::new("yaserde_item", field.get_span()); let inner = enclose_formatted_characters_for_value(&item_ident, label_name); Some(quote! { @@ -269,8 +165,8 @@ pub fn serialize( } }) } - FieldType::FieldTypeVec { .. } => { - let item_ident = Ident::new("yaserde_item", field.span()); + Field::FieldVec { .. } => { + let item_ident = Ident::new("yaserde_item", field.get_span()); let inner = enclose_formatted_characters_for_value(&item_ident, label_name); Some(quote! { @@ -283,7 +179,7 @@ pub fn serialize( } }) } - FieldType::FieldTypeStruct { .. } => Some(if field_attrs.flatten { + Field::FieldStruct { .. } => Some(if field.is_flatten() { quote! { if let Some(ref item) = &self.#label { writer.set_start_event_name(None); @@ -302,8 +198,8 @@ pub fn serialize( }), _ => unimplemented!(), }, - FieldType::FieldTypeStruct { .. } => { - let (start_event, skip_start) = if field_attrs.flatten { + Field::FieldStruct { .. } => { + let (start_event, skip_start) = if field.is_flatten() { (quote!(None), true) } else { (quote!(Some(#label_name.to_string())), false) @@ -315,9 +211,9 @@ pub fn serialize( self.#label.serialize(writer)?; }) } - FieldType::FieldTypeVec { data_type } => match *data_type { - FieldType::FieldTypeString => { - let item_ident = Ident::new("yaserde_item", field.span()); + Field::FieldVec { data_type } => match *data_type { + Field::FieldString => { + let item_ident = Ident::new("yaserde_item", field.get_span()); let inner = enclose_formatted_characters_for_value(&item_ident, label_name); Some(quote! { @@ -326,18 +222,18 @@ pub fn serialize( } }) } - FieldType::FieldTypeBool - | FieldType::FieldTypeI8 - | FieldType::FieldTypeU8 - | FieldType::FieldTypeI16 - | FieldType::FieldTypeU16 - | FieldType::FieldTypeI32 - | FieldType::FieldTypeU32 - | FieldType::FieldTypeI64 - | FieldType::FieldTypeU64 - | FieldType::FieldTypeF32 - | FieldType::FieldTypeF64 => { - let item_ident = Ident::new("yaserde_item", field.span()); + Field::FieldBool + | Field::FieldI8 + | Field::FieldU8 + | Field::FieldI16 + | Field::FieldU16 + | Field::FieldI32 + | Field::FieldU32 + | Field::FieldI64 + | Field::FieldU64 + | Field::FieldF32 + | Field::FieldF64 => { + let item_ident = Ident::new("yaserde_item", field.get_span()); let inner = enclose_formatted_characters_for_value(&item_ident, label_name); Some(quote! { @@ -346,7 +242,7 @@ pub fn serialize( } }) } - FieldType::FieldTypeOption { .. } => Some(quote! { + Field::FieldOption { .. } => Some(quote! { for item in &self.#label { if let Some(value) = item { writer.set_start_event_name(None); @@ -355,18 +251,18 @@ pub fn serialize( } } }), - FieldType::FieldTypeStruct { .. } => Some(quote! { + Field::FieldStruct { .. } => Some(quote! { for item in &self.#label { writer.set_start_event_name(None); writer.set_skip_start_end(false); item.serialize(writer)?; } }), - FieldType::FieldTypeVec { .. } => { + Field::FieldVec { .. } => { unimplemented!(); } }, - }) + } }) .filter_map(|x| x) .collect(); diff --git a/yaserde_derive/src/ser/implement_deserializer.rs b/yaserde_derive/src/ser/implement_deserializer.rs index b128d7b..645b4ed 100644 --- a/yaserde_derive/src/ser/implement_deserializer.rs +++ b/yaserde_derive/src/ser/implement_deserializer.rs @@ -1,4 +1,4 @@ -use crate::attribute::YaSerdeAttribute; +use crate::common::YaSerdeAttribute; use crate::ser::namespace::generate_namespaces_definition; use proc_macro2::Ident; use proc_macro2::TokenStream; diff --git a/yaserde_derive/src/ser/label.rs b/yaserde_derive/src/ser/label.rs index b77ee2e..89998a5 100644 --- a/yaserde_derive/src/ser/label.rs +++ b/yaserde_derive/src/ser/label.rs @@ -1,4 +1,4 @@ -use crate::attribute::YaSerdeAttribute; +use crate::common::YaSerdeAttribute; use proc_macro2::Ident; pub fn build_label_name( diff --git a/yaserde_derive/src/ser/mod.rs b/yaserde_derive/src/ser/mod.rs index 6e5e8c1..23d8353 100644 --- a/yaserde_derive/src/ser/mod.rs +++ b/yaserde_derive/src/ser/mod.rs @@ -5,7 +5,7 @@ pub mod implement_deserializer; pub mod label; pub mod namespace; -use crate::attribute::YaSerdeAttribute; +use crate::common::YaSerdeAttribute; use proc_macro2::TokenStream; use syn; use syn::Ident; @@ -15,25 +15,30 @@ pub fn expand_derive_serialize(ast: &syn::DeriveInput) -> Result { - expand_struct::serialize(data_struct, name, &root, &root_attrs) + expand_struct::serialize(data_struct, name, &root_name, &root_attributes) + } + syn::Data::Enum(ref data_enum) => { + expand_enum::serialize(data_enum, name, &root_name, &root_attributes) } - syn::Data::Enum(ref data_enum) => expand_enum::serialize(data_enum, name, &root, &root_attrs), syn::Data::Union(ref _data_union) => unimplemented!(), }; diff --git a/yaserde_derive/src/ser/namespace.rs b/yaserde_derive/src/ser/namespace.rs index 6a7bf5a..3127531 100644 --- a/yaserde_derive/src/ser/namespace.rs +++ b/yaserde_derive/src/ser/namespace.rs @@ -1,4 +1,4 @@ -use crate::attribute::YaSerdeAttribute; +use crate::common::YaSerdeAttribute; use proc_macro2::TokenStream; pub fn generate_namespaces_definition(attributes: &YaSerdeAttribute) -> TokenStream {