diff --git a/yaserde/src/lib.rs b/yaserde/src/lib.rs index 77db2a5..9702656 100644 --- a/yaserde/src/lib.rs +++ b/yaserde/src/lib.rs @@ -14,5 +14,5 @@ pub trait YaDeserialize : Sized { } pub trait YaSerialize : Sized { - fn derive_serialize(&self, read: &mut EventWriter, parent_attributes: Option<&Vec>) -> Result<(), String>; + fn derive_serialize(&self, read: &mut EventWriter) -> Result<(), String>; } diff --git a/yaserde/tests/serializer.rs b/yaserde/tests/serializer.rs index ad9cab1..8424f8c 100644 --- a/yaserde/tests/serializer.rs +++ b/yaserde/tests/serializer.rs @@ -11,17 +11,17 @@ use xml::writer::EventWriter; use yaserde::YaSerialize; macro_rules! convert_and_validate { - ($model:expr, $content:expr) => { + ($model:expr, $content:expr) => ( let mut buf = Cursor::new(Vec::new()); let mut writer = EventWriter::new(&mut buf); - let _status = $model.derive_serialize(&mut writer, None); + let _status = $model.derive_serialize(&mut writer); let buffer = writer.into_inner(); let cursor = buffer.get_ref(); let data = str::from_utf8(cursor).expect("Found invalid UTF-8"); assert_eq!(data, $content); - } + ) } #[test] @@ -57,4 +57,118 @@ fn ser_list_of_items() { let content = "something1something2".to_string(); convert_and_validate!(model, content); -} \ No newline at end of file +} + +#[test] +fn se_attributes() { + #[derive(YaSerialize, PartialEq, Debug)] + #[yaserde(root="base")] + pub struct XmlStruct { + #[yaserde(attribute)] + item: String, + sub: SubStruct + } + + #[derive(YaSerialize, PartialEq, Debug)] + #[yaserde(root="sub")] + pub struct SubStruct { + #[yaserde(attribute)] + subitem: String + } + + impl Default for SubStruct { + fn default() -> SubStruct { + SubStruct{ + subitem: "".to_string() + } + } + } + + let model = XmlStruct{ + item: "something".to_string(), + sub: SubStruct{ + subitem: "sub-something".to_string() + } + }; + + let content = ""; + convert_and_validate!(model, content); +} + +#[test] +fn ser_rename() { + #[derive(YaSerialize, PartialEq, Debug)] + #[yaserde(root="base")] + pub struct XmlStruct { + #[yaserde(attribute, rename="Item")] + item: String, + #[yaserde(rename="sub")] + sub_struct: SubStruct + } + + #[derive(YaSerialize, PartialEq, Debug)] + #[yaserde(root="sub")] + pub struct SubStruct { + #[yaserde(attribute, rename="sub_item")] + subitem: String, + } + + impl Default for SubStruct { + fn default() -> SubStruct { + SubStruct{ + subitem: "".to_string() + } + } + } + + let model = XmlStruct{ + item: "something".to_string(), + sub_struct: SubStruct{ + subitem: "sub_something".to_string() + } + }; + + let content = ""; + convert_and_validate!(model, content); +} + +#[test] +fn ser_text_content_with_attributes() { + #[derive(YaSerialize, PartialEq, Debug)] + #[yaserde(root="base")] + pub struct XmlStruct { + #[yaserde(attribute, rename="Item")] + item: String, + #[yaserde(rename="sub")] + sub_struct: SubStruct + } + + #[derive(YaSerialize, PartialEq, Debug)] + #[yaserde(root="sub")] + pub struct SubStruct { + #[yaserde(attribute, rename="sub_item")] + subitem: String, + #[yaserde(text)] + text: String, + } + + impl Default for SubStruct { + fn default() -> SubStruct { + SubStruct{ + subitem: "".to_string(), + text: "".to_string(), + } + } + } + + let model = XmlStruct{ + item: "something".to_string(), + sub_struct: SubStruct{ + subitem: "sub_something".to_string(), + text: "text_content".to_string() + } + }; + + let content = "text_content"; + convert_and_validate!(model, content); +} diff --git a/yaserde_derive/src/ser/expand_struct.rs b/yaserde_derive/src/ser/expand_struct.rs index 442591a..ef18d93 100644 --- a/yaserde_derive/src/ser/expand_struct.rs +++ b/yaserde_derive/src/ser/expand_struct.rs @@ -7,9 +7,13 @@ use syn::DataStruct; use proc_macro2::Span; pub fn serialize(data_struct: &DataStruct, name: &Ident, root: &String) -> Tokens { - let struct_inspector : Tokens = data_struct.fields.iter().map(|ref field| + let build_attributes : Tokens = data_struct.fields.iter().map(|ref field| { let field_attrs = YaSerdeAttribute::parse(&field.attrs); + if field_attrs.attribute == false { + return None; + } + let renamed_label = match field_attrs.rename { Some(value) => Some(Ident::new(&format!("{}", value), Span::call_site())), @@ -21,30 +25,66 @@ pub fn serialize(data_struct: &DataStruct, name: &Ident, root: &String) -> Token match get_field_type(field) { Some(FieldType::FieldTypeString) => Some(quote!{ - let start_event = xml::writer::events::XmlEvent::start_element(#label_name); - let data_event = xml::writer::events::XmlEvent::characters(&self.#label); - let end_event = xml::writer::events::XmlEvent::end_element(); + .attr(#label_name, &self.#label) + }), + _ => None + } + }) + .filter(|x| x.is_some()) + .map(|x| x.unwrap()) + .fold(Tokens::new(), |mut tokens, token| {tokens.append_all(token); tokens}); + + let struct_inspector : Tokens = data_struct.fields.iter().map(|ref field| + { + let field_attrs = YaSerdeAttribute::parse(&field.attrs); + if field_attrs.attribute == true { + return None; + } + + let label = field.ident; + if field_attrs.text == true { + return Some(quote!( + let data_event = XmlEvent::characters(&self.#label); + let _ret = writer.write(data_event); + )) + } + + let renamed_label = + match field_attrs.rename { + Some(value) => Some(Ident::new(&format!("{}", value), Span::call_site())), + None => field.ident + }; + let label_name = renamed_label.unwrap().to_string(); + + match get_field_type(field) { + Some(FieldType::FieldTypeString) => + Some(quote!{ + let start_event = XmlEvent::start_element(#label_name); + let data_event = XmlEvent::characters(&self.#label); + let end_event = XmlEvent::end_element(); let _ret = writer.write(start_event); let _ret = writer.write(data_event); let _ret = writer.write(end_event); }), Some(FieldType::FieldTypeStruct{..}) => Some(quote!{ - let start_event = xml::writer::events::XmlEvent::start_element(#label_name); - let end_event = xml::writer::events::XmlEvent::end_element(); - let _ret = writer.write(start_event); - let _ret = writer.write(end_event); + match self.#label.derive_serialize(writer) { + Ok(()) => {}, + Err(msg) => { + return Err(msg); + }, + }; }), Some(FieldType::FieldTypeVec) => Some(quote!{ for item in &self.#label { - let start_event = xml::writer::events::XmlEvent::start_element(#label_name); + let start_event = XmlEvent::start_element(#label_name); let _ret = writer.write(start_event); - let data_event = xml::writer::events::XmlEvent::characters(item); + let data_event = XmlEvent::characters(item); let _ret = writer.write(data_event); - let end_event = xml::writer::events::XmlEvent::end_element(); + let end_event = XmlEvent::end_element(); let _ret = writer.write(end_event); } }), @@ -62,13 +102,13 @@ pub fn serialize(data_struct: &DataStruct, name: &Ident, root: &String) -> Token impl YaSerialize for #name { #[allow(unused_variables)] - fn derive_serialize(&self, writer: &mut xml::EventWriter, parent_attributes: Option<&Vec>) -> Result<(), String> { - let struct_start_event = xml::writer::events::XmlEvent::start_element(#root); + fn derive_serialize(&self, writer: &mut xml::EventWriter) -> Result<(), String> { + let struct_start_event = XmlEvent::start_element(#root)#build_attributes; let _ret = writer.write(struct_start_event); #struct_inspector - let struct_end_event = xml::writer::events::XmlEvent::end_element(); + let struct_end_event = XmlEvent::end_element(); let _ret = writer.write(struct_end_event); Ok(()) }