start to add serialiser
This commit is contained in:
		
							parent
							
								
									f5a0a53d27
								
							
						
					
					
						commit
						c22df74dd3
					
				| @ -5,14 +5,14 @@ extern crate xml; | |||||||
| #[macro_use] | #[macro_use] | ||||||
| extern crate yaserde_derive; | extern crate yaserde_derive; | ||||||
| 
 | 
 | ||||||
| use std::io::Read; | use std::io::{Read, Write}; | ||||||
| use xml::EventReader; | use xml::{EventReader, EventWriter}; | ||||||
| use xml::attribute::OwnedAttribute; | use xml::attribute::OwnedAttribute; | ||||||
| 
 | 
 | ||||||
| pub trait YaDeserialize : Sized { | pub trait YaDeserialize : Sized { | ||||||
|   fn derive_deserialize<R: Read>(read: &mut EventReader<R>, parent_attributes: Option<&Vec<OwnedAttribute>>) -> Result<Self, String>; |   fn derive_deserialize<R: Read>(read: &mut EventReader<R>, parent_attributes: Option<&Vec<OwnedAttribute>>) -> Result<Self, String>; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub trait YaSerialize { | pub trait YaSerialize : Sized { | ||||||
|   fn derive_serialize(); |   fn derive_serialize<W: Write>(&self, read: &mut EventWriter<W>, parent_attributes: Option<&Vec<OwnedAttribute>>) -> Result<(), String>; | ||||||
| } | } | ||||||
|  | |||||||
| @ -6,11 +6,11 @@ extern crate xml; | |||||||
| 
 | 
 | ||||||
| use std::io::Read; | use std::io::Read; | ||||||
| use xml::reader::EventReader; | use xml::reader::EventReader; | ||||||
| use yaserde::{YaDeserialize, YaSerialize}; | use yaserde::{YaDeserialize}; | ||||||
| 
 | 
 | ||||||
| #[test] | #[test] | ||||||
| fn test_basic() { | fn de_basic() { | ||||||
|   #[derive(YaDeserialize, YaSerialize, PartialEq, Debug)] |   #[derive(YaDeserialize, PartialEq, Debug)] | ||||||
|   #[yaserde(root="base")] |   #[yaserde(root="base")] | ||||||
|   pub struct XmlStruct { |   pub struct XmlStruct { | ||||||
|     item: String |     item: String | ||||||
| @ -26,8 +26,8 @@ fn test_basic() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[test] | #[test] | ||||||
| fn test_list_of_items() { | fn de_list_of_items() { | ||||||
|   #[derive(YaDeserialize, YaSerialize, PartialEq, Debug)] |   #[derive(YaDeserialize, PartialEq, Debug)] | ||||||
|   #[yaserde(root="base")] |   #[yaserde(root="base")] | ||||||
|   pub struct XmlStruct { |   pub struct XmlStruct { | ||||||
|     items: Vec<String> |     items: Vec<String> | ||||||
| @ -46,8 +46,8 @@ fn test_list_of_items() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[test] | #[test] | ||||||
| fn test_attributes() { | fn de_attributes() { | ||||||
|   #[derive(YaDeserialize, YaSerialize, PartialEq, Debug)] |   #[derive(YaDeserialize, PartialEq, Debug)] | ||||||
|   #[yaserde(root="base")] |   #[yaserde(root="base")] | ||||||
|   pub struct XmlStruct { |   pub struct XmlStruct { | ||||||
|     #[yaserde(attribute)] |     #[yaserde(attribute)] | ||||||
| @ -55,7 +55,7 @@ fn test_attributes() { | |||||||
|     sub: SubStruct |     sub: SubStruct | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   #[derive(YaDeserialize, YaSerialize, PartialEq, Debug)] |   #[derive(YaDeserialize, PartialEq, Debug)] | ||||||
|   #[yaserde(root="sub")] |   #[yaserde(root="sub")] | ||||||
|   pub struct SubStruct { |   pub struct SubStruct { | ||||||
|     #[yaserde(attribute)] |     #[yaserde(attribute)] | ||||||
| @ -83,8 +83,8 @@ fn test_attributes() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[test] | #[test] | ||||||
| fn test_rename() { | fn de_rename() { | ||||||
|   #[derive(YaDeserialize, YaSerialize, PartialEq, Debug)] |   #[derive(YaDeserialize, PartialEq, Debug)] | ||||||
|   #[yaserde(root="base")] |   #[yaserde(root="base")] | ||||||
|   pub struct XmlStruct { |   pub struct XmlStruct { | ||||||
|     #[yaserde(attribute, rename="Item")] |     #[yaserde(attribute, rename="Item")] | ||||||
| @ -93,7 +93,7 @@ fn test_rename() { | |||||||
|     sub_struct: SubStruct |     sub_struct: SubStruct | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   #[derive(YaDeserialize, YaSerialize, PartialEq, Debug)] |   #[derive(YaDeserialize, PartialEq, Debug)] | ||||||
|   #[yaserde(root="sub")] |   #[yaserde(root="sub")] | ||||||
|   pub struct SubStruct { |   pub struct SubStruct { | ||||||
|     #[yaserde(attribute, rename="sub_item")] |     #[yaserde(attribute, rename="sub_item")] | ||||||
| @ -121,8 +121,8 @@ fn test_rename() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[test] | #[test] | ||||||
| fn test_text_content_with_attributes() { | fn de_text_content_with_attributes() { | ||||||
|   #[derive(YaDeserialize, YaSerialize, PartialEq, Debug)] |   #[derive(YaDeserialize, PartialEq, Debug)] | ||||||
|   #[yaserde(root="base")] |   #[yaserde(root="base")] | ||||||
|   pub struct XmlStruct { |   pub struct XmlStruct { | ||||||
|     #[yaserde(attribute, rename="Item")] |     #[yaserde(attribute, rename="Item")] | ||||||
| @ -131,7 +131,7 @@ fn test_text_content_with_attributes() { | |||||||
|     sub_struct: SubStruct |     sub_struct: SubStruct | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   #[derive(YaDeserialize, YaSerialize, PartialEq, Debug)] |   #[derive(YaDeserialize, PartialEq, Debug)] | ||||||
|   #[yaserde(root="sub")] |   #[yaserde(root="sub")] | ||||||
|   pub struct SubStruct { |   pub struct SubStruct { | ||||||
|     #[yaserde(attribute, rename="sub_item")] |     #[yaserde(attribute, rename="sub_item")] | ||||||
|  | |||||||
							
								
								
									
										65
									
								
								yaserde/tests/serializer.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								yaserde/tests/serializer.rs
									
									
									
									
									
										Normal file
									
								
							| @ -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 = "<?xml version=\"1.0\" encoding=\"utf-8\"?><base><item>something</item></base>".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<String> | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   let model = XmlStruct{ | ||||||
|  |     items: vec![ | ||||||
|  |       "something1".to_string(), | ||||||
|  |       "something2".to_string() | ||||||
|  |     ] | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   let content = "<?xml version=\"1.0\" encoding=\"utf-8\"?><base><items>something1</items><items>something2</items></base>".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); | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -1,6 +1,6 @@ | |||||||
| 
 | 
 | ||||||
| use der::attribute::*; | use de::attribute::*; | ||||||
| use der::field_type::*; | use de::field_type::*; | ||||||
| use quote::Tokens; | use quote::Tokens; | ||||||
| use syn::Ident; | use syn::Ident; | ||||||
| use syn::DataStruct; | use syn::DataStruct; | ||||||
| @ -8,7 +8,7 @@ use syn::punctuated::Pair; | |||||||
| use syn::Type::Path; | use syn::Type::Path; | ||||||
| use proc_macro2::Span; | 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 variables : Tokens = data_struct.fields.iter().map(|ref field| | ||||||
|     { |     { | ||||||
|       let label = field.ident; |       let label = field.ident; | ||||||
| @ -19,7 +19,7 @@ pub fn expand_derive_deserialize(ast: &syn::DeriveInput) -> Result<quote::Tokens | |||||||
|   let impl_block = |   let impl_block = | ||||||
|     match data { |     match data { | ||||||
|       &syn::Data::Struct(ref data_struct) => { |       &syn::Data::Struct(ref data_struct) => { | ||||||
|         expand_struct::parse(data_struct, &name, &root, &root_attrs) |         expand_struct::parse(data_struct, &name, &root) | ||||||
|       }, |       }, | ||||||
|       &syn::Data::Enum(ref _data_enum) => { |       &syn::Data::Enum(ref _data_enum) => { | ||||||
|         unimplemented!() |         unimplemented!() | ||||||
| @ -29,7 +29,7 @@ pub fn expand_derive_deserialize(ast: &syn::DeriveInput) -> Result<quote::Tokens | |||||||
|       }, |       }, | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|   let dummy_const = Ident::new(&format!("_IMPL_DESERIALIZE_FOR_{}", name), Span::def_site()); |   let dummy_const = Ident::new(&format!("_IMPL_YA_DESERIALIZE_FOR_{}", name), Span::def_site()); | ||||||
| 
 | 
 | ||||||
|   let generated = quote! { |   let generated = quote! { | ||||||
|     #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] |     #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] | ||||||
| @ -6,33 +6,25 @@ extern crate proc_macro2; | |||||||
| extern crate quote; | extern crate quote; | ||||||
| extern crate syn; | extern crate syn; | ||||||
| 
 | 
 | ||||||
| mod der; | mod de; | ||||||
|  | mod ser; | ||||||
| 
 | 
 | ||||||
| use proc_macro::TokenStream; | use proc_macro::TokenStream; | ||||||
| 
 | 
 | ||||||
| fn expand_derive_serialize(ast: &syn::DeriveInput) -> quote::Tokens { |  | ||||||
|   let name = &ast.ident; |  | ||||||
|   quote! { |  | ||||||
|     impl YaSerialize for #name { |  | ||||||
|       fn derive_serialize() { |  | ||||||
|         println!("serialize {}", stringify!(#name)); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[proc_macro_derive(YaDeserialize, attributes(yaserde))] | #[proc_macro_derive(YaDeserialize, attributes(yaserde))] | ||||||
| pub fn derive_deserialize(input: TokenStream) -> TokenStream { | pub fn derive_deserialize(input: TokenStream) -> TokenStream { | ||||||
|   let ast = syn::parse(input).unwrap(); |   let ast = syn::parse(input).unwrap(); | ||||||
|   match der::expand_derive_deserialize(&ast) { |   match de::expand_derive_deserialize(&ast) { | ||||||
|     Ok(expanded) => expanded.into(), |     Ok(expanded) => expanded.into(), | ||||||
|     Err(msg) => panic!(msg), |     Err(msg) => panic!(msg), | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[proc_macro_derive(YaSerialize)] | #[proc_macro_derive(YaSerialize, attributes(yaserde))] | ||||||
| pub fn derive_serialize(input: TokenStream) -> TokenStream { | pub fn derive_serialize(input: TokenStream) -> TokenStream { | ||||||
|   let ast = syn::parse(input).unwrap(); |   let ast = syn::parse(input).unwrap(); | ||||||
|   let gen = expand_derive_serialize(&ast); |   match ser::expand_derive_serialize(&ast) { | ||||||
|   gen.into() |     Ok(expanded) => expanded.into(), | ||||||
|  |     Err(msg) => panic!(msg), | ||||||
|  |   } | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										77
									
								
								yaserde_derive/src/ser/expand_struct.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								yaserde_derive/src/ser/expand_struct.rs
									
									
									
									
									
										Normal file
									
								
							| @ -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<W: Write>(&self, writer: &mut xml::EventWriter<W>, parent_attributes: Option<&Vec<xml::attribute::OwnedAttribute>>) -> 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(()) | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										45
									
								
								yaserde_derive/src/ser/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								yaserde_derive/src/ser/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @ -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<quote::Tokens, String> { | ||||||
|  |   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) | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user