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.
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>
{
Err(format!("Unexpected str {}", v))
@ -54,11 +99,13 @@ macro_rules! serialize_type {
serialize_type!(bool);
serialize_type!(char);
serialize_type!(usize);
serialize_type!(u8);
serialize_type!(u16);
serialize_type!(u32);
serialize_type!(u64);
serialize_type!(isize);
serialize_type!(i8);
serialize_type!(i16);
serialize_type!(i32);
@ -66,4 +113,3 @@ serialize_type!(i64);
serialize_type!(f32);
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 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|
{
match variant.fields {
@ -18,12 +18,26 @@ pub fn parse(data_enum: &DataEnum, name: &Ident, root: &String, namespaces: &BTr
let field_label = field.ident;
match get_field_type(field) {
Some(FieldType::FieldTypeString) => {
Some(quote!{
#[allow(unused_mut)]
let mut #field_label : String = "".to_string();
})
},
Some(FieldType::FieldTypeString) =>
build_default_value(&field_label, quote!{String}, quote!{"".to_string()}),
Some(FieldType::FieldTypeBool) =>
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(quote!{
#[allow(unused_mut)]
@ -33,12 +47,26 @@ pub fn parse(data_enum: &DataEnum, name: &Ident, root: &String, namespaces: &BTr
Some(FieldType::FieldTypeVec{data_type}) => {
let dt = Box::into_raw(data_type);
match unsafe{dt.as_ref()} {
Some(&FieldType::FieldTypeString) => {
Some(quote!{
#[allow(unused_mut)]
let mut #field_label : Vec<String> = vec![];
})
},
Some(&FieldType::FieldTypeString) =>
build_default_value(&field_label, quote!{Vec<String>}, quote!{vec![]}),
Some(&FieldType::FieldTypeBool) =>
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(quote!{
#[allow(unused_mut)]
@ -181,13 +209,6 @@ pub fn parse(data_enum: &DataEnum, name: &Ident, root: &String, namespaces: &BTr
let _root = reader.next();
},
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();
},
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 {
let validate_namespace : Tokens = namespaces.iter().map(|(ref prefix, ref namespace)| {
let validate_namespace : Tokens = namespaces.iter().map(|(ref _prefix, ref namespace)| {
Some(quote!(
let mut found = false;
@ -33,12 +33,26 @@ pub fn parse(data_struct: &DataStruct, name: &Ident, root: &String, namespaces:
{
let label = field.ident;
match get_field_type(field) {
Some(FieldType::FieldTypeString) => {
Some(quote!{
#[allow(unused_mut)]
let mut #label : String = "".to_string();
})
},
Some(FieldType::FieldTypeString) =>
build_default_value(&label, quote!{String}, quote!{"".to_string()}),
Some(FieldType::FieldTypeBool) =>
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(quote!{
#[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}) => {
let dt = Box::into_raw(data_type);
match unsafe{dt.as_ref()} {
Some(&FieldType::FieldTypeString) => {
Some(quote!{
#[allow(unused_mut)]
let mut #label : Vec<String> = vec![];
})
},
Some(&FieldType::FieldTypeString) =>
build_default_value(&label, quote!{Vec<String>}, quote!{vec![]}),
Some(&FieldType::FieldTypeBool) =>
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(quote!{
#[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 label = field.ident;
let label_name = label.unwrap().to_string();
let field_attrs = YaSerdeAttribute::parse(&field.attrs);
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());
match get_field_type(field) {
Some(FieldType::FieldTypeString) => {
Some(quote!{
#[allow(non_snake_case, non_camel_case_types)]
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))
}
}
})
let visitor = Ident::new("visit_str", Span::call_site());
build_declare_visitor(quote!{String}, &visitor, &visitor_label)
},
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}) => {
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);
match unsafe{dt.as_ref()} {
Some(&FieldType::FieldTypeString) => {
Some(quote!{
#[allow(non_snake_case, non_camel_case_types)]
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))
}
}
})
let visitor = Ident::new("visit_str", Span::call_site());
build_declare_visitor(quote!{String}, &visitor, &visitor_label)
}
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}) => {
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) {
Some(FieldType::FieldTypeString) => {
Some(quote!{
#label_name => {
let visitor = #visitor_label{};
if let XmlEvent::StartElement { .. } = *reader.peek()? {
reader.set_map_value()
}
let result = reader.read_inner_value::<String, _>(|reader| {
if let XmlEvent::EndElement { .. } = *reader.peek()? {
return visitor.visit_str("");
}
if let Ok(XmlEvent::Characters(s)) = reader.next() {
visitor.visit_str(&s)
} else {
Err(format!("unable to parse content for {}", #label_name))
}
});
if let Ok(value) = result {
#label = value
}
}
})
let visitor = Ident::new("visit_str", Span::call_site());
build_call_visitor(quote!{String}, &visitor, quote!{= value}, &visitor_label, &label, &label_name)
},
Some(FieldType::FieldTypeBool) => {
let visitor = Ident::new("visit_bool", Span::call_site());
build_call_visitor(quote!{bool}, &visitor, quote!{= value}, &visitor_label, &label, &label_name)
},
Some(FieldType::FieldTypeI8) => {
let visitor = Ident::new("visit_i8", Span::call_site());
build_call_visitor(quote!{i8}, &visitor, quote!{= value}, &visitor_label, &label, &label_name)
},
Some(FieldType::FieldTypeU8) => {
let visitor = Ident::new("visit_u8", Span::call_site());
build_call_visitor(quote!{u8}, &visitor, quote!{= 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!{= value}, &visitor_label, &label, &label_name)
},
Some(FieldType::FieldTypeI16) => {
let visitor = Ident::new("visit_i16", Span::call_site());
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(quote!{
@ -213,30 +314,44 @@ pub fn parse(data_struct: &DataStruct, name: &Ident, root: &String, namespaces:
let dt = Box::into_raw(data_type);
match unsafe{dt.as_ref()} {
Some(&FieldType::FieldTypeString) => {
Some(quote!{
#label_name => {
let visitor = #visitor_label{};
if let XmlEvent::StartElement { .. } = *reader.peek()? {
reader.set_map_value()
}
let result = reader.read_inner_value::<String, _>(|reader| {
if let XmlEvent::EndElement { .. } = *reader.peek()? {
return visitor.visit_str("");
}
if let Ok(XmlEvent::Characters(s)) = reader.next() {
visitor.visit_str(&s)
} else {
Err(format!("unable to parse content for {}", #label_name))
}
});
if let Ok(value) = result {
#label.push(value)
}
}
})
let visitor = Ident::new("visit_str", Span::call_site());
build_call_visitor(quote!{String}, &visitor, quote!{.push(value)}, &visitor_label, &label, &label_name)
}
Some(&FieldType::FieldTypeBool) => {
let visitor = Ident::new("visit_bool", Span::call_site());
build_call_visitor(quote!{bool}, &visitor, quote!{.push(value)}, &visitor_label, &label, &label_name)
}
Some(&FieldType::FieldTypeI8) => {
let visitor = Ident::new("visit_i8", Span::call_site());
build_call_visitor(quote!{i8}, &visitor, quote!{.push(value)}, &visitor_label, &label, &label_name)
}
Some(&FieldType::FieldTypeU8) => {
let visitor = Ident::new("visit_u8", Span::call_site());
build_call_visitor(quote!{u8}, &visitor, quote!{.push(value)}, &visitor_label, &label, &label_name)
}
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}) => {
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 field_ident = field.ident.unwrap().to_string();
let label_name =
if let Some(value) = field_attrs.rename {
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}) => {
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!{
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);
match get_field_type(field) {
Some(FieldType::FieldTypeString) => {
if field_attrs.text {
Some(quote!{
#label = text_content.to_owned();
})
} else {
None
}
},
Some(FieldType::FieldTypeString) =>
build_set_text_to_value(&field_attrs, &label, quote!{text_content.to_owned()}),
Some(FieldType::FieldTypeBool) =>
build_set_text_to_value(&field_attrs, &label, quote!{bool::from_str(text_content).unwrap()}),
Some(FieldType::FieldTypeI8) =>
build_set_text_to_value(&field_attrs, &label, quote!{i8::from_str(text_content).unwrap()}),
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::FieldTypeVec{..})|
None => None,
@ -341,14 +467,12 @@ pub fn parse(data_struct: &DataStruct, name: &Ident, root: &String, namespaces:
{
let label = field.ident;
match get_field_type(field) {
Some(FieldType::FieldTypeString) |
Some(FieldType::FieldTypeStruct{..}) |
Some(FieldType::FieldTypeVec{..}) =>
Some(quote!{
#label: #label,
}),
None => None,
if get_field_type(field).is_some() {
Some(quote!{
#label: #label,
})
} else {
None
}
})
.filter(|x| x.is_some())
@ -358,6 +482,8 @@ pub fn parse(data_struct: &DataStruct, name: &Ident, root: &String, namespaces:
quote! {
use xml::reader::XmlEvent;
use yaserde::Visitor;
#[allow(unknown_lints, unused_imports)]
use std::str::FromStr;
impl YaDeserialize for #name {
#[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)]
pub enum FieldType {
FieldTypeString,
FieldTypeBool,
FieldTypeI8,
FieldTypeU8,
FieldTypeI16,
FieldTypeU16,
FieldTypeI32,
FieldTypeU32,
FieldTypeI64,
FieldTypeU64,
FieldTypeVec{data_type: Box<FieldType>},
FieldTypeStruct{struct_name: syn::Ident},
}
@ -14,6 +23,15 @@ impl FieldType {
fn from_ident(t: &syn::PathSegment) -> Option<FieldType> {
match t.ident.as_ref() {
"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" => {
get_vec_type(t).map(|data_type| {
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) {
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!{
.attr(#label_name, &self.#label)
}),
Some(FieldType::FieldTypeStruct{struct_name: _struct_name}) =>
Some(FieldType::FieldTypeStruct{..}) =>
Some(quote!{
.attr(#label_name, &*{
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 _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!{
let start_event = XmlEvent::start_element(#label_name);
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) {
Ok(()) => {},
Err(msg) => {
return Err(msg);
},
};
let struct_end_event = XmlEvent::end_element();
let _ret = writer.write(struct_end_event);
}),
Some(FieldType::FieldTypeVec{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::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!{
for item in &self.#label {
let start_event = XmlEvent::start_element(#label_name);
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!{
let start_event = XmlEvent::start_element(#label_name);
let _ret = writer.write(start_event);
for item in &self.#label {
writer.set_skip_start_end(false);
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!();},