From c22df74dd348311e23ac77ae8c82d97fe6f0f3c8 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Arnaud Date: Tue, 10 Apr 2018 10:14:58 +0200 Subject: [PATCH] start to add serialiser --- yaserde/src/lib.rs | 8 +- yaserde/tests/deserializer.rs | 28 +++---- yaserde/tests/serializer.rs | 65 ++++++++++++++++ yaserde_derive/src/{der => de}/attribute.rs | 0 .../src/{der => de}/expand_struct.rs | 6 +- yaserde_derive/src/{der => de}/field_type.rs | 0 yaserde_derive/src/{der => de}/mod.rs | 4 +- yaserde_derive/src/lib.rs | 24 ++---- yaserde_derive/src/ser/expand_struct.rs | 77 +++++++++++++++++++ yaserde_derive/src/ser/mod.rs | 45 +++++++++++ 10 files changed, 218 insertions(+), 39 deletions(-) create mode 100644 yaserde/tests/serializer.rs rename yaserde_derive/src/{der => de}/attribute.rs (100%) rename yaserde_derive/src/{der => de}/expand_struct.rs (98%) rename yaserde_derive/src/{der => de}/field_type.rs (100%) rename yaserde_derive/src/{der => de}/mod.rs (84%) create mode 100644 yaserde_derive/src/ser/expand_struct.rs create mode 100644 yaserde_derive/src/ser/mod.rs diff --git a/yaserde/src/lib.rs b/yaserde/src/lib.rs index 45ec9bb..77db2a5 100644 --- a/yaserde/src/lib.rs +++ b/yaserde/src/lib.rs @@ -5,14 +5,14 @@ extern crate xml; #[macro_use] extern crate yaserde_derive; -use std::io::Read; -use xml::EventReader; +use std::io::{Read, Write}; +use xml::{EventReader, EventWriter}; use xml::attribute::OwnedAttribute; pub trait YaDeserialize : Sized { fn derive_deserialize(read: &mut EventReader, parent_attributes: Option<&Vec>) -> Result; } -pub trait YaSerialize { - fn derive_serialize(); +pub trait YaSerialize : Sized { + fn derive_serialize(&self, read: &mut EventWriter, parent_attributes: Option<&Vec>) -> Result<(), String>; } diff --git a/yaserde/tests/deserializer.rs b/yaserde/tests/deserializer.rs index d75ac67..d22768e 100644 --- a/yaserde/tests/deserializer.rs +++ b/yaserde/tests/deserializer.rs @@ -6,11 +6,11 @@ extern crate xml; use std::io::Read; use xml::reader::EventReader; -use yaserde::{YaDeserialize, YaSerialize}; +use yaserde::{YaDeserialize}; #[test] -fn test_basic() { - #[derive(YaDeserialize, YaSerialize, PartialEq, Debug)] +fn de_basic() { + #[derive(YaDeserialize, PartialEq, Debug)] #[yaserde(root="base")] pub struct XmlStruct { item: String @@ -26,8 +26,8 @@ fn test_basic() { } #[test] -fn test_list_of_items() { - #[derive(YaDeserialize, YaSerialize, PartialEq, Debug)] +fn de_list_of_items() { + #[derive(YaDeserialize, PartialEq, Debug)] #[yaserde(root="base")] pub struct XmlStruct { items: Vec @@ -46,8 +46,8 @@ fn test_list_of_items() { } #[test] -fn test_attributes() { - #[derive(YaDeserialize, YaSerialize, PartialEq, Debug)] +fn de_attributes() { + #[derive(YaDeserialize, PartialEq, Debug)] #[yaserde(root="base")] pub struct XmlStruct { #[yaserde(attribute)] @@ -55,7 +55,7 @@ fn test_attributes() { sub: SubStruct } - #[derive(YaDeserialize, YaSerialize, PartialEq, Debug)] + #[derive(YaDeserialize, PartialEq, Debug)] #[yaserde(root="sub")] pub struct SubStruct { #[yaserde(attribute)] @@ -83,8 +83,8 @@ fn test_attributes() { } #[test] -fn test_rename() { - #[derive(YaDeserialize, YaSerialize, PartialEq, Debug)] +fn de_rename() { + #[derive(YaDeserialize, PartialEq, Debug)] #[yaserde(root="base")] pub struct XmlStruct { #[yaserde(attribute, rename="Item")] @@ -93,7 +93,7 @@ fn test_rename() { sub_struct: SubStruct } - #[derive(YaDeserialize, YaSerialize, PartialEq, Debug)] + #[derive(YaDeserialize, PartialEq, Debug)] #[yaserde(root="sub")] pub struct SubStruct { #[yaserde(attribute, rename="sub_item")] @@ -121,8 +121,8 @@ fn test_rename() { } #[test] -fn test_text_content_with_attributes() { - #[derive(YaDeserialize, YaSerialize, PartialEq, Debug)] +fn de_text_content_with_attributes() { + #[derive(YaDeserialize, PartialEq, Debug)] #[yaserde(root="base")] pub struct XmlStruct { #[yaserde(attribute, rename="Item")] @@ -131,7 +131,7 @@ fn test_text_content_with_attributes() { sub_struct: SubStruct } - #[derive(YaDeserialize, YaSerialize, PartialEq, Debug)] + #[derive(YaDeserialize, PartialEq, Debug)] #[yaserde(root="sub")] pub struct SubStruct { #[yaserde(attribute, rename="sub_item")] diff --git a/yaserde/tests/serializer.rs b/yaserde/tests/serializer.rs new file mode 100644 index 0000000..923f7a6 --- /dev/null +++ b/yaserde/tests/serializer.rs @@ -0,0 +1,65 @@ + +extern crate yaserde; +#[macro_use] +extern crate yaserde_derive; +extern crate xml; + +use std::str; +use std::io::Cursor; +use std::io::Write; +use xml::writer::EventWriter; +use yaserde::{YaSerialize}; + +#[test] +fn ser_basic() { + #[derive(YaSerialize, PartialEq, Debug)] + #[yaserde(root="base")] + pub struct XmlStruct { + item: String + } + + let model = XmlStruct { + item: "something".to_string() + }; + + let content = "something".to_string(); + + let mut buf = Cursor::new(Vec::new()); + let mut writer = EventWriter::new(&mut buf); + let _status = model.derive_serialize(&mut writer, None); + + 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] +fn ser_list_of_items() { + #[derive(YaSerialize, PartialEq, Debug)] + #[yaserde(root="base")] + pub struct XmlStruct { + items: Vec + } + + let model = XmlStruct{ + items: vec![ + "something1".to_string(), + "something2".to_string() + ] + }; + + let content = "something1something2".to_string(); + + let mut buf = Cursor::new(Vec::new()); + let mut writer = EventWriter::new(&mut buf); + let _status = model.derive_serialize(&mut writer, None); + + 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); + +} \ No newline at end of file diff --git a/yaserde_derive/src/der/attribute.rs b/yaserde_derive/src/de/attribute.rs similarity index 100% rename from yaserde_derive/src/der/attribute.rs rename to yaserde_derive/src/de/attribute.rs diff --git a/yaserde_derive/src/der/expand_struct.rs b/yaserde_derive/src/de/expand_struct.rs similarity index 98% rename from yaserde_derive/src/der/expand_struct.rs rename to yaserde_derive/src/de/expand_struct.rs index 8de9ae5..6bca28e 100644 --- a/yaserde_derive/src/der/expand_struct.rs +++ b/yaserde_derive/src/de/expand_struct.rs @@ -1,6 +1,6 @@ -use der::attribute::*; -use der::field_type::*; +use de::attribute::*; +use de::field_type::*; use quote::Tokens; use syn::Ident; use syn::DataStruct; @@ -8,7 +8,7 @@ use syn::punctuated::Pair; use syn::Type::Path; use proc_macro2::Span; -pub fn parse(data_struct: &DataStruct, name: &Ident, root: &String, _root_attributes: &YaSerdeAttribute) -> Tokens { +pub fn parse(data_struct: &DataStruct, name: &Ident, root: &String) -> Tokens { let variables : Tokens = data_struct.fields.iter().map(|ref field| { let label = field.ident; diff --git a/yaserde_derive/src/der/field_type.rs b/yaserde_derive/src/de/field_type.rs similarity index 100% rename from yaserde_derive/src/der/field_type.rs rename to yaserde_derive/src/de/field_type.rs diff --git a/yaserde_derive/src/der/mod.rs b/yaserde_derive/src/de/mod.rs similarity index 84% rename from yaserde_derive/src/der/mod.rs rename to yaserde_derive/src/de/mod.rs index ff0d6a1..5392c83 100644 --- a/yaserde_derive/src/der/mod.rs +++ b/yaserde_derive/src/de/mod.rs @@ -19,7 +19,7 @@ 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) }, &syn::Data::Enum(ref _data_enum) => { unimplemented!() @@ -29,7 +29,7 @@ pub fn expand_derive_deserialize(ast: &syn::DeriveInput) -> Result quote::Tokens { - let name = &ast.ident; - quote! { - impl YaSerialize for #name { - fn derive_serialize() { - println!("serialize {}", stringify!(#name)); - } - } - } -} - #[proc_macro_derive(YaDeserialize, attributes(yaserde))] pub fn derive_deserialize(input: TokenStream) -> TokenStream { let ast = syn::parse(input).unwrap(); - match der::expand_derive_deserialize(&ast) { + match de::expand_derive_deserialize(&ast) { Ok(expanded) => expanded.into(), Err(msg) => panic!(msg), } } -#[proc_macro_derive(YaSerialize)] +#[proc_macro_derive(YaSerialize, attributes(yaserde))] pub fn derive_serialize(input: TokenStream) -> TokenStream { let ast = syn::parse(input).unwrap(); - let gen = expand_derive_serialize(&ast); - gen.into() + match ser::expand_derive_serialize(&ast) { + Ok(expanded) => expanded.into(), + Err(msg) => panic!(msg), + } } diff --git a/yaserde_derive/src/ser/expand_struct.rs b/yaserde_derive/src/ser/expand_struct.rs new file mode 100644 index 0000000..709d3dd --- /dev/null +++ b/yaserde_derive/src/ser/expand_struct.rs @@ -0,0 +1,77 @@ + +use de::attribute::*; +use de::field_type::*; +use quote::Tokens; +use syn::Ident; +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 field_attrs = YaSerdeAttribute::parse(&field.attrs); + let renamed_label = + match field_attrs.rename { + Some(value) => Some(Ident::new(&format!("{}", value), Span::call_site())), + None => field.ident + }; + let label = field.ident; + let label_name = renamed_label.unwrap().to_string(); + + 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(); + 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); + }), + Some(FieldType::FieldTypeVec) => + Some(quote!{ + for item in &self.#label { + let start_event = xml::writer::events::XmlEvent::start_element(#label_name); + let _ret = writer.write(start_event); + + let data_event = xml::writer::events::XmlEvent::characters(item); + let _ret = writer.write(data_event); + + let end_event = xml::writer::events::XmlEvent::end_element(); + let _ret = writer.write(end_event); + } + }), + None => None, + } + }) + .filter(|x| x.is_some()) + .map(|x| x.unwrap()) + .fold(Tokens::new(), |mut tokens, token| {tokens.append_all(token); tokens}); + + println!("{:?}", struct_inspector); + + quote! { + use xml::writer::XmlEvent; + + 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); + let _ret = writer.write(struct_start_event); + + #struct_inspector + + let struct_end_event = xml::writer::events::XmlEvent::end_element(); + let _ret = writer.write(struct_end_event); + Ok(()) + } + } + } +} diff --git a/yaserde_derive/src/ser/mod.rs b/yaserde_derive/src/ser/mod.rs new file mode 100644 index 0000000..ffc75ca --- /dev/null +++ b/yaserde_derive/src/ser/mod.rs @@ -0,0 +1,45 @@ + +// pub mod attribute; +pub mod expand_struct; +// pub mod field_type; + +use de::attribute; + +use proc_macro2::Span; +use quote; +use syn; +use syn::Ident; + +pub fn expand_derive_serialize(ast: &syn::DeriveInput) -> Result { + let name = &ast.ident; + let attrs = &ast.attrs; + let data = &ast.data; + + let root_attrs = attribute::YaSerdeAttribute::parse(&attrs); + let root = root_attrs.clone().root.unwrap_or(name.to_string()); + + let impl_block = + match data { + &syn::Data::Struct(ref data_struct) => { + expand_struct::serialize(data_struct, &name, &root) + }, + &syn::Data::Enum(ref _data_enum) => { + unimplemented!() + }, + &syn::Data::Union(ref _data_union) => { + unimplemented!() + }, + }; + + let dummy_const = Ident::new(&format!("_IMPL_YA_SERIALIZE_FOR_{}", name), Span::def_site()); + + let generated = quote! { + #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] + const #dummy_const: () = { + extern crate yaserde as _yaserde; + #impl_block + }; + }; + + Ok(generated) +}