start to add serialiser
This commit is contained in:
parent
f5a0a53d27
commit
c22df74dd3
@ -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>;
|
||||
}
|
||||
|
||||
@ -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")]
|
||||
|
||||
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 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;
|
||||
@ -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)]
|
||||
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
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