support type de/ser-rialization

This commit is contained in:
Marc-Antoine Arnaud 2018-05-23 16:59:31 +02:00
parent 7a6ae6e6fe
commit a88f6535f4
7 changed files with 551 additions and 139 deletions

View File

@ -25,6 +25,51 @@ pub trait Visitor<'de>: Sized {
/// The value produced by this visitor. /// The value produced by this visitor.
type Value; type Value;
fn visit_bool(self, v: &str) -> Result<Self::Value, String>
{
Err(format!("Unexpected bool {}", v))
}
fn visit_i8(self, v: &str) -> Result<Self::Value, String>
{
Err(format!("Unexpected i8 {}", v))
}
fn visit_u8(self, v: &str) -> Result<Self::Value, String>
{
Err(format!("Unexpected u8 {}", v))
}
fn visit_i16(self, v: &str) -> Result<Self::Value, String>
{
Err(format!("Unexpected i16 {}", v))
}
fn visit_u16(self, v: &str) -> Result<Self::Value, String>
{
Err(format!("Unexpected u16 {}", v))
}
fn visit_i32(self, v: &str) -> Result<Self::Value, String>
{
Err(format!("Unexpected i32 {}", v))
}
fn visit_u32(self, v: &str) -> Result<Self::Value, String>
{
Err(format!("Unexpected u32 {}", v))
}
fn visit_i64(self, v: &str) -> Result<Self::Value, String>
{
Err(format!("Unexpected i64 {}", v))
}
fn visit_u64(self, v: &str) -> Result<Self::Value, String>
{
Err(format!("Unexpected u64 {}", v))
}
fn visit_str(self, v: &str) -> Result<Self::Value, String> fn visit_str(self, v: &str) -> Result<Self::Value, String>
{ {
Err(format!("Unexpected str {}", v)) Err(format!("Unexpected str {}", v))
@ -54,11 +99,13 @@ macro_rules! serialize_type {
serialize_type!(bool); serialize_type!(bool);
serialize_type!(char); serialize_type!(char);
serialize_type!(usize);
serialize_type!(u8); serialize_type!(u8);
serialize_type!(u16); serialize_type!(u16);
serialize_type!(u32); serialize_type!(u32);
serialize_type!(u64); serialize_type!(u64);
serialize_type!(isize);
serialize_type!(i8); serialize_type!(i8);
serialize_type!(i16); serialize_type!(i16);
serialize_type!(i32); serialize_type!(i32);
@ -66,4 +113,3 @@ serialize_type!(i64);
serialize_type!(f32); serialize_type!(f32);
serialize_type!(f64); serialize_type!(f64);

48
yaserde/tests/der_type.rs Normal file
View File

@ -0,0 +1,48 @@
extern crate yaserde;
#[macro_use]
extern crate yaserde_derive;
extern crate xml;
#[macro_use]
extern crate log;
use std::io::Read;
use yaserde::YaDeserialize;
use yaserde::de::from_str;
macro_rules! convert_and_validate {
($type:ty, $value:expr, $content:expr) => ({
#[derive(YaDeserialize, PartialEq, Debug)]
#[yaserde(root="data")]
pub struct Data {
item: $type
}
let model = Data {
item: $value
};
let content = String::from("<?xml version=\"1.0\" encoding=\"utf-8\"?><data><item>") + $content + "</item></data>";
let loaded : Result<Data, String> = from_str(&content);
assert_eq!(loaded, Ok(model));
})
}
#[test]
fn de_type() {
convert_and_validate!(bool, true, "true");
convert_and_validate!(u8, 12 as u8, "12");
convert_and_validate!(i8, 12 as i8, "12");
convert_and_validate!(i8, -12 as i8, "-12");
convert_and_validate!(u16, 12 as u16, "12");
convert_and_validate!(i16, 12 as i16, "12");
convert_and_validate!(i16, -12 as i16, "-12");
convert_and_validate!(u32, 12 as u32, "12");
convert_and_validate!(i32, 12 as i32, "12");
convert_and_validate!(i32, -12 as i32, "-12");
convert_and_validate!(u64, 12 as u64, "12");
convert_and_validate!(i64, 12 as i64, "12");
convert_and_validate!(i64, -12 as i64, "-12");
}

46
yaserde/tests/se_type.rs Normal file
View File

@ -0,0 +1,46 @@
extern crate yaserde;
#[macro_use]
extern crate yaserde_derive;
extern crate xml;
#[macro_use]
extern crate log;
use std::io::Write;
use yaserde::YaSerialize;
use yaserde::ser::to_string;
macro_rules! convert_and_validate {
($type:ty, $value:expr, $content:expr) => ({
#[derive(YaSerialize, PartialEq, Debug)]
#[yaserde(root="data")]
pub struct Data {
item: $type
}
let model = Data {
item: $value
};
let data : Result<String, String> = to_string(&model);
let content = String::from("<?xml version=\"1.0\" encoding=\"utf-8\"?><data><item>") + $content + "</item></data>";
assert_eq!(data, Ok(content));
})
}
#[test]
fn ser_type() {
convert_and_validate!(bool, true, "true");
convert_and_validate!(u8, 12 as u8, "12");
convert_and_validate!(i8, 12 as i8, "12");
convert_and_validate!(i8, -12 as i8, "-12");
convert_and_validate!(u16, 12 as u16, "12");
convert_and_validate!(i16, 12 as i16, "12");
convert_and_validate!(i16, -12 as i16, "-12");
convert_and_validate!(u32, 12 as u32, "12");
convert_and_validate!(i32, 12 as i32, "12");
convert_and_validate!(i32, -12 as i32, "-12");
convert_and_validate!(u64, 12 as u64, "12");
convert_and_validate!(i64, 12 as i64, "12");
convert_and_validate!(i64, -12 as i64, "-12");
}

View File

@ -8,7 +8,7 @@ use syn::Ident;
use syn::DataEnum; use syn::DataEnum;
use proc_macro2::Span; use proc_macro2::Span;
pub fn parse(data_enum: &DataEnum, name: &Ident, root: &String, namespaces: &BTreeMap<String, String>) -> Tokens { pub fn parse(data_enum: &DataEnum, name: &Ident, root: &String, _namespaces: &BTreeMap<String, String>) -> Tokens {
let variables : Tokens = data_enum.variants.iter().map(|ref variant| let variables : Tokens = data_enum.variants.iter().map(|ref variant|
{ {
match variant.fields { match variant.fields {
@ -18,12 +18,26 @@ pub fn parse(data_enum: &DataEnum, name: &Ident, root: &String, namespaces: &BTr
let field_label = field.ident; let field_label = field.ident;
match get_field_type(field) { match get_field_type(field) {
Some(FieldType::FieldTypeString) => { Some(FieldType::FieldTypeString) =>
Some(quote!{ build_default_value(&field_label, quote!{String}, quote!{"".to_string()}),
#[allow(unused_mut)] Some(FieldType::FieldTypeBool) =>
let mut #field_label : String = "".to_string(); build_default_value(&field_label, quote!{bool}, quote!{false}),
}) Some(FieldType::FieldTypeI8) =>
}, build_default_value(&field_label, quote!{i8}, quote!{0}),
Some(FieldType::FieldTypeU8) =>
build_default_value(&field_label, quote!{u8}, quote!{0}),
Some(FieldType::FieldTypeI16) =>
build_default_value(&field_label, quote!{i16}, quote!{0}),
Some(FieldType::FieldTypeU16) =>
build_default_value(&field_label, quote!{u16}, quote!{0}),
Some(FieldType::FieldTypeI32) =>
build_default_value(&field_label, quote!{i32}, quote!{0}),
Some(FieldType::FieldTypeU32) =>
build_default_value(&field_label, quote!{u32}, quote!{0}),
Some(FieldType::FieldTypeI64) =>
build_default_value(&field_label, quote!{i64}, quote!{0}),
Some(FieldType::FieldTypeU64) =>
build_default_value(&field_label, quote!{u64}, quote!{0}),
Some(FieldType::FieldTypeStruct{struct_name}) => { Some(FieldType::FieldTypeStruct{struct_name}) => {
Some(quote!{ Some(quote!{
#[allow(unused_mut)] #[allow(unused_mut)]
@ -33,12 +47,26 @@ pub fn parse(data_enum: &DataEnum, name: &Ident, root: &String, namespaces: &BTr
Some(FieldType::FieldTypeVec{data_type}) => { Some(FieldType::FieldTypeVec{data_type}) => {
let dt = Box::into_raw(data_type); let dt = Box::into_raw(data_type);
match unsafe{dt.as_ref()} { match unsafe{dt.as_ref()} {
Some(&FieldType::FieldTypeString) => { Some(&FieldType::FieldTypeString) =>
Some(quote!{ build_default_value(&field_label, quote!{Vec<String>}, quote!{vec![]}),
#[allow(unused_mut)] Some(&FieldType::FieldTypeBool) =>
let mut #field_label : Vec<String> = vec![]; build_default_value(&field_label, quote!{Vec<bool>}, quote!{vec![]}),
}) Some(&FieldType::FieldTypeI8) =>
}, build_default_value(&field_label, quote!{Vec<i8>}, quote!{vec![]}),
Some(&FieldType::FieldTypeU8) =>
build_default_value(&field_label, quote!{Vec<u8>}, quote!{vec![]}),
Some(&FieldType::FieldTypeI16) =>
build_default_value(&field_label, quote!{Vec<i16>}, quote!{vec![]}),
Some(&FieldType::FieldTypeU16) =>
build_default_value(&field_label, quote!{Vec<u16>}, quote!{vec![]}),
Some(&FieldType::FieldTypeI32) =>
build_default_value(&field_label, quote!{Vec<i32>}, quote!{vec![]}),
Some(&FieldType::FieldTypeU32) =>
build_default_value(&field_label, quote!{Vec<u32>}, quote!{vec![]}),
Some(&FieldType::FieldTypeI64) =>
build_default_value(&field_label, quote!{Vec<i64>}, quote!{vec![]}),
Some(&FieldType::FieldTypeU64) =>
build_default_value(&field_label, quote!{Vec<u64>}, quote!{vec![]}),
Some(&FieldType::FieldTypeStruct{struct_name}) => { Some(&FieldType::FieldTypeStruct{struct_name}) => {
Some(quote!{ Some(quote!{
#[allow(unused_mut)] #[allow(unused_mut)]
@ -181,13 +209,6 @@ pub fn parse(data_enum: &DataEnum, name: &Ident, root: &String, namespaces: &BTr
let _root = reader.next(); let _root = reader.next();
}, },
xml::reader::XmlEvent::Characters(characters_content) => { xml::reader::XmlEvent::Characters(characters_content) => {
// println!("{:?} - {:?} -- {:?}", prev_level, current_level, characters_content.as_str());
// if prev_level == current_level {
// match characters_content.as_str() {
// #match_to_enum
// _ => {}
// }
// }
let _root = reader.next(); let _root = reader.next();
}, },
event => { event => {
@ -206,3 +227,10 @@ pub fn parse(data_enum: &DataEnum, name: &Ident, root: &String, namespaces: &BTr
} }
} }
} }
fn build_default_value(label: &Option<Ident>, field_type: Tokens, default: Tokens) -> Option<Tokens> {
Some(quote!{
#[allow(unused_mut)]
let mut #label : #field_type = #default;
})
}

View File

@ -9,7 +9,7 @@ use proc_macro2::Span;
pub fn parse(data_struct: &DataStruct, name: &Ident, root: &String, namespaces: &BTreeMap<String, String>) -> Tokens { pub fn parse(data_struct: &DataStruct, name: &Ident, root: &String, namespaces: &BTreeMap<String, String>) -> Tokens {
let validate_namespace : Tokens = namespaces.iter().map(|(ref prefix, ref namespace)| { let validate_namespace : Tokens = namespaces.iter().map(|(ref _prefix, ref namespace)| {
Some(quote!( Some(quote!(
let mut found = false; let mut found = false;
@ -33,12 +33,26 @@ pub fn parse(data_struct: &DataStruct, name: &Ident, root: &String, namespaces:
{ {
let label = field.ident; let label = field.ident;
match get_field_type(field) { match get_field_type(field) {
Some(FieldType::FieldTypeString) => { Some(FieldType::FieldTypeString) =>
Some(quote!{ build_default_value(&label, quote!{String}, quote!{"".to_string()}),
#[allow(unused_mut)] Some(FieldType::FieldTypeBool) =>
let mut #label : String = "".to_string(); build_default_value(&label, quote!{bool}, quote!{false}),
}) Some(FieldType::FieldTypeI8) =>
}, build_default_value(&label, quote!{i8}, quote!{0}),
Some(FieldType::FieldTypeU8) =>
build_default_value(&label, quote!{u8}, quote!{0}),
Some(FieldType::FieldTypeI16) =>
build_default_value(&label, quote!{i16}, quote!{0}),
Some(FieldType::FieldTypeU16) =>
build_default_value(&label, quote!{u16}, quote!{0}),
Some(FieldType::FieldTypeI32) =>
build_default_value(&label, quote!{i32}, quote!{0}),
Some(FieldType::FieldTypeU32) =>
build_default_value(&label, quote!{u32}, quote!{0}),
Some(FieldType::FieldTypeI64) =>
build_default_value(&label, quote!{i64}, quote!{0}),
Some(FieldType::FieldTypeU64) =>
build_default_value(&label, quote!{u64}, quote!{0}),
Some(FieldType::FieldTypeStruct{struct_name}) => { Some(FieldType::FieldTypeStruct{struct_name}) => {
Some(quote!{ Some(quote!{
#[allow(unused_mut, non_snake_case, non_camel_case_types)] #[allow(unused_mut, non_snake_case, non_camel_case_types)]
@ -48,12 +62,26 @@ pub fn parse(data_struct: &DataStruct, name: &Ident, root: &String, namespaces:
Some(FieldType::FieldTypeVec{data_type}) => { Some(FieldType::FieldTypeVec{data_type}) => {
let dt = Box::into_raw(data_type); let dt = Box::into_raw(data_type);
match unsafe{dt.as_ref()} { match unsafe{dt.as_ref()} {
Some(&FieldType::FieldTypeString) => { Some(&FieldType::FieldTypeString) =>
Some(quote!{ build_default_value(&label, quote!{Vec<String>}, quote!{vec![]}),
#[allow(unused_mut)] Some(&FieldType::FieldTypeBool) =>
let mut #label : Vec<String> = vec![]; build_default_value(&label, quote!{Vec<bool>}, quote!{vec![]}),
}) Some(&FieldType::FieldTypeI8) =>
}, build_default_value(&label, quote!{Vec<i8>}, quote!{vec![]}),
Some(&FieldType::FieldTypeU8) =>
build_default_value(&label, quote!{Vec<u8>}, quote!{vec![]}),
Some(&FieldType::FieldTypeI16) =>
build_default_value(&label, quote!{Vec<i16>}, quote!{vec![]}),
Some(&FieldType::FieldTypeU16) =>
build_default_value(&label, quote!{Vec<u16>}, quote!{vec![]}),
Some(&FieldType::FieldTypeI32) =>
build_default_value(&label, quote!{Vec<i32>}, quote!{vec![]}),
Some(&FieldType::FieldTypeU32) =>
build_default_value(&label, quote!{Vec<u32>}, quote!{vec![]}),
Some(&FieldType::FieldTypeI64) =>
build_default_value(&label, quote!{Vec<i64>}, quote!{vec![]}),
Some(&FieldType::FieldTypeU64) =>
build_default_value(&label, quote!{Vec<u64>}, quote!{vec![]}),
Some(&FieldType::FieldTypeStruct{struct_name}) => { Some(&FieldType::FieldTypeStruct{struct_name}) => {
Some(quote!{ Some(quote!{
#[allow(unused_mut)] #[allow(unused_mut)]
@ -73,23 +101,56 @@ pub fn parse(data_struct: &DataStruct, name: &Ident, root: &String, namespaces:
let field_visitors: Tokens = data_struct.fields.iter().map(|ref field| let field_visitors: Tokens = data_struct.fields.iter().map(|ref field|
{ {
let label = field.ident; let field_attrs = YaSerdeAttribute::parse(&field.attrs);
let label_name = label.unwrap().to_string(); let label_name =
if let Some(value) = field_attrs.rename {
Ident::new(&format!("{}", value), Span::call_site()).to_string()
} else {
field.ident.unwrap().to_string()
};
let visitor_label = Ident::new(&format!("__Visitor{}", label_name), Span::call_site()); let visitor_label = Ident::new(&format!("__Visitor{}", label_name), Span::call_site());
match get_field_type(field) { match get_field_type(field) {
Some(FieldType::FieldTypeString) => { Some(FieldType::FieldTypeString) => {
Some(quote!{ let visitor = Ident::new("visit_str", Span::call_site());
#[allow(non_snake_case, non_camel_case_types)] build_declare_visitor(quote!{String}, &visitor, &visitor_label)
struct #visitor_label; },
impl<'de> Visitor<'de> for #visitor_label { Some(FieldType::FieldTypeBool) => {
type Value = String; let visitor = Ident::new("visit_bool", Span::call_site());
build_declare_visitor(quote!{bool}, &visitor, &visitor_label)
fn visit_str(self, v: &str) -> Result<Self::Value, String> { },
Ok(String::from(v)) Some(FieldType::FieldTypeI8) => {
} let visitor = Ident::new("visit_i8", Span::call_site());
} build_declare_visitor(quote!{i8}, &visitor, &visitor_label)
}) },
Some(FieldType::FieldTypeU8) => {
let visitor = Ident::new("visit_u8", Span::call_site());
build_declare_visitor(quote!{u8}, &visitor, &visitor_label)
},
Some(FieldType::FieldTypeI16) => {
let visitor = Ident::new("visit_i16", Span::call_site());
build_declare_visitor(quote!{i16}, &visitor, &visitor_label)
},
Some(FieldType::FieldTypeU16) => {
let visitor = Ident::new("visit_u16", Span::call_site());
build_declare_visitor(quote!{u16}, &visitor, &visitor_label)
},
Some(FieldType::FieldTypeI32) => {
let visitor = Ident::new("visit_i32", Span::call_site());
build_declare_visitor(quote!{i32}, &visitor, &visitor_label)
},
Some(FieldType::FieldTypeU32) => {
let visitor = Ident::new("visit_u32", Span::call_site());
build_declare_visitor(quote!{u32}, &visitor, &visitor_label)
},
Some(FieldType::FieldTypeI64) => {
let visitor = Ident::new("visit_i64", Span::call_site());
build_declare_visitor(quote!{i64}, &visitor, &visitor_label)
},
Some(FieldType::FieldTypeU64) => {
let visitor = Ident::new("visit_u64", Span::call_site());
build_declare_visitor(quote!{u64}, &visitor, &visitor_label)
}, },
Some(FieldType::FieldTypeStruct{struct_name}) => { Some(FieldType::FieldTypeStruct{struct_name}) => {
let struct_id = struct_name.to_string(); let struct_id = struct_name.to_string();
@ -113,17 +174,44 @@ pub fn parse(data_struct: &DataStruct, name: &Ident, root: &String, namespaces:
let dt = Box::into_raw(data_type); let dt = Box::into_raw(data_type);
match unsafe{dt.as_ref()} { match unsafe{dt.as_ref()} {
Some(&FieldType::FieldTypeString) => { Some(&FieldType::FieldTypeString) => {
Some(quote!{ let visitor = Ident::new("visit_str", Span::call_site());
#[allow(non_snake_case, non_camel_case_types)] build_declare_visitor(quote!{String}, &visitor, &visitor_label)
struct #visitor_label;
impl<'de> Visitor<'de> for #visitor_label {
type Value = String;
fn visit_str(self, v: &str) -> Result<Self::Value, String> {
Ok(String::from(v))
} }
Some(&FieldType::FieldTypeBool) => {
let visitor = Ident::new("visit_bool", Span::call_site());
build_declare_visitor(quote!{bool}, &visitor, &visitor_label)
} }
}) Some(&FieldType::FieldTypeI8) => {
let visitor = Ident::new("visit_i8", Span::call_site());
build_declare_visitor(quote!{i8}, &visitor, &visitor_label)
}
Some(&FieldType::FieldTypeU8) => {
let visitor = Ident::new("visit_u8", Span::call_site());
build_declare_visitor(quote!{u8}, &visitor, &visitor_label)
}
Some(&FieldType::FieldTypeI16) => {
let visitor = Ident::new("visit_i16", Span::call_site());
build_declare_visitor(quote!{i16}, &visitor, &visitor_label)
}
Some(&FieldType::FieldTypeU16) => {
let visitor = Ident::new("visit_u16", Span::call_site());
build_declare_visitor(quote!{u16}, &visitor, &visitor_label)
}
Some(&FieldType::FieldTypeI32) => {
let visitor = Ident::new("visit_i32", Span::call_site());
build_declare_visitor(quote!{i32}, &visitor, &visitor_label)
}
Some(&FieldType::FieldTypeU32) => {
let visitor = Ident::new("visit_u32", Span::call_site());
build_declare_visitor(quote!{u32}, &visitor, &visitor_label)
}
Some(&FieldType::FieldTypeI64) => {
let visitor = Ident::new("visit_i64", Span::call_site());
build_declare_visitor(quote!{i64}, &visitor, &visitor_label)
}
Some(&FieldType::FieldTypeU64) => {
let visitor = Ident::new("visit_u64", Span::call_site());
build_declare_visitor(quote!{u64}, &visitor, &visitor_label)
} }
Some(&FieldType::FieldTypeStruct{struct_name}) => { Some(&FieldType::FieldTypeStruct{struct_name}) => {
let struct_ident = Ident::new(&format!("{}", struct_name), Span::def_site()); let struct_ident = Ident::new(&format!("{}", struct_name), Span::def_site());
@ -167,31 +255,44 @@ pub fn parse(data_struct: &DataStruct, name: &Ident, root: &String, namespaces:
match get_field_type(field) { match get_field_type(field) {
Some(FieldType::FieldTypeString) => { Some(FieldType::FieldTypeString) => {
Some(quote!{ let visitor = Ident::new("visit_str", Span::call_site());
#label_name => { build_call_visitor(quote!{String}, &visitor, quote!{= value}, &visitor_label, &label, &label_name)
let visitor = #visitor_label{}; },
Some(FieldType::FieldTypeBool) => {
if let XmlEvent::StartElement { .. } = *reader.peek()? { let visitor = Ident::new("visit_bool", Span::call_site());
reader.set_map_value() build_call_visitor(quote!{bool}, &visitor, quote!{= value}, &visitor_label, &label, &label_name)
} },
Some(FieldType::FieldTypeI8) => {
let result = reader.read_inner_value::<String, _>(|reader| { let visitor = Ident::new("visit_i8", Span::call_site());
if let XmlEvent::EndElement { .. } = *reader.peek()? { build_call_visitor(quote!{i8}, &visitor, quote!{= value}, &visitor_label, &label, &label_name)
return visitor.visit_str(""); },
} Some(FieldType::FieldTypeU8) => {
let visitor = Ident::new("visit_u8", Span::call_site());
if let Ok(XmlEvent::Characters(s)) = reader.next() { build_call_visitor(quote!{u8}, &visitor, quote!{= value}, &visitor_label, &label, &label_name)
visitor.visit_str(&s) },
} else { Some(FieldType::FieldTypeU16) => {
Err(format!("unable to parse content for {}", #label_name)) let visitor = Ident::new("visit_u16", Span::call_site());
} build_call_visitor(quote!{u16}, &visitor, quote!{= value}, &visitor_label, &label, &label_name)
}); },
Some(FieldType::FieldTypeI16) => {
if let Ok(value) = result { let visitor = Ident::new("visit_i16", Span::call_site());
#label = value build_call_visitor(quote!{i16}, &visitor, quote!{= value}, &visitor_label, &label, &label_name)
} },
} Some(FieldType::FieldTypeU32) => {
}) let visitor = Ident::new("visit_u32", Span::call_site());
build_call_visitor(quote!{u32}, &visitor, quote!{= value}, &visitor_label, &label, &label_name)
},
Some(FieldType::FieldTypeI32) => {
let visitor = Ident::new("visit_i32", Span::call_site());
build_call_visitor(quote!{i32}, &visitor, quote!{= value}, &visitor_label, &label, &label_name)
},
Some(FieldType::FieldTypeU64) => {
let visitor = Ident::new("visit_u64", Span::call_site());
build_call_visitor(quote!{u64}, &visitor, quote!{= value}, &visitor_label, &label, &label_name)
},
Some(FieldType::FieldTypeI64) => {
let visitor = Ident::new("visit_i64", Span::call_site());
build_call_visitor(quote!{i64}, &visitor, quote!{= value}, &visitor_label, &label, &label_name)
}, },
Some(FieldType::FieldTypeStruct{struct_name}) => { Some(FieldType::FieldTypeStruct{struct_name}) => {
Some(quote!{ Some(quote!{
@ -213,30 +314,44 @@ pub fn parse(data_struct: &DataStruct, name: &Ident, root: &String, namespaces:
let dt = Box::into_raw(data_type); let dt = Box::into_raw(data_type);
match unsafe{dt.as_ref()} { match unsafe{dt.as_ref()} {
Some(&FieldType::FieldTypeString) => { Some(&FieldType::FieldTypeString) => {
Some(quote!{ let visitor = Ident::new("visit_str", Span::call_site());
#label_name => { build_call_visitor(quote!{String}, &visitor, quote!{.push(value)}, &visitor_label, &label, &label_name)
let visitor = #visitor_label{};
if let XmlEvent::StartElement { .. } = *reader.peek()? {
reader.set_map_value()
} }
Some(&FieldType::FieldTypeBool) => {
let result = reader.read_inner_value::<String, _>(|reader| { let visitor = Ident::new("visit_bool", Span::call_site());
if let XmlEvent::EndElement { .. } = *reader.peek()? { build_call_visitor(quote!{bool}, &visitor, quote!{.push(value)}, &visitor_label, &label, &label_name)
return visitor.visit_str("");
} }
Some(&FieldType::FieldTypeI8) => {
if let Ok(XmlEvent::Characters(s)) = reader.next() { let visitor = Ident::new("visit_i8", Span::call_site());
visitor.visit_str(&s) build_call_visitor(quote!{i8}, &visitor, quote!{.push(value)}, &visitor_label, &label, &label_name)
} else {
Err(format!("unable to parse content for {}", #label_name))
} }
}); Some(&FieldType::FieldTypeU8) => {
let visitor = Ident::new("visit_u8", Span::call_site());
if let Ok(value) = result { build_call_visitor(quote!{u8}, &visitor, quote!{.push(value)}, &visitor_label, &label, &label_name)
#label.push(value)
} }
Some(&FieldType::FieldTypeI16) => {
let visitor = Ident::new("visit_i16", Span::call_site());
build_call_visitor(quote!{i16}, &visitor, quote!{.push(value)}, &visitor_label, &label, &label_name)
} }
}) Some(&FieldType::FieldTypeU16) => {
let visitor = Ident::new("visit_u16", Span::call_site());
build_call_visitor(quote!{u16}, &visitor, quote!{.push(value)}, &visitor_label, &label, &label_name)
}
Some(&FieldType::FieldTypeI32) => {
let visitor = Ident::new("visit_i32", Span::call_site());
build_call_visitor(quote!{i32}, &visitor, quote!{.push(value)}, &visitor_label, &label, &label_name)
}
Some(&FieldType::FieldTypeU32) => {
let visitor = Ident::new("visit_u32", Span::call_site());
build_call_visitor(quote!{u32}, &visitor, quote!{.push(value)}, &visitor_label, &label, &label_name)
}
Some(&FieldType::FieldTypeI64) => {
let visitor = Ident::new("visit_i64", Span::call_site());
build_call_visitor(quote!{i64}, &visitor, quote!{.push(value)}, &visitor_label, &label, &label_name)
}
Some(&FieldType::FieldTypeU64) => {
let visitor = Ident::new("visit_u64", Span::call_site());
build_call_visitor(quote!{u64}, &visitor, quote!{.push(value)}, &visitor_label, &label, &label_name)
} }
Some(&FieldType::FieldTypeStruct{struct_name}) => { Some(&FieldType::FieldTypeStruct{struct_name}) => {
let struct_ident = Ident::new(&format!("{}", struct_name), Span::def_site()); let struct_ident = Ident::new(&format!("{}", struct_name), Span::def_site());
@ -272,7 +387,6 @@ pub fn parse(data_struct: &DataStruct, name: &Ident, root: &String, namespaces:
} }
let label = field.ident; let label = field.ident;
let field_ident = field.ident.unwrap().to_string();
let label_name = let label_name =
if let Some(value) = field_attrs.rename { if let Some(value) = field_attrs.rename {
Ident::new(&format!("{}", value), Span::call_site()).to_string() Ident::new(&format!("{}", value), Span::call_site()).to_string()
@ -291,7 +405,7 @@ pub fn parse(data_struct: &DataStruct, name: &Ident, root: &String, namespaces:
}) })
} }
Some(FieldType::FieldTypeStruct{struct_name}) => { Some(FieldType::FieldTypeStruct{struct_name}) => {
let struct_ident = Ident::new(&format!("__Visitor_{}_{}", field_ident, struct_name), Span::call_site()); let struct_ident = Ident::new(&format!("__Visitor_{}_{}", label_name, struct_name), Span::call_site());
Some(quote!{ Some(quote!{
for attr in attributes { for attr in attributes {
@ -319,15 +433,27 @@ pub fn parse(data_struct: &DataStruct, name: &Ident, root: &String, namespaces:
let field_attrs = YaSerdeAttribute::parse(&field.attrs); let field_attrs = YaSerdeAttribute::parse(&field.attrs);
match get_field_type(field) { match get_field_type(field) {
Some(FieldType::FieldTypeString) => { Some(FieldType::FieldTypeString) =>
if field_attrs.text { build_set_text_to_value(&field_attrs, &label, quote!{text_content.to_owned()}),
Some(quote!{ Some(FieldType::FieldTypeBool) =>
#label = text_content.to_owned(); build_set_text_to_value(&field_attrs, &label, quote!{bool::from_str(text_content).unwrap()}),
}) Some(FieldType::FieldTypeI8) =>
} else { build_set_text_to_value(&field_attrs, &label, quote!{i8::from_str(text_content).unwrap()}),
None Some(FieldType::FieldTypeU8) =>
} build_set_text_to_value(&field_attrs, &label, quote!{u8::from_str(text_content).unwrap()}),
}, Some(FieldType::FieldTypeI16) =>
build_set_text_to_value(&field_attrs, &label, quote!{i16::from_str(text_content).unwrap()}),
Some(FieldType::FieldTypeU16) =>
build_set_text_to_value(&field_attrs, &label, quote!{u16::from_str(text_content).unwrap()}),
Some(FieldType::FieldTypeI32) =>
build_set_text_to_value(&field_attrs, &label, quote!{i32::from_str(text_content).unwrap()}),
Some(FieldType::FieldTypeU32) =>
build_set_text_to_value(&field_attrs, &label, quote!{u32::from_str(text_content).unwrap()}),
Some(FieldType::FieldTypeI64) =>
build_set_text_to_value(&field_attrs, &label, quote!{i64::from_str(text_content).unwrap()}),
Some(FieldType::FieldTypeU64) =>
build_set_text_to_value(&field_attrs, &label, quote!{u64::from_str(text_content).unwrap()}),
Some(FieldType::FieldTypeStruct{..}) | Some(FieldType::FieldTypeStruct{..}) |
Some(FieldType::FieldTypeVec{..})| Some(FieldType::FieldTypeVec{..})|
None => None, None => None,
@ -341,14 +467,12 @@ pub fn parse(data_struct: &DataStruct, name: &Ident, root: &String, namespaces:
{ {
let label = field.ident; let label = field.ident;
match get_field_type(field) { if get_field_type(field).is_some() {
Some(FieldType::FieldTypeString) |
Some(FieldType::FieldTypeStruct{..}) |
Some(FieldType::FieldTypeVec{..}) =>
Some(quote!{ Some(quote!{
#label: #label, #label: #label,
}), })
None => None, } else {
None
} }
}) })
.filter(|x| x.is_some()) .filter(|x| x.is_some())
@ -358,6 +482,8 @@ pub fn parse(data_struct: &DataStruct, name: &Ident, root: &String, namespaces:
quote! { quote! {
use xml::reader::XmlEvent; use xml::reader::XmlEvent;
use yaserde::Visitor; use yaserde::Visitor;
#[allow(unknown_lints, unused_imports)]
use std::str::FromStr;
impl YaDeserialize for #name { impl YaDeserialize for #name {
#[allow(unused_variables)] #[allow(unused_variables)]
@ -410,3 +536,64 @@ pub fn parse(data_struct: &DataStruct, name: &Ident, root: &String, namespaces:
} }
} }
} }
fn build_default_value(label: &Option<Ident>, field_type: Tokens, default: Tokens) -> Option<Tokens> {
Some(quote!{
#[allow(unused_mut)]
let mut #label : #field_type = #default;
})
}
fn build_declare_visitor(field_type: Tokens, visitor: &Ident, visitor_label: &Ident) -> Option<Tokens> {
Some(quote!{
#[allow(non_snake_case, non_camel_case_types)]
struct #visitor_label;
impl<'de> Visitor<'de> for #visitor_label {
type Value = #field_type;
fn #visitor(self, v: &str) -> Result<Self::Value, String> {
Ok(#field_type::from_str(v).unwrap())
}
}
})
}
fn build_call_visitor(field_type: Tokens, visitor: &Ident, action: Tokens, visitor_label: &Ident, label: &Option<Ident>, label_name: &String) -> Option<Tokens> {
Some(quote!{
#label_name => {
let visitor = #visitor_label{};
if let XmlEvent::StartElement { .. } = *reader.peek()? {
reader.set_map_value()
}
let result = reader.read_inner_value::<#field_type, _>(|reader| {
if let XmlEvent::EndElement { .. } = *reader.peek()? {
return visitor.#visitor("");
}
if let Ok(XmlEvent::Characters(s)) = reader.next() {
visitor.#visitor(&s)
} else {
Err(format!("unable to parse content for {}", #label_name))
}
});
if let Ok(value) = result {
// #label = value
#label#action
}
}
})
}
fn build_set_text_to_value(field_attrs: &YaSerdeAttribute, label: &Option<Ident>, action: Tokens) -> Option<Tokens> {
if field_attrs.text {
Some(quote!{
#label = #action;
})
} else {
None
}
}

View File

@ -6,6 +6,15 @@ use syn::Type::Path;
#[derive(Debug)] #[derive(Debug)]
pub enum FieldType { pub enum FieldType {
FieldTypeString, FieldTypeString,
FieldTypeBool,
FieldTypeI8,
FieldTypeU8,
FieldTypeI16,
FieldTypeU16,
FieldTypeI32,
FieldTypeU32,
FieldTypeI64,
FieldTypeU64,
FieldTypeVec{data_type: Box<FieldType>}, FieldTypeVec{data_type: Box<FieldType>},
FieldTypeStruct{struct_name: syn::Ident}, FieldTypeStruct{struct_name: syn::Ident},
} }
@ -14,6 +23,15 @@ impl FieldType {
fn from_ident(t: &syn::PathSegment) -> Option<FieldType> { fn from_ident(t: &syn::PathSegment) -> Option<FieldType> {
match t.ident.as_ref() { match t.ident.as_ref() {
"String" => Some(FieldType::FieldTypeString), "String" => Some(FieldType::FieldTypeString),
"bool" => Some(FieldType::FieldTypeBool),
"i8" => Some(FieldType::FieldTypeI8),
"u8" => Some(FieldType::FieldTypeU8),
"i16" => Some(FieldType::FieldTypeI16),
"u16" => Some(FieldType::FieldTypeU16),
"i32" => Some(FieldType::FieldTypeI32),
"u32" => Some(FieldType::FieldTypeU32),
"i64" => Some(FieldType::FieldTypeI64),
"u64" => Some(FieldType::FieldTypeU64),
"Vec" => { "Vec" => {
get_vec_type(t).map(|data_type| { get_vec_type(t).map(|data_type| {
let p = syn::PathSegment{ let p = syn::PathSegment{

View File

@ -30,11 +30,20 @@ pub fn serialize(data_struct: &DataStruct, name: &Ident, root: &String, namespac
}; };
match get_field_type(field) { match get_field_type(field) {
Some(FieldType::FieldTypeString) => Some(FieldType::FieldTypeString) |
Some(FieldType::FieldTypeBool) |
Some(FieldType::FieldTypeI8) |
Some(FieldType::FieldTypeU8) |
Some(FieldType::FieldTypeI16) |
Some(FieldType::FieldTypeU16) |
Some(FieldType::FieldTypeI32) |
Some(FieldType::FieldTypeU32) |
Some(FieldType::FieldTypeI64) |
Some(FieldType::FieldTypeU64) =>
Some(quote!{ Some(quote!{
.attr(#label_name, &self.#label) .attr(#label_name, &self.#label)
}), }),
Some(FieldType::FieldTypeStruct{struct_name: _struct_name}) => Some(FieldType::FieldTypeStruct{..}) =>
Some(quote!{ Some(quote!{
.attr(#label_name, &*{ .attr(#label_name, &*{
use std::mem; use std::mem;
@ -108,21 +117,35 @@ pub fn serialize(data_struct: &DataStruct, name: &Ident, root: &String, namespac
let end_event = XmlEvent::end_element(); let end_event = XmlEvent::end_element();
let _ret = writer.write(end_event); let _ret = writer.write(end_event);
}), }),
Some(FieldType::FieldTypeStruct{..}) => Some(FieldType::FieldTypeBool) |
Some(FieldType::FieldTypeI8) |
Some(FieldType::FieldTypeU8) |
Some(FieldType::FieldTypeI16) |
Some(FieldType::FieldTypeU16) |
Some(FieldType::FieldTypeI32) |
Some(FieldType::FieldTypeU32) |
Some(FieldType::FieldTypeI64) |
Some(FieldType::FieldTypeU64) =>
Some(quote!{ Some(quote!{
let start_event = XmlEvent::start_element(#label_name); let start_event = XmlEvent::start_element(#label_name);
let _ret = writer.write(start_event); let _ret = writer.write(start_event);
writer.set_skip_start_end(true); let content = format!("{}", &self.#label);
let data_event = XmlEvent::characters(&content);
let _ret = writer.write(data_event);
let end_event = XmlEvent::end_element();
let _ret = writer.write(end_event);
}),
Some(FieldType::FieldTypeStruct{..}) =>
Some(quote!{
writer.set_skip_start_end(false);
match self.#label.serialize(writer) { match self.#label.serialize(writer) {
Ok(()) => {}, Ok(()) => {},
Err(msg) => { Err(msg) => {
return Err(msg); return Err(msg);
}, },
}; };
let struct_end_event = XmlEvent::end_element();
let _ret = writer.write(struct_end_event);
}), }),
Some(FieldType::FieldTypeVec{data_type}) => { Some(FieldType::FieldTypeVec{data_type}) => {
let dt = Box::into_raw(data_type); let dt = Box::into_raw(data_type);
@ -141,12 +164,30 @@ pub fn serialize(data_struct: &DataStruct, name: &Ident, root: &String, namespac
} }
}) })
}, },
Some(&FieldType::FieldTypeStruct{..}) => { Some(&FieldType::FieldTypeBool) |
Some(&FieldType::FieldTypeI8) |
Some(&FieldType::FieldTypeU8) |
Some(&FieldType::FieldTypeI16) |
Some(&FieldType::FieldTypeU16) |
Some(&FieldType::FieldTypeI32) |
Some(&FieldType::FieldTypeU32) |
Some(&FieldType::FieldTypeI64) |
Some(&FieldType::FieldTypeU64) => {
Some(quote!{ Some(quote!{
for item in &self.#label {
let start_event = XmlEvent::start_element(#label_name); let start_event = XmlEvent::start_element(#label_name);
let _ret = writer.write(start_event); let _ret = writer.write(start_event);
let data_event = XmlEvent::characters(format!("{}", item));
let _ret = writer.write(data_event);
let end_event = XmlEvent::end_element();
let _ret = writer.write(end_event);
}
})
},
Some(&FieldType::FieldTypeStruct{..}) => {
Some(quote!{
for item in &self.#label { for item in &self.#label {
writer.set_skip_start_end(false); writer.set_skip_start_end(false);
match item.serialize(writer) { match item.serialize(writer) {
@ -156,8 +197,6 @@ pub fn serialize(data_struct: &DataStruct, name: &Ident, root: &String, namespac
}, },
}; };
} }
let end_event = XmlEvent::end_element();
let _ret = writer.write(end_event);
}) })
}, },
Some(&FieldType::FieldTypeVec{..}) => {unimplemented!();}, Some(&FieldType::FieldTypeVec{..}) => {unimplemented!();},