diff --git a/yaserde/tests/der_option.rs b/yaserde/tests/der_option.rs new file mode 100644 index 0000000..67d0222 --- /dev/null +++ b/yaserde/tests/der_option.rs @@ -0,0 +1,116 @@ +#[macro_use] +extern crate log; +extern crate xml; +extern crate yaserde; +#[macro_use] +extern crate yaserde_derive; + +use std::io::Read; +use yaserde::YaDeserialize; +use yaserde::de::from_str; + +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); +} diff --git a/yaserde/tests/der_type.rs b/yaserde/tests/der_type.rs index edc06aa..ba96c0d 100644 --- a/yaserde/tests/der_type.rs +++ b/yaserde/tests/der_type.rs @@ -48,6 +48,7 @@ macro_rules! convert_and_validate_for_attribute { #[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"); @@ -64,6 +65,7 @@ fn de_type() { 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"); diff --git a/yaserde/tests/se_option.rs b/yaserde/tests/se_option.rs new file mode 100644 index 0000000..f177b20 --- /dev/null +++ b/yaserde/tests/se_option.rs @@ -0,0 +1,116 @@ +#[macro_use] +extern crate log; +extern crate xml; +extern crate yaserde; +#[macro_use] +extern crate yaserde_derive; + +use std::io::Write; +use yaserde::YaSerialize; +use yaserde::ser::to_string; + +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_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); +} diff --git a/yaserde/tests/se_type.rs b/yaserde/tests/se_type.rs index 4da602d..cce650a 100644 --- a/yaserde/tests/se_type.rs +++ b/yaserde/tests/se_type.rs @@ -44,6 +44,7 @@ macro_rules! convert_and_validate_as_attribute { #[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"); @@ -60,6 +61,7 @@ fn ser_type() { convert_and_validate!(f32, -12.5 as f32, "-12.5"); convert_and_validate!(f64, -12.5 as f64, "-12.5"); + 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"); diff --git a/yaserde_derive/src/de/expand_enum.rs b/yaserde_derive/src/de/expand_enum.rs index d148b03..466c0b6 100644 --- a/yaserde_derive/src/de/expand_enum.rs +++ b/yaserde_derive/src/de/expand_enum.rs @@ -66,6 +66,10 @@ pub fn parse( #[allow(unused_mut)] let mut #field_label : #struct_name = #struct_name::default(); }), + Some(FieldType::FieldTypeOption { .. }) => Some(quote!{ + #[allow(unused_mut)] + let mut #field_label = None; + }), Some(FieldType::FieldTypeVec { data_type }) => { let dt = Box::into_raw(data_type); match unsafe { dt.as_ref() } { @@ -109,7 +113,8 @@ pub fn parse( #[allow(unused_mut)] let mut #field_label : Vec<#struct_name> = vec![]; }), - Some(&FieldType::FieldTypeVec { .. }) => { + Some(&FieldType::FieldTypeOption { .. }) + | Some(&FieldType::FieldTypeVec { .. }) => { unimplemented!(); } None => { diff --git a/yaserde_derive/src/de/expand_struct.rs b/yaserde_derive/src/de/expand_struct.rs index 6ba1cf8..207a477 100644 --- a/yaserde_derive/src/de/expand_struct.rs +++ b/yaserde_derive/src/de/expand_struct.rs @@ -62,6 +62,10 @@ pub fn parse( #[allow(unused_mut, non_snake_case, non_camel_case_types)] let mut #label : #struct_name = #struct_name::default(); }), + Some(FieldType::FieldTypeOption { .. }) => Some(quote!{ + #[allow(unused_mut, non_snake_case, non_camel_case_types)] + let mut #label = None; + }), Some(FieldType::FieldTypeVec { data_type }) => { let dt = Box::into_raw(data_type); match unsafe { dt.as_ref() } { @@ -105,7 +109,7 @@ pub fn parse( #[allow(unused_mut)] let mut #label : Vec<#struct_name> = vec![]; }), - Some(&FieldType::FieldTypeVec { .. }) => { + Some(&FieldType::FieldTypeOption { .. }) | Some(&FieldType::FieldTypeVec { .. }) => { unimplemented!(); } None => { @@ -194,6 +198,50 @@ pub fn parse( } }) } + Some(FieldType::FieldTypeOption { data_type }) => { + let dt = Box::into_raw(data_type); + match unsafe { dt.as_ref() } { + Some(&FieldType::FieldTypeString) => { + build_declare_visitor("e!{String}, "e!{visit_str}, &visitor_label) + } + Some(&FieldType::FieldTypeBool) => { + build_declare_visitor("e!{bool}, "e!{visit_bool}, &visitor_label) + } + Some(&FieldType::FieldTypeI8) => { + build_declare_visitor("e!{i8}, "e!{visit_i8}, &visitor_label) + } + Some(&FieldType::FieldTypeU8) => { + build_declare_visitor("e!{u8}, "e!{visit_u8}, &visitor_label) + } + Some(&FieldType::FieldTypeI16) => { + build_declare_visitor("e!{i16}, "e!{visit_i16}, &visitor_label) + } + Some(&FieldType::FieldTypeU16) => { + build_declare_visitor("e!{u16}, "e!{visit_u16}, &visitor_label) + } + Some(&FieldType::FieldTypeI32) => { + build_declare_visitor("e!{i32}, "e!{visit_i32}, &visitor_label) + } + Some(&FieldType::FieldTypeU32) => { + build_declare_visitor("e!{u32}, "e!{visit_u32}, &visitor_label) + } + Some(&FieldType::FieldTypeI64) => { + build_declare_visitor("e!{i64}, "e!{visit_i64}, &visitor_label) + } + Some(&FieldType::FieldTypeU64) => { + build_declare_visitor("e!{u64}, "e!{visit_u64}, &visitor_label) + } + Some(&FieldType::FieldTypeF32) => { + build_declare_visitor("e!{f32}, "e!{visit_f32}, &visitor_label) + } + Some(&FieldType::FieldTypeF64) => { + build_declare_visitor("e!{f64}, "e!{visit_f64}, &visitor_label) + } + _ => { + unimplemented!(); + } + } + } Some(FieldType::FieldTypeVec { data_type }) => { let dt = Box::into_raw(data_type); match unsafe { dt.as_ref() } { @@ -422,6 +470,144 @@ pub fn parse( } } }), + Some(FieldType::FieldTypeOption { data_type }) => { + let dt = Box::into_raw(data_type); + match unsafe { dt.as_ref() } { + Some(&FieldType::FieldTypeString) => { + let visitor = Ident::new("visit_str", Span::call_site()); + build_call_visitor( + "e!{String}, + &visitor, + "e!{= Some(value)}, + &visitor_label, + label, + &label_name, + ) + } + Some(&FieldType::FieldTypeBool) => { + let visitor = Ident::new("visit_bool", Span::call_site()); + build_call_visitor( + "e!{bool}, + &visitor, + "e!{= Some(value)}, + &visitor_label, + label, + &label_name, + ) + } + Some(&FieldType::FieldTypeU8) => { + let visitor = Ident::new("visit_u8", Span::call_site()); + build_call_visitor( + "e!{u8}, + &visitor, + "e!{= Some(value)}, + &visitor_label, + label, + &label_name, + ) + } + Some(&FieldType::FieldTypeI8) => { + let visitor = Ident::new("visit_i8", Span::call_site()); + build_call_visitor( + "e!{i8}, + &visitor, + "e!{= Some(value)}, + &visitor_label, + label, + &label_name, + ) + } + Some(&FieldType::FieldTypeU16) => { + let visitor = Ident::new("visit_u16", Span::call_site()); + build_call_visitor( + "e!{u16}, + &visitor, + "e!{= Some(value)}, + &visitor_label, + label, + &label_name, + ) + } + Some(&FieldType::FieldTypeI16) => { + let visitor = Ident::new("visit_i16", Span::call_site()); + build_call_visitor( + "e!{i16}, + &visitor, + "e!{= Some(value)}, + &visitor_label, + label, + &label_name, + ) + } + Some(&FieldType::FieldTypeU32) => { + let visitor = Ident::new("visit_u32", Span::call_site()); + build_call_visitor( + "e!{u32}, + &visitor, + "e!{= Some(value)}, + &visitor_label, + label, + &label_name, + ) + } + Some(&FieldType::FieldTypeI32) => { + let visitor = Ident::new("visit_i32", Span::call_site()); + build_call_visitor( + "e!{i32}, + &visitor, + "e!{= Some(value)}, + &visitor_label, + label, + &label_name, + ) + } + Some(&FieldType::FieldTypeU64) => { + let visitor = Ident::new("visit_u64", Span::call_site()); + build_call_visitor( + "e!{u64}, + &visitor, + "e!{= Some(value)}, + &visitor_label, + label, + &label_name, + ) + } + Some(&FieldType::FieldTypeI64) => { + let visitor = Ident::new("visit_i64", Span::call_site()); + build_call_visitor( + "e!{i64}, + &visitor, + "e!{= Some(value)}, + &visitor_label, + label, + &label_name, + ) + } + Some(&FieldType::FieldTypeF32) => { + let visitor = Ident::new("visit_f32", Span::call_site()); + build_call_visitor( + "e!{f32}, + &visitor, + "e!{= Some(value)}, + &visitor_label, + label, + &label_name, + ) + } + Some(&FieldType::FieldTypeF64) => { + let visitor = Ident::new("visit_f64", Span::call_site()); + build_call_visitor( + "e!{f64}, + &visitor, + "e!{= Some(value)}, + &visitor_label, + label, + &label_name, + ) + } + _ => None, + } + } Some(FieldType::FieldTypeVec { data_type }) => { let dt = Box::into_raw(data_type); match unsafe { dt.as_ref() } { @@ -613,40 +799,173 @@ pub fn parse( } } }), - Some(FieldType::FieldTypeBool) => { - build_call_visitor_for_attribute(label, &label_name, "e!{visit_bool}, &visitor_label) + Some(FieldType::FieldTypeBool) => build_call_visitor_for_attribute( + label, + &label_name, + "e!{= value}, + "e!{visit_bool}, + &visitor_label, + ), + Some(FieldType::FieldTypeI8) => build_call_visitor_for_attribute( + label, + &label_name, + "e!{= value}, + "e!{visit_i8}, + &visitor_label, + ), + Some(FieldType::FieldTypeU8) => build_call_visitor_for_attribute( + label, + &label_name, + "e!{= value}, + "e!{visit_u8}, + &visitor_label, + ), + Some(FieldType::FieldTypeI16) => build_call_visitor_for_attribute( + label, + &label_name, + "e!{= value}, + "e!{visit_i16}, + &visitor_label, + ), + Some(FieldType::FieldTypeU16) => build_call_visitor_for_attribute( + label, + &label_name, + "e!{= value}, + "e!{visit_u16}, + &visitor_label, + ), + Some(FieldType::FieldTypeI32) => build_call_visitor_for_attribute( + label, + &label_name, + "e!{= value}, + "e!{visit_i32}, + &visitor_label, + ), + Some(FieldType::FieldTypeU32) => build_call_visitor_for_attribute( + label, + &label_name, + "e!{= value}, + "e!{visit_u32}, + &visitor_label, + ), + Some(FieldType::FieldTypeI64) => build_call_visitor_for_attribute( + label, + &label_name, + "e!{= value}, + "e!{visit_i64}, + &visitor_label, + ), + Some(FieldType::FieldTypeU64) => build_call_visitor_for_attribute( + label, + &label_name, + "e!{= value}, + "e!{visit_u64}, + &visitor_label, + ), + Some(FieldType::FieldTypeF32) => build_call_visitor_for_attribute( + label, + &label_name, + "e!{= value}, + "e!{visit_f32}, + &visitor_label, + ), + Some(FieldType::FieldTypeF64) => build_call_visitor_for_attribute( + label, + &label_name, + "e!{= value}, + "e!{visit_f64}, + &visitor_label, + ), + Some(FieldType::FieldTypeOption { data_type }) => { + let dt = Box::into_raw(data_type); + match unsafe { dt.as_ref() } { + Some(&FieldType::FieldTypeString) => build_call_visitor_for_attribute( + label, + &label_name, + "e!{= Some(value)}, + "e!{visit_str}, + &visitor_label, + ), + Some(&FieldType::FieldTypeBool) => build_call_visitor_for_attribute( + label, + &label_name, + "e!{= Some(value)}, + "e!{visit_bool}, + &visitor_label, + ), + Some(&FieldType::FieldTypeU8) => build_call_visitor_for_attribute( + label, + &label_name, + "e!{= Some(value)}, + "e!{visit_u8}, + &visitor_label, + ), + Some(&FieldType::FieldTypeI8) => build_call_visitor_for_attribute( + label, + &label_name, + "e!{= Some(value)}, + "e!{visit_i8}, + &visitor_label, + ), + Some(&FieldType::FieldTypeU16) => build_call_visitor_for_attribute( + label, + &label_name, + "e!{= Some(value)}, + "e!{visit_u16}, + &visitor_label, + ), + Some(&FieldType::FieldTypeI16) => build_call_visitor_for_attribute( + label, + &label_name, + "e!{= Some(value)}, + "e!{visit_i16}, + &visitor_label, + ), + Some(&FieldType::FieldTypeU32) => build_call_visitor_for_attribute( + label, + &label_name, + "e!{= Some(value)}, + "e!{visit_u32}, + &visitor_label, + ), + Some(&FieldType::FieldTypeI32) => build_call_visitor_for_attribute( + label, + &label_name, + "e!{= Some(value)}, + "e!{visit_i32}, + &visitor_label, + ), + Some(&FieldType::FieldTypeU64) => build_call_visitor_for_attribute( + label, + &label_name, + "e!{= Some(value)}, + "e!{visit_u64}, + &visitor_label, + ), + Some(&FieldType::FieldTypeI64) => build_call_visitor_for_attribute( + label, + &label_name, + "e!{= Some(value)}, + "e!{visit_i64}, + &visitor_label, + ), + Some(&FieldType::FieldTypeF32) => build_call_visitor_for_attribute( + label, + &label_name, + "e!{= Some(value)}, + "e!{visit_f32}, + &visitor_label, + ), + Some(&FieldType::FieldTypeF64) => build_call_visitor_for_attribute( + label, + &label_name, + "e!{= Some(value)}, + "e!{visit_f64}, + &visitor_label, + ), + _ => None, + } } - Some(FieldType::FieldTypeI8) => { - build_call_visitor_for_attribute(label, &label_name, "e!{visit_i8}, &visitor_label) - } - Some(FieldType::FieldTypeU8) => { - build_call_visitor_for_attribute(label, &label_name, "e!{visit_u8}, &visitor_label) - } - Some(FieldType::FieldTypeI16) => { - build_call_visitor_for_attribute(label, &label_name, "e!{visit_i16}, &visitor_label) - } - Some(FieldType::FieldTypeU16) => { - build_call_visitor_for_attribute(label, &label_name, "e!{visit_u16}, &visitor_label) - } - Some(FieldType::FieldTypeI32) => { - build_call_visitor_for_attribute(label, &label_name, "e!{visit_i32}, &visitor_label) - } - Some(FieldType::FieldTypeU32) => { - build_call_visitor_for_attribute(label, &label_name, "e!{visit_u32}, &visitor_label) - } - Some(FieldType::FieldTypeI64) => { - build_call_visitor_for_attribute(label, &label_name, "e!{visit_i64}, &visitor_label) - } - Some(FieldType::FieldTypeU64) => { - build_call_visitor_for_attribute(label, &label_name, "e!{visit_u64}, &visitor_label) - } - Some(FieldType::FieldTypeF32) => { - build_call_visitor_for_attribute(label, &label_name, "e!{visit_f32}, &visitor_label) - } - Some(FieldType::FieldTypeF64) => { - build_call_visitor_for_attribute(label, &label_name, "e!{visit_f64}, &visitor_label) - } - Some(FieldType::FieldTypeStruct { struct_name }) => { let struct_ident = Ident::new( &format!("__Visitor_{}_{}", label_name, struct_name), @@ -742,9 +1061,10 @@ pub fn parse( "e!{f64::from_str(text_content).unwrap()}, ), - Some(FieldType::FieldTypeStruct { .. }) | Some(FieldType::FieldTypeVec { .. }) | None => { - None - } + Some(FieldType::FieldTypeStruct { .. }) + | Some(FieldType::FieldTypeOption { .. }) + | Some(FieldType::FieldTypeVec { .. }) + | None => None, } }) .filter(|x| x.is_some()) @@ -900,6 +1220,7 @@ fn build_call_visitor( fn build_call_visitor_for_attribute( label: &Option, label_name: &str, + action: &TokenStream, visitor: &TokenStream, visitor_label: &Ident, ) -> Option { @@ -908,7 +1229,7 @@ fn build_call_visitor_for_attribute( if attr.name.local_name == #label_name { let visitor = #visitor_label{}; match visitor.#visitor(&attr.value) { - Ok(value) => {#label = value;} + Ok(value) => {#label #action;} Err(msg) => {return Err(msg);} } } diff --git a/yaserde_derive/src/field_type.rs b/yaserde_derive/src/field_type.rs index ee5b251..f50a13a 100644 --- a/yaserde_derive/src/field_type.rs +++ b/yaserde_derive/src/field_type.rs @@ -16,6 +16,7 @@ pub enum FieldType { FieldTypeU64, FieldTypeF32, FieldTypeF64, + FieldTypeOption { data_type: Box }, FieldTypeVec { data_type: Box }, FieldTypeStruct { struct_name: syn::Ident }, } @@ -35,7 +36,17 @@ impl FieldType { "u64" => Some(FieldType::FieldTypeU64), "f32" => Some(FieldType::FieldTypeF32), "f64" => Some(FieldType::FieldTypeF64), - "Vec" => get_vec_type(t).map(|data_type| { + "Option" => get_sub_type(t).map(|data_type| { + let p = syn::PathSegment { + ident: data_type, + arguments: syn::PathArguments::None, + }; + + FieldType::FieldTypeOption { + data_type: Box::new(FieldType::from_ident(&p).unwrap()), + } + }), + "Vec" => get_sub_type(t).map(|data_type| { let p = syn::PathSegment { ident: data_type, arguments: syn::PathArguments::None, @@ -62,7 +73,7 @@ pub fn get_field_type(field: &syn::Field) -> Option { } } -fn get_vec_type(t: &syn::PathSegment) -> Option { +fn get_sub_type(t: &syn::PathSegment) -> Option { if let syn::PathArguments::AngleBracketed(ref args) = t.arguments { if let Some(Pair::End(tt)) = args.args.first() { if let syn::GenericArgument::Type(ref argument) = *tt { diff --git a/yaserde_derive/src/ser/expand_struct.rs b/yaserde_derive/src/ser/expand_struct.rs index 10612c7..bdcc813 100644 --- a/yaserde_derive/src/ser/expand_struct.rs +++ b/yaserde_derive/src/ser/expand_struct.rs @@ -46,7 +46,7 @@ pub fn serialize( | Some(FieldType::FieldTypeU64) | Some(FieldType::FieldTypeF32) | Some(FieldType::FieldTypeF64) => Some(quote!{ - .attr(#label_name, &*{ + let struct_start_event = struct_start_event.attr(#label_name, &*{ use std::mem; unsafe { let content = format!("{}", self.#label); @@ -54,11 +54,50 @@ pub fn serialize( mem::forget(content); ret } - - }) + }); }), + Some(FieldType::FieldTypeOption { data_type }) => { + let dt = Box::into_raw(data_type); + match unsafe { dt.as_ref() } { + Some(&FieldType::FieldTypeString) => Some(quote!{ + let struct_start_event = + if let Some(ref value) = self.#label { + struct_start_event.attr(#label_name, &value) + } else { + struct_start_event + }; + }), + Some(&FieldType::FieldTypeBool) + | Some(&FieldType::FieldTypeI8) + | Some(&FieldType::FieldTypeU8) + | Some(&FieldType::FieldTypeI16) + | Some(&FieldType::FieldTypeU16) + | Some(&FieldType::FieldTypeI32) + | Some(&FieldType::FieldTypeU32) + | Some(&FieldType::FieldTypeI64) + | Some(&FieldType::FieldTypeU64) + | Some(&FieldType::FieldTypeF32) + | Some(&FieldType::FieldTypeF64) => Some(quote!{ + let struct_start_event = + if let Some(value) = self.#label { + struct_start_event.attr(#label_name, &*{ + use std::mem; + unsafe { + let content = format!("{}", value); + let ret : &'static str = mem::transmute(&content as &str); + mem::forget(content); + ret + } + }) + } else { + struct_start_event + }; + }), + _ => None, + } + } Some(FieldType::FieldTypeStruct { .. }) => Some(quote!{ - .attr(#label_name, &*{ + let struct_start_event = struct_start_event.attr(#label_name, &*{ use std::mem; match yaserde::ser::to_string_content(&self.#label) { Ok(value) => { @@ -70,7 +109,7 @@ pub fn serialize( }, Err(msg) => return Err("Unable to serialize content".to_owned()), } - }) + }); }), _ => None, } @@ -156,6 +195,47 @@ pub fn serialize( let end_event = XmlEvent::end_element(); let _ret = writer.write(end_event); }), + Some(FieldType::FieldTypeOption { data_type }) => { + let dt = Box::into_raw(data_type); + match unsafe { dt.as_ref() } { + Some(&FieldType::FieldTypeString) => Some(quote!{ + if let Some(ref item) = self.#label { + let start_event = XmlEvent::start_element(#label_name); + let _ret = writer.write(start_event); + + let data_event = XmlEvent::characters(&item); + let _ret = writer.write(data_event); + + let end_event = XmlEvent::end_element(); + let _ret = writer.write(end_event); + } + }), + Some(&FieldType::FieldTypeBool) + | Some(&FieldType::FieldTypeI8) + | Some(&FieldType::FieldTypeU8) + | Some(&FieldType::FieldTypeI16) + | Some(&FieldType::FieldTypeU16) + | Some(&FieldType::FieldTypeI32) + | Some(&FieldType::FieldTypeU32) + | Some(&FieldType::FieldTypeI64) + | Some(&FieldType::FieldTypeU64) + | Some(&FieldType::FieldTypeF32) + | Some(&FieldType::FieldTypeF64) => Some(quote!{ + if let Some(item) = self.#label { + let start_event = XmlEvent::start_element(#label_name); + let _ret = writer.write(start_event); + + let content = format!("{}", item); + let data_event = XmlEvent::characters(&content); + let _ret = writer.write(data_event); + + let end_event = XmlEvent::end_element(); + let _ret = writer.write(end_event); + } + }), + _ => None, + } + } Some(FieldType::FieldTypeStruct { .. }) => Some(quote!{ writer.set_skip_start_end(false); match self.#label.serialize(writer) { @@ -202,6 +282,19 @@ pub fn serialize( let _ret = writer.write(end_event); } }), + Some(&FieldType::FieldTypeOption { .. }) => Some(quote!{ + for item in &self.#label { + if let Some(value) = item { + writer.set_skip_start_end(false); + match value.serialize(writer) { + Ok(()) => {}, + Err(msg) => { + return Err(msg); + }, + }; + } + } + }), Some(&FieldType::FieldTypeStruct { .. }) => Some(quote!{ for item in &self.#label { writer.set_skip_start_end(false); @@ -241,7 +334,8 @@ pub fn serialize( error!("Struct: start to expand {:?}", #root); let skip = writer.skip_start_end(); if !skip { - let struct_start_event = XmlEvent::start_element(#root)#build_attributes#add_namespaces; + let struct_start_event = XmlEvent::start_element(#root)#add_namespaces; + #build_attributes let _ret = writer.write(struct_start_event); }