initial commit
This commit is contained in:
parent
f948bbcd29
commit
d002cabe95
5
Cargo.toml
Normal file
5
Cargo.toml
Normal file
@ -0,0 +1,5 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"yaserde",
|
||||
"yaserde_derive",
|
||||
]
|
||||
12
yaserde/Cargo.toml
Normal file
12
yaserde/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "yaserde"
|
||||
version = "0.1.0"
|
||||
authors = ["Marc-Antoine Arnaud <arnaud.marcantoine@gmail.com>"]
|
||||
|
||||
[dependencies]
|
||||
yaserde_derive = { path = "../yaserde_derive", optional = true }
|
||||
regex = "0.2"
|
||||
xml-rs = "0.7.0"
|
||||
|
||||
[dev-dependencies]
|
||||
yaserde_derive = { path = "../yaserde_derive" }
|
||||
18
yaserde/src/lib.rs
Normal file
18
yaserde/src/lib.rs
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
extern crate xml;
|
||||
#[cfg(feature = "yaserde_derive")]
|
||||
#[allow(unused_imports)]
|
||||
#[macro_use]
|
||||
extern crate yaserde_derive;
|
||||
|
||||
use std::io::Read;
|
||||
use xml::EventReader;
|
||||
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();
|
||||
}
|
||||
163
yaserde/tests/deserializer.rs
Normal file
163
yaserde/tests/deserializer.rs
Normal file
@ -0,0 +1,163 @@
|
||||
|
||||
extern crate yaserde;
|
||||
#[macro_use]
|
||||
extern crate yaserde_derive;
|
||||
extern crate xml;
|
||||
|
||||
use std::io::Read;
|
||||
use xml::reader::EventReader;
|
||||
use yaserde::{YaDeserialize, YaSerialize};
|
||||
|
||||
#[test]
|
||||
fn test_basic() {
|
||||
#[derive(YaDeserialize, YaSerialize, PartialEq, Debug)]
|
||||
#[yaserde(root="base")]
|
||||
pub struct XmlStruct {
|
||||
item: String
|
||||
}
|
||||
|
||||
let content = "<base><item>something</item></base>".to_string();
|
||||
let mut parser = EventReader::from_str(content.as_str());
|
||||
|
||||
let loaded = XmlStruct::derive_deserialize(&mut parser, None);
|
||||
assert_eq!(loaded, Ok(XmlStruct{
|
||||
item: "something".to_string()
|
||||
}));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_list_of_items() {
|
||||
#[derive(YaDeserialize, YaSerialize, PartialEq, Debug)]
|
||||
#[yaserde(root="base")]
|
||||
pub struct XmlStruct {
|
||||
items: Vec<String>
|
||||
}
|
||||
|
||||
let content = "<base><items>something1</items><items>something2</items></base>".to_string();
|
||||
let mut parser = EventReader::from_str(content.as_str());
|
||||
|
||||
let loaded = XmlStruct::derive_deserialize(&mut parser, None);
|
||||
assert_eq!(loaded, Ok(XmlStruct{
|
||||
items: vec![
|
||||
"something1".to_string(),
|
||||
"something2".to_string()
|
||||
]
|
||||
}));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_attributes() {
|
||||
#[derive(YaDeserialize, YaSerialize, PartialEq, Debug)]
|
||||
#[yaserde(root="base")]
|
||||
pub struct XmlStruct {
|
||||
#[yaserde(attribute)]
|
||||
item: String,
|
||||
sub: SubStruct
|
||||
}
|
||||
|
||||
#[derive(YaDeserialize, 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 content = "<base item=\"something\"><sub subitem=\"sub-something\"></sub></base>".to_string();
|
||||
let mut parser = EventReader::from_str(content.as_str());
|
||||
|
||||
let loaded = XmlStruct::derive_deserialize(&mut parser, None);
|
||||
assert_eq!(loaded, Ok(XmlStruct{
|
||||
item: "something".to_string(),
|
||||
sub: SubStruct{
|
||||
subitem: "sub-something".to_string()
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rename() {
|
||||
#[derive(YaDeserialize, YaSerialize, PartialEq, Debug)]
|
||||
#[yaserde(root="base")]
|
||||
pub struct XmlStruct {
|
||||
#[yaserde(attribute, rename="Item")]
|
||||
item: String,
|
||||
#[yaserde(rename="sub")]
|
||||
sub_struct: SubStruct
|
||||
}
|
||||
|
||||
#[derive(YaDeserialize, 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 content = "<base Item=\"something\"><sub sub_item=\"sub_something\"></sub></base>".to_string();
|
||||
let mut parser = EventReader::from_str(content.as_str());
|
||||
|
||||
let loaded = XmlStruct::derive_deserialize(&mut parser, None);
|
||||
assert_eq!(loaded, Ok(XmlStruct{
|
||||
item: "something".to_string(),
|
||||
sub_struct: SubStruct{
|
||||
subitem: "sub_something".to_string()
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_text_content_with_attributes() {
|
||||
#[derive(YaDeserialize, YaSerialize, PartialEq, Debug)]
|
||||
#[yaserde(root="base")]
|
||||
pub struct XmlStruct {
|
||||
#[yaserde(attribute, rename="Item")]
|
||||
item: String,
|
||||
#[yaserde(rename="sub")]
|
||||
sub_struct: SubStruct
|
||||
}
|
||||
|
||||
#[derive(YaDeserialize, 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 content = "<base Item=\"something\"><sub sub_item=\"sub_something\">text_content</sub></base>".to_string();
|
||||
let mut parser = EventReader::from_str(content.as_str());
|
||||
|
||||
let loaded = XmlStruct::derive_deserialize(&mut parser, None);
|
||||
assert_eq!(loaded, Ok(XmlStruct{
|
||||
item: "something".to_string(),
|
||||
sub_struct: SubStruct{
|
||||
subitem: "sub_something".to_string(),
|
||||
text: "text_content".to_string()
|
||||
}
|
||||
}));
|
||||
}
|
||||
13
yaserde_derive/Cargo.toml
Normal file
13
yaserde_derive/Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "yaserde_derive"
|
||||
version = "0.1.0"
|
||||
authors = ["Marc-Antoine Arnaud <arnaud.marcantoine@gmail.com>"]
|
||||
|
||||
[dependencies]
|
||||
syn = { version = "0.12.14", features = ["visit", "extra-traits"] }
|
||||
proc-macro2 = "0.2.3"
|
||||
quote = "0.4.2"
|
||||
|
||||
[lib]
|
||||
name = "yaserde_derive"
|
||||
proc-macro = true
|
||||
83
yaserde_derive/src/der/attribute.rs
Normal file
83
yaserde_derive/src/der/attribute.rs
Normal file
@ -0,0 +1,83 @@
|
||||
|
||||
use proc_macro2::TokenNode::*;
|
||||
use proc_macro2::Delimiter::Parenthesis;
|
||||
use syn::Attribute;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct YaSerdeAttribute {
|
||||
pub root: Option<String>,
|
||||
pub rename: Option<String>,
|
||||
pub attribute: bool,
|
||||
pub text: bool,
|
||||
}
|
||||
|
||||
impl YaSerdeAttribute {
|
||||
pub fn parse(attrs: &Vec<Attribute>) -> YaSerdeAttribute {
|
||||
|
||||
let mut root = None;
|
||||
let mut rename = None;
|
||||
let mut attribute = false;
|
||||
let mut text = false;
|
||||
|
||||
for attr in attrs.iter() {
|
||||
let mut attr_iter = attr.clone().tts.into_iter();
|
||||
match attr_iter.next() {
|
||||
Some(token) => {
|
||||
match token.kind {
|
||||
Group(Parenthesis, token_stream) => {
|
||||
let mut attr_iter = token_stream.into_iter();
|
||||
|
||||
while let Some(item) = attr_iter.next() {
|
||||
match item.kind {
|
||||
Term(t) => {
|
||||
match t.as_str() {
|
||||
"root" => {
|
||||
attr_iter.next();
|
||||
let v = attr_iter.next().map(|s|
|
||||
match s.kind {
|
||||
Literal(l) => {
|
||||
Some(l.to_string().replace("\"", ""))
|
||||
},
|
||||
_ => None
|
||||
});
|
||||
root = v.unwrap_or(None);
|
||||
},
|
||||
"rename" => {
|
||||
attr_iter.next();
|
||||
let v = attr_iter.next().map(|s|
|
||||
match s.kind {
|
||||
Literal(l) => {
|
||||
Some(l.to_string().replace("\"", ""))
|
||||
},
|
||||
_ => None
|
||||
});
|
||||
rename = v.unwrap_or(None);
|
||||
},
|
||||
"attribute" => {
|
||||
attribute = true;
|
||||
}
|
||||
"text" => {
|
||||
text = true;
|
||||
}
|
||||
_ => {},
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
},
|
||||
None => {},
|
||||
}
|
||||
}
|
||||
|
||||
YaSerdeAttribute {
|
||||
root: root,
|
||||
rename: rename,
|
||||
attribute: attribute,
|
||||
text: text,
|
||||
}
|
||||
}
|
||||
}
|
||||
285
yaserde_derive/src/der/expand_struct.rs
Normal file
285
yaserde_derive/src/der/expand_struct.rs
Normal file
@ -0,0 +1,285 @@
|
||||
|
||||
use der::attribute::*;
|
||||
use der::field_type::*;
|
||||
use quote::Tokens;
|
||||
use syn::Ident;
|
||||
use syn::DataStruct;
|
||||
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 {
|
||||
let variables : Tokens = data_struct.fields.iter().map(|ref field|
|
||||
{
|
||||
let label = field.ident;
|
||||
|
||||
match field.ty {
|
||||
Path(ref path) => {
|
||||
match path.path.segments.first() {
|
||||
Some(Pair::End(t)) => {
|
||||
let pair = path.path.segments.first().unwrap();
|
||||
|
||||
match t.ident.to_string().as_str() {
|
||||
"String" => {
|
||||
Some(quote!{
|
||||
let mut #label : #pair = "".to_string();
|
||||
})
|
||||
},
|
||||
"Vec" => {
|
||||
Some(quote!{
|
||||
let mut #label : #pair = vec![];
|
||||
})
|
||||
},
|
||||
_ => {
|
||||
Some(quote!{
|
||||
let mut #label : #pair = #pair::default();
|
||||
})
|
||||
},
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
None
|
||||
},
|
||||
}
|
||||
},
|
||||
_ => {None},
|
||||
}
|
||||
})
|
||||
.filter(|x| x.is_some())
|
||||
.map(|x| x.unwrap())
|
||||
.fold(Tokens::new(), |mut sum, val| {sum.append_all(val); sum});
|
||||
|
||||
let attributes_loading: Tokens = data_struct.fields.iter().map(|ref field|
|
||||
match get_field_type(field) {
|
||||
Some(FieldType::FieldTypeString) => {
|
||||
let label = field.ident;
|
||||
let field_attrs = YaSerdeAttribute::parse(&field.attrs);
|
||||
|
||||
match (field_attrs.attribute, field_attrs.rename) {
|
||||
(true, Some(value)) => {
|
||||
let label_name = Ident::new(&format!("{}", value), Span::call_site()).to_string();
|
||||
Some(quote!{
|
||||
match current_attributes {
|
||||
Some(attributes) =>
|
||||
for attr in attributes {
|
||||
if attr.name.local_name == #label_name {
|
||||
#label = attr.value.to_owned();
|
||||
}
|
||||
},
|
||||
None => {},
|
||||
}
|
||||
})
|
||||
},
|
||||
(true, None) => {
|
||||
let label_name = field.ident.unwrap().to_string();
|
||||
Some(quote!{
|
||||
match current_attributes {
|
||||
Some(attributes) =>
|
||||
for attr in attributes {
|
||||
if attr.name.local_name == #label_name {
|
||||
#label = attr.value.to_owned();
|
||||
}
|
||||
},
|
||||
None => {},
|
||||
}
|
||||
})
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
None
|
||||
}
|
||||
})
|
||||
.filter(|x| x.is_some())
|
||||
.map(|x| x.unwrap())
|
||||
.fold(Tokens::new(), |mut sum, val| {sum.append_all(val); sum});
|
||||
|
||||
let assign_text_field: Tokens = data_struct.fields.iter().map(|ref field|
|
||||
match get_field_type(field) {
|
||||
Some(FieldType::FieldTypeString) => {
|
||||
let label = field.ident;
|
||||
let field_attrs = YaSerdeAttribute::parse(&field.attrs);
|
||||
|
||||
match field_attrs.text {
|
||||
true => {
|
||||
Some(quote!{
|
||||
#label = characters_content.to_owned();
|
||||
})
|
||||
},
|
||||
false => None
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
None
|
||||
}
|
||||
})
|
||||
.filter(|x| x.is_some())
|
||||
.map(|x| x.unwrap())
|
||||
.fold(Tokens::new(), |mut sum, val| {sum.append_all(val); sum});
|
||||
|
||||
let fields : Tokens = data_struct.fields.iter().map(|ref field|
|
||||
{
|
||||
let field_attrs = YaSerdeAttribute::parse(&field.attrs);
|
||||
let label = field.ident;
|
||||
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!{
|
||||
#label_name => {
|
||||
match read.next() {
|
||||
Ok(xml::reader::XmlEvent::Characters(characters_content)) => {
|
||||
#label = characters_content.trim().to_string();
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
},
|
||||
})
|
||||
},
|
||||
Some(FieldType::FieldTypeStruct{name}) => {
|
||||
let struct_ident = Ident::new(&format!("{}", name), Span::def_site());
|
||||
|
||||
Some(quote!{
|
||||
#label_name => {
|
||||
match #struct_ident::derive_deserialize(read, Some(&attributes)) {
|
||||
Ok(parsed_structure) => {
|
||||
prev_level -= 1;
|
||||
#label = parsed_structure;
|
||||
},
|
||||
Err(msg) => {
|
||||
println!("ERROR {:?}", msg);
|
||||
},
|
||||
}
|
||||
},
|
||||
})
|
||||
},
|
||||
Some(FieldType::FieldTypeVec) => {
|
||||
match get_vec_type(field) {
|
||||
Some(identifier) => {
|
||||
match identifier.to_string().as_str() {
|
||||
"String" => {
|
||||
Some(quote!{
|
||||
#label_name => {
|
||||
match read.next() {
|
||||
Ok(xml::reader::XmlEvent::Characters(characters_content)) => {
|
||||
#label.push(characters_content.trim().to_string());
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
},
|
||||
})
|
||||
},
|
||||
struct_name => {
|
||||
let struct_ident = Ident::new(&format!("{}", struct_name), Span::def_site());
|
||||
Some(quote!{
|
||||
#label_name => {
|
||||
match #struct_ident::derive_deserialize(read, Some(&attributes)) {
|
||||
Ok(parsed_item) => {
|
||||
prev_level -= 1;
|
||||
#label.push(parsed_item);
|
||||
},
|
||||
Err(msg) => {
|
||||
println!("ERROR {:?}", msg);
|
||||
},
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
None => None
|
||||
}
|
||||
},
|
||||
_ => None
|
||||
}
|
||||
})
|
||||
.filter(|x| x.is_some())
|
||||
.map(|x| x.unwrap())
|
||||
.fold(Tokens::new(), |mut sum, val| {sum.append_all(val); sum});
|
||||
|
||||
let struct_builder : Tokens = data_struct.fields.iter().map(|ref field|
|
||||
{
|
||||
let label = field.ident;
|
||||
|
||||
match get_field_type(field) {
|
||||
Some(FieldType::FieldTypeString) |
|
||||
Some(FieldType::FieldTypeStruct{..}) |
|
||||
Some(FieldType::FieldTypeVec) =>
|
||||
Some(quote!{
|
||||
#label: #label,
|
||||
}),
|
||||
None => None,
|
||||
}
|
||||
})
|
||||
.filter(|x| x.is_some())
|
||||
.map(|x| x.unwrap())
|
||||
.fold(Tokens::new(), |mut tokens, token| {tokens.append_all(token); tokens});
|
||||
|
||||
quote! {
|
||||
use xml::reader::XmlEvent;
|
||||
|
||||
impl YaDeserialize for #name {
|
||||
#[allow(unused_variables)]
|
||||
fn derive_deserialize<R: Read>(read: &mut xml::EventReader<R>, parent_attributes: Option<&Vec<xml::attribute::OwnedAttribute>>) -> Result<Self, String> {
|
||||
let mut prev_level = 0;
|
||||
let mut current_level = 0;
|
||||
|
||||
#variables
|
||||
let current_attributes = parent_attributes;
|
||||
#attributes_loading
|
||||
|
||||
loop {
|
||||
match read.next() {
|
||||
Ok(XmlEvent::StartDocument{..}) => {
|
||||
},
|
||||
Ok(XmlEvent::EndDocument) => {
|
||||
break;
|
||||
},
|
||||
Ok(XmlEvent::StartElement{name, attributes, namespace: _namespace}) => {
|
||||
// println!("{} | {} - {}: {}", #root, prev_level, current_level, name.local_name.as_str());
|
||||
if prev_level == current_level {
|
||||
match name.local_name.as_str() {
|
||||
#root => {
|
||||
let root_attributes = attributes.clone();
|
||||
let current_attributes = Some(&root_attributes);
|
||||
#attributes_loading
|
||||
|
||||
current_level += 1;
|
||||
},
|
||||
#fields
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
|
||||
prev_level += 1;
|
||||
},
|
||||
Ok(XmlEvent::EndElement{name}) => {
|
||||
if #root == name.local_name.as_str() {
|
||||
// println!("BREAK {}", #root);
|
||||
break;
|
||||
}
|
||||
prev_level -= 1;
|
||||
}
|
||||
Ok(xml::reader::XmlEvent::Characters(characters_content)) => {
|
||||
if prev_level == current_level {
|
||||
#assign_text_field
|
||||
}
|
||||
},
|
||||
Ok(_event) => {
|
||||
},
|
||||
Err(_msg) => {
|
||||
break;
|
||||
},
|
||||
}
|
||||
}
|
||||
Ok(#name{#struct_builder})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
70
yaserde_derive/src/der/field_type.rs
Normal file
70
yaserde_derive/src/der/field_type.rs
Normal file
@ -0,0 +1,70 @@
|
||||
|
||||
use syn;
|
||||
use syn::punctuated::Pair;
|
||||
use syn::Type::Path;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum FieldType {
|
||||
FieldTypeString,
|
||||
FieldTypeVec,
|
||||
FieldTypeStruct{name: String},
|
||||
}
|
||||
|
||||
pub fn get_field_type(field: &syn::Field) -> Option<FieldType> {
|
||||
match field.ty {
|
||||
Path(ref path) => {
|
||||
match path.path.segments.first() {
|
||||
Some(Pair::End(t)) => {
|
||||
match t.ident.to_string().as_str() {
|
||||
"String" => Some(FieldType::FieldTypeString),
|
||||
"Vec" => Some(FieldType::FieldTypeVec),
|
||||
name => Some(FieldType::FieldTypeStruct{name: name.to_string()}),
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
None
|
||||
},
|
||||
}
|
||||
},
|
||||
_ => {None},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_vec_type(field: &syn::Field) -> Option<syn::Ident> {
|
||||
match field.ty {
|
||||
Path(ref path) => {
|
||||
match path.path.segments.first() {
|
||||
Some(Pair::End(t)) => {
|
||||
match t.arguments {
|
||||
syn::PathArguments::AngleBracketed(ref args) => {
|
||||
match args.args.first() {
|
||||
Some(Pair::End(tt)) => {
|
||||
match tt {
|
||||
&syn::GenericArgument::Type(ref argument) => {
|
||||
match argument {
|
||||
&Path(ref path2) => {
|
||||
match path2.path.segments.first() {
|
||||
Some(Pair::End(ttt)) => {
|
||||
Some(ttt.ident)
|
||||
},
|
||||
_ => None
|
||||
}
|
||||
},
|
||||
_ => None
|
||||
}
|
||||
},
|
||||
_ => None
|
||||
}
|
||||
},
|
||||
_ => None
|
||||
}
|
||||
},
|
||||
_ => None
|
||||
}
|
||||
},
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
43
yaserde_derive/src/der/mod.rs
Normal file
43
yaserde_derive/src/der/mod.rs
Normal file
@ -0,0 +1,43 @@
|
||||
|
||||
pub mod attribute;
|
||||
pub mod expand_struct;
|
||||
pub mod field_type;
|
||||
|
||||
use proc_macro2::Span;
|
||||
use quote;
|
||||
use syn;
|
||||
use syn::Ident;
|
||||
|
||||
pub fn expand_derive_deserialize(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::parse(data_struct, &name, &root, &root_attrs)
|
||||
},
|
||||
&syn::Data::Enum(ref _data_enum) => {
|
||||
unimplemented!()
|
||||
},
|
||||
&syn::Data::Union(ref _data_union) => {
|
||||
unimplemented!()
|
||||
},
|
||||
};
|
||||
|
||||
let dummy_const = Ident::new(&format!("_IMPL_DESERIALIZE_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)
|
||||
}
|
||||
38
yaserde_derive/src/lib.rs
Normal file
38
yaserde_derive/src/lib.rs
Normal file
@ -0,0 +1,38 @@
|
||||
#![recursion_limit="128"]
|
||||
|
||||
extern crate proc_macro;
|
||||
extern crate proc_macro2;
|
||||
#[macro_use]
|
||||
extern crate quote;
|
||||
extern crate syn;
|
||||
|
||||
mod der;
|
||||
|
||||
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) {
|
||||
Ok(expanded) => expanded.into(),
|
||||
Err(msg) => panic!(msg),
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro_derive(YaSerialize)]
|
||||
pub fn derive_serialize(input: TokenStream) -> TokenStream {
|
||||
let ast = syn::parse(input).unwrap();
|
||||
let gen = expand_derive_serialize(&ast);
|
||||
gen.into()
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user