diff --git a/yaserde/src/ser/mod.rs b/yaserde/src/ser/mod.rs index 21a9e69..73f18b5 100644 --- a/yaserde/src/ser/mod.rs +++ b/yaserde/src/ser/mod.rs @@ -42,6 +42,7 @@ pub fn serialize_with_writer_content( pub struct Serializer { writer: EventWriter, skip_start_end: bool, + start_event_name: Option, } impl<'de, W: Write> Serializer { @@ -49,6 +50,7 @@ impl<'de, W: Write> Serializer { Serializer { writer, skip_start_end: false, + start_event_name: None, } } @@ -76,6 +78,14 @@ impl<'de, W: Write> Serializer { self.skip_start_end = state; } + pub fn get_start_event_name<'a>(&self) -> Option { + self.start_event_name.clone() + } + + pub fn set_start_event_name<'a>(&mut self, name: Option) { + self.start_event_name = name; + } + pub fn write<'a, E>(&mut self, event: E) -> xml::writer::Result<()> where E: Into>, diff --git a/yaserde/tests/der_option.rs b/yaserde/tests/der_option.rs index 7346dba..1e20085 100644 --- a/yaserde/tests/der_option.rs +++ b/yaserde/tests/der_option.rs @@ -116,3 +116,27 @@ fn de_option() { 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/se_option.rs b/yaserde/tests/se_option.rs index 974529b..15bbfaa 100644 --- a/yaserde/tests/se_option.rs +++ b/yaserde/tests/se_option.rs @@ -119,3 +119,27 @@ fn ser_option() { 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/serializer.rs b/yaserde/tests/serializer.rs index 68337b8..e4ee903 100644 --- a/yaserde/tests/serializer.rs +++ b/yaserde/tests/serializer.rs @@ -273,7 +273,7 @@ fn ser_enum() { }, }; - let content = "true0128255OpaqueOpaqueTransparent"; + let content = "true0128255OpaqueOpaqueTransparent"; convert_and_validate!(model, content); } diff --git a/yaserde_derive/src/de/expand_struct.rs b/yaserde_derive/src/de/expand_struct.rs index a2574ee..a874f4b 100644 --- a/yaserde_derive/src/de/expand_struct.rs +++ b/yaserde_derive/src/de/expand_struct.rs @@ -234,7 +234,18 @@ pub fn parse( Some(&FieldType::FieldTypeF64) => { build_declare_visitor("e!{f64}, "e!{visit_f64}, &visitor_label) } - _ => { + Some(&FieldType::FieldTypeStruct{ref struct_name}) => { + let struct_ident = Ident::new(&format!("{}", struct_name), Span::call_site()); + Some(quote!{ + #[allow(non_snake_case, non_camel_case_types)] + struct #visitor_label; + impl<'de> Visitor<'de> for #visitor_label { + type Value = #struct_ident; + } + }) + } + dude => { + println!("{:?}", dude); unimplemented!(); } } @@ -602,7 +613,24 @@ pub fn parse( &label_name, ) } - _ => None, + Some(&FieldType::FieldTypeStruct { ref struct_name }) => { + let struct_ident = Ident::new(&format!("{}", struct_name), Span::call_site()); + Some(quote!{ + #label_name => { + reader.set_map_value(); + match #struct_ident::deserialize(reader) { + Ok(parsed_item) => { + #label = Some(parsed_item); + let _root = reader.next_event(); + }, + Err(msg) => { + return Err(msg); + }, + } + } + }) + } + _ => unimplemented!(), } } Some(FieldType::FieldTypeVec { data_type }) => { diff --git a/yaserde_derive/src/ser/expand_enum.rs b/yaserde_derive/src/ser/expand_enum.rs index 67542f1..8299d80 100644 --- a/yaserde_derive/src/ser/expand_enum.rs +++ b/yaserde_derive/src/ser/expand_enum.rs @@ -123,13 +123,7 @@ pub fn serialize( Some(quote!{ &#name::#label{..} => { - let struct_start_event = XmlEvent::start_element(#label_name); - let _ret = writer.write(struct_start_event); - #enum_fields - - let struct_end_event = XmlEvent::end_element(); - let _ret = writer.write(struct_end_event); } }) } @@ -164,6 +158,11 @@ pub fn serialize( #[allow(unused_variables)] fn serialize(&self, writer: &mut yaserde::ser::Serializer) -> Result<(), String> { + if let Some(label) = writer.get_start_event_name() { + let struct_start_event = XmlEvent::start_element(label.as_ref()); + let _ret = writer.write(struct_start_event); + return Ok(()); + } error!("Enum: start to expand {:?}", #root); if !writer.skip_start_end() { diff --git a/yaserde_derive/src/ser/expand_struct.rs b/yaserde_derive/src/ser/expand_struct.rs index f65dddd..f8d9917 100644 --- a/yaserde_derive/src/ser/expand_struct.rs +++ b/yaserde_derive/src/ser/expand_struct.rs @@ -105,7 +105,7 @@ pub fn serialize( let _ret = writer.write(end_event); } }), - _ => None, + _ => unimplemented!(), } } Some(FieldType::FieldTypeStruct { .. }) => Some(quote!{ @@ -170,7 +170,7 @@ pub fn serialize( }; let label_name = if let Some(prefix) = field_attrs.prefix { - prefix + ":" + renamed_label.to_string().as_ref() + format!("{}:{}", prefix, renamed_label) } else { renamed_label.to_string() }; @@ -260,17 +260,46 @@ pub fn serialize( } } }), - _ => None, + Some(&FieldType::FieldTypeStruct { .. }) => Some(quote!{ + if let Some(ref item) = &self.#label { + let start_event = XmlEvent::start_element(#label_name); + let _ret = writer.write(start_event); + + writer.set_skip_start_end(false); + match item.serialize(writer) { + Ok(()) => {}, + Err(msg) => { + return Err(msg); + }, + }; + + let end_event = XmlEvent::end_element(); + let _ret = writer.write(end_event); + } + }), + _ => unimplemented!(), } } Some(FieldType::FieldTypeStruct { .. }) => Some(quote!{ - writer.set_skip_start_end(false); + writer.set_start_event_name(Some(#label_name.to_string())); match self.#label.serialize(writer) { Ok(()) => {}, Err(msg) => { return Err(msg); }, }; + writer.set_start_event_name(None); + + writer.set_skip_start_end(true); + match self.#label.serialize(writer) { + Ok(()) => {}, + Err(msg) => { + return Err(msg); + }, + }; + + let end_event = XmlEvent::end_element(); + let _ret = writer.write(end_event); }), Some(FieldType::FieldTypeVec { data_type }) => { let dt = Box::into_raw(data_type); @@ -358,6 +387,12 @@ pub fn serialize( #[allow(unused_variables)] fn serialize(&self, writer: &mut yaserde::ser::Serializer) -> Result<(), String> { + if let Some(label) = writer.get_start_event_name() { + let struct_start_event = XmlEvent::start_element(label.as_ref()); + #build_attributes + let _ret = writer.write(struct_start_event); + return Ok(()) + } error!("Struct: start to expand {:?}", #root); let skip = writer.skip_start_end(); if !skip {