start to add serialiser

This commit is contained in:
Marc-Antoine Arnaud 2018-04-10 10:14:58 +02:00
parent f5a0a53d27
commit c22df74dd3
10 changed files with 218 additions and 39 deletions

View File

@ -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<R: Read>(read: &mut EventReader<R>, parent_attributes: Option<&Vec<OwnedAttribute>>) -> Result<Self, String>;
}
pub trait YaSerialize {
fn derive_serialize();
pub trait YaSerialize : Sized {
fn derive_serialize<W: Write>(&self, read: &mut EventWriter<W>, parent_attributes: Option<&Vec<OwnedAttribute>>) -> Result<(), String>;
}

View File

@ -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<String>
@ -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")]

View 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);
}

View File

@ -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;

View File

@ -19,7 +19,7 @@ pub fn expand_derive_deserialize(ast: &syn::DeriveInput) -> Result<quote::Tokens
let impl_block =
match data {
&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) => {
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! {
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]

View File

@ -6,33 +6,25 @@ extern crate proc_macro2;
extern crate quote;
extern crate syn;
mod der;
mod de;
mod ser;
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))]
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),
}
}

View 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(())
}
}
}
}

View 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)
}