From 95f826b41f426fb57f1dd02d0c26965abcc79210 Mon Sep 17 00:00:00 2001 From: Dmitry Samoylov Date: Mon, 30 Dec 2019 22:38:45 +0700 Subject: [PATCH] Add serialization for enums with unnamed fields (#8) --- yaserde/tests/serializer.rs | 126 ++++++++++++++++++++++++++ yaserde_derive/src/ser/expand_enum.rs | 99 +++++++++++++++++++- 2 files changed, 224 insertions(+), 1 deletion(-) diff --git a/yaserde/tests/serializer.rs b/yaserde/tests/serializer.rs index 1290131..a1ba1ca 100644 --- a/yaserde/tests/serializer.rs +++ b/yaserde/tests/serializer.rs @@ -299,6 +299,132 @@ fn ser_attribute_enum() { 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), + } + + impl Default for Enum { + fn default() -> Enum { + Enum::Simple + } + } + + let model = XmlStruct { + color: Enum::Field(String::from("some_text")), + }; + + let content = "some_text"; + convert_and_validate!(model, content); + + let model = XmlStruct { + color: Enum::FullPath(String::from("some_text")), + }; + + let content = "some_text"; + convert_and_validate!(model, content); + + let model = XmlStruct { + color: Enum::Integer(56), + }; + + let content = + "56"; + convert_and_validate!(model, content); + + let model = XmlStruct { + color: Enum::UserStruct(OtherStruct { fi: 24, se: 42 }), + }; + + let content = "2442"; + convert_and_validate!(model, content); + + let model = XmlStruct { + color: Enum::OptionString(Some(String::from("some_text"))), + }; + + let content = "some_text"; + convert_and_validate!(model, content); + + let model = XmlStruct { + color: Enum::OptionString(None), + }; + + let content = ""; + convert_and_validate!(model, content); + + let model = XmlStruct { + color: Enum::OptionUserStruct(Some(OtherStruct { fi: 12, se: 23 })), + }; + + let content = "1223"; + convert_and_validate!(model, content); + + let model = XmlStruct { + color: Enum::OptionUserStruct(None), + }; + + let content = ""; + convert_and_validate!(model, content); + + let model = XmlStruct { + color: Enum::Strings(vec![String::from("abc"), String::from("def")]), + }; + + let content = "abcdef"; + convert_and_validate!(model, content); + + let model = XmlStruct { + color: Enum::Ints(vec![23, 45]), + }; + + let content = "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 = "12233445"; + convert_and_validate!(model, content); + + let model = XmlStruct { + color: Enum::ToRename(87), + }; + + let content = + "87"; + convert_and_validate!(model, content); +} + #[test] fn ser_name_issue_21() { #[derive(YaSerialize, PartialEq, Debug)] diff --git a/yaserde_derive/src/ser/expand_enum.rs b/yaserde_derive/src/ser/expand_enum.rs index 693bf0b..70ce614 100644 --- a/yaserde_derive/src/ser/expand_enum.rs +++ b/yaserde_derive/src/ser/expand_enum.rs @@ -127,7 +127,104 @@ pub fn serialize( } }) } - Fields::Unnamed(ref _fields) => unimplemented!(), + Fields::Unnamed(ref fields) => { + let enum_fields: TokenStream = fields + .unnamed + .iter() + .map(|field| { + let field_attrs = YaSerdeAttribute::parse(&field.attrs); + if field_attrs.attribute { + return None; + } + + let field_label_name = renamed_label.to_string(); + + let write_element = |action: &TokenStream| { + quote! { + let struct_start_event = XmlEvent::start_element(#field_label_name); + let _ret = writer.write(struct_start_event); + + #action + + let struct_end_event = XmlEvent::end_element(); + let _ret = writer.write(struct_end_event); + } + }; + + let write_string_chars = quote! { + let data_event = XmlEvent::characters(item); + let _ret = writer.write(data_event); + }; + + let write_simple_type = write_element("e! { + let s = item.to_string(); + let data_event = XmlEvent::characters(&s); + let _ret = writer.write(data_event); + }); + + let serialize = quote! { + writer.set_skip_start_end(true); + if let Err(msg) = item.serialize(writer) { + return Err(msg); + }; + }; + + let write_sub_type = |data_type| { + write_element(match data_type { + FieldType::FieldTypeString => &write_string_chars, + _ => &serialize, + }) + }; + + let match_field = |write: &TokenStream| { + quote! { + match self { + &#name::#label(ref item) => { + #write + }, + _ => {}, + } + } + }; + + match get_field_type(field) { + Some(FieldType::FieldTypeOption { data_type }) => { + let write = write_sub_type(*data_type); + + Some(match_field("e! { + if let Some(item) = item { + #write + } + })) + } + Some(FieldType::FieldTypeVec { data_type }) => { + let write = write_sub_type(*data_type); + + Some(match_field("e! { + for item in item { + #write + } + })) + } + 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, + } + }) + .filter_map(|x| x) + .collect(); + + Some(quote! { + &#name::#label{..} => { + #enum_fields + } + }) + } } }) .filter(|x| x.is_some())