diff --git a/yaserde/src/lib.rs b/yaserde/src/lib.rs index a2034f7..68becda 100644 --- a/yaserde/src/lib.rs +++ b/yaserde/src/lib.rs @@ -25,6 +25,51 @@ pub trait Visitor<'de>: Sized { /// The value produced by this visitor. type Value; + fn visit_bool(self, v: &str) -> Result + { + Err(format!("Unexpected bool {}", v)) + } + + fn visit_i8(self, v: &str) -> Result + { + Err(format!("Unexpected i8 {}", v)) + } + + fn visit_u8(self, v: &str) -> Result + { + Err(format!("Unexpected u8 {}", v)) + } + + fn visit_i16(self, v: &str) -> Result + { + Err(format!("Unexpected i16 {}", v)) + } + + fn visit_u16(self, v: &str) -> Result + { + Err(format!("Unexpected u16 {}", v)) + } + + fn visit_i32(self, v: &str) -> Result + { + Err(format!("Unexpected i32 {}", v)) + } + + fn visit_u32(self, v: &str) -> Result + { + Err(format!("Unexpected u32 {}", v)) + } + + fn visit_i64(self, v: &str) -> Result + { + Err(format!("Unexpected i64 {}", v)) + } + + fn visit_u64(self, v: &str) -> Result + { + Err(format!("Unexpected u64 {}", v)) + } + fn visit_str(self, v: &str) -> Result { 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); - diff --git a/yaserde/tests/der_type.rs b/yaserde/tests/der_type.rs new file mode 100644 index 0000000..d930986 --- /dev/null +++ b/yaserde/tests/der_type.rs @@ -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("") + $content + ""; + + let loaded : Result = 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"); +} diff --git a/yaserde/tests/se_type.rs b/yaserde/tests/se_type.rs new file mode 100644 index 0000000..29366a4 --- /dev/null +++ b/yaserde/tests/se_type.rs @@ -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 = to_string(&model); + let content = String::from("") + $content + ""; + 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"); +} diff --git a/yaserde_derive/src/de/expand_enum.rs b/yaserde_derive/src/de/expand_enum.rs index 3848680..0d84a08 100644 --- a/yaserde_derive/src/de/expand_enum.rs +++ b/yaserde_derive/src/de/expand_enum.rs @@ -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) -> Tokens { +pub fn parse(data_enum: &DataEnum, name: &Ident, root: &String, _namespaces: &BTreeMap) -> 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 = vec![]; - }) - }, + Some(&FieldType::FieldTypeString) => + build_default_value(&field_label, quote!{Vec}, quote!{vec![]}), + Some(&FieldType::FieldTypeBool) => + build_default_value(&field_label, quote!{Vec}, quote!{vec![]}), + Some(&FieldType::FieldTypeI8) => + build_default_value(&field_label, quote!{Vec}, quote!{vec![]}), + Some(&FieldType::FieldTypeU8) => + build_default_value(&field_label, quote!{Vec}, quote!{vec![]}), + Some(&FieldType::FieldTypeI16) => + build_default_value(&field_label, quote!{Vec}, quote!{vec![]}), + Some(&FieldType::FieldTypeU16) => + build_default_value(&field_label, quote!{Vec}, quote!{vec![]}), + Some(&FieldType::FieldTypeI32) => + build_default_value(&field_label, quote!{Vec}, quote!{vec![]}), + Some(&FieldType::FieldTypeU32) => + build_default_value(&field_label, quote!{Vec}, quote!{vec![]}), + Some(&FieldType::FieldTypeI64) => + build_default_value(&field_label, quote!{Vec}, quote!{vec![]}), + Some(&FieldType::FieldTypeU64) => + build_default_value(&field_label, quote!{Vec}, 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, field_type: Tokens, default: Tokens) -> Option { + Some(quote!{ + #[allow(unused_mut)] + let mut #label : #field_type = #default; + }) +} diff --git a/yaserde_derive/src/de/expand_struct.rs b/yaserde_derive/src/de/expand_struct.rs index 577c6e2..7961047 100644 --- a/yaserde_derive/src/de/expand_struct.rs +++ b/yaserde_derive/src/de/expand_struct.rs @@ -9,7 +9,7 @@ use proc_macro2::Span; pub fn parse(data_struct: &DataStruct, name: &Ident, root: &String, namespaces: &BTreeMap) -> 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 = vec![]; - }) - }, + Some(&FieldType::FieldTypeString) => + build_default_value(&label, quote!{Vec}, quote!{vec![]}), + Some(&FieldType::FieldTypeBool) => + build_default_value(&label, quote!{Vec}, quote!{vec![]}), + Some(&FieldType::FieldTypeI8) => + build_default_value(&label, quote!{Vec}, quote!{vec![]}), + Some(&FieldType::FieldTypeU8) => + build_default_value(&label, quote!{Vec}, quote!{vec![]}), + Some(&FieldType::FieldTypeI16) => + build_default_value(&label, quote!{Vec}, quote!{vec![]}), + Some(&FieldType::FieldTypeU16) => + build_default_value(&label, quote!{Vec}, quote!{vec![]}), + Some(&FieldType::FieldTypeI32) => + build_default_value(&label, quote!{Vec}, quote!{vec![]}), + Some(&FieldType::FieldTypeU32) => + build_default_value(&label, quote!{Vec}, quote!{vec![]}), + Some(&FieldType::FieldTypeI64) => + build_default_value(&label, quote!{Vec}, quote!{vec![]}), + Some(&FieldType::FieldTypeU64) => + build_default_value(&label, quote!{Vec}, 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 { - 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 { - 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::(|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::(|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, field_type: Tokens, default: Tokens) -> Option { + Some(quote!{ + #[allow(unused_mut)] + let mut #label : #field_type = #default; + }) +} + +fn build_declare_visitor(field_type: Tokens, visitor: &Ident, visitor_label: &Ident) -> Option { + 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 { + Ok(#field_type::from_str(v).unwrap()) + } + } + }) +} + +fn build_call_visitor(field_type: Tokens, visitor: &Ident, action: Tokens, visitor_label: &Ident, label: &Option, label_name: &String) -> Option { + 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, action: Tokens) -> Option { + if field_attrs.text { + Some(quote!{ + #label = #action; + }) + } else { + None + } +} diff --git a/yaserde_derive/src/field_type.rs b/yaserde_derive/src/field_type.rs index a7d279c..73f6f9c 100644 --- a/yaserde_derive/src/field_type.rs +++ b/yaserde_derive/src/field_type.rs @@ -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}, FieldTypeStruct{struct_name: syn::Ident}, } @@ -14,6 +23,15 @@ impl FieldType { fn from_ident(t: &syn::PathSegment) -> Option { 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{ diff --git a/yaserde_derive/src/ser/expand_struct.rs b/yaserde_derive/src/ser/expand_struct.rs index e015300..261e673 100644 --- a/yaserde_derive/src/ser/expand_struct.rs +++ b/yaserde_derive/src/ser/expand_struct.rs @@ -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!();},