diff --git a/yaserde/src/lib.rs b/yaserde/src/lib.rs index 9702656..91028b2 100644 --- a/yaserde/src/lib.rs +++ b/yaserde/src/lib.rs @@ -14,5 +14,5 @@ pub trait YaDeserialize : Sized { } pub trait YaSerialize : Sized { - fn derive_serialize(&self, read: &mut EventWriter) -> Result<(), String>; + fn derive_serialize(&self, read: &mut EventWriter, skip_start_end: bool) -> Result<(), String>; } diff --git a/yaserde/tests/deserializer.rs b/yaserde/tests/deserializer.rs index fcf7cb8..a462a2c 100644 --- a/yaserde/tests/deserializer.rs +++ b/yaserde/tests/deserializer.rs @@ -180,3 +180,59 @@ fn de_text_content_with_attributes() { } }); } + +#[test] +fn de_enum() { + #[derive(YaDeserialize, PartialEq, Debug)] + #[yaserde(root="base")] + pub struct XmlStruct { + background: Color + } + + #[derive(YaDeserialize, PartialEq, Debug)] + #[yaserde(root="color")] + pub enum Color { + White, + Black, + } + + impl Default for Color { + fn default() -> Color { + Color::White + } + } + + #[derive(YaDeserialize, PartialEq, Debug)] + pub struct RGBColor { + red: String, + green: String, + blue: String, + } + + impl Default for RGBColor { + fn default() -> RGBColor { + RGBColor{ + red: "0".to_string(), + green: "0".to_string(), + blue: "0".to_string(), + } + } + } + + #[derive(YaDeserialize, PartialEq, Debug)] + pub enum Alpha { + Transparent, + Opaque, + } + + impl Default for Alpha { + fn default() -> Alpha { + Alpha::Transparent + } + } + + let content = "Black"; + convert_and_validate!(content, XmlStruct, XmlStruct{ + background: Color::Black + }); +} diff --git a/yaserde/tests/serializer.rs b/yaserde/tests/serializer.rs index 39dbe07..e48588d 100644 --- a/yaserde/tests/serializer.rs +++ b/yaserde/tests/serializer.rs @@ -14,7 +14,7 @@ macro_rules! convert_and_validate { ($model:expr, $content:expr) => ( let mut buf = Cursor::new(Vec::new()); let mut writer = EventWriter::new(&mut buf); - let _status = $model.derive_serialize(&mut writer); + let _status = $model.derive_serialize(&mut writer, false); let buffer = writer.into_inner(); let cursor = buffer.get_ref(); @@ -215,7 +215,7 @@ fn ser_enum() { White, Black, #[yaserde(rename="custom")] - Custom{ + Custom { enabled: String, color: RGBColor, alpha: Alpha, @@ -262,6 +262,6 @@ fn ser_enum() { } }; - let content = "true0128255OpaqueOpaqueTransparent"; + let content = "true0128255OpaqueOpaqueTransparent"; convert_and_validate!(model, content); } diff --git a/yaserde_derive/src/de/expand_enum.rs b/yaserde_derive/src/de/expand_enum.rs new file mode 100644 index 0000000..8a4d0e1 --- /dev/null +++ b/yaserde_derive/src/de/expand_enum.rs @@ -0,0 +1,290 @@ + +use attribute::*; +use field_type::*; +use quote::Tokens; +use syn::Fields; +use syn::Ident; +use syn::DataEnum; +use proc_macro2::Span; + +pub fn parse(data_enum: &DataEnum, name: &Ident, root: &String) -> Tokens { + let variables : Tokens = data_enum.variants.iter().map(|ref variant| + { + match variant.fields { + Fields::Unit => None, + Fields::Named(ref fields) => { + let enum_fields = fields.named.iter().map(|ref field| { + let field_label = field.ident; + + match get_field_type(field) { + Some(FieldType::FieldTypeString) => { + Some(quote!{ + let mut #field_label : String = "".to_string(); + }) + }, + Some(FieldType::FieldTypeStruct{struct_name}) => { + Some(quote!{ + let mut #field_label : #struct_name = #struct_name::default(); + }) + }, + Some(FieldType::FieldTypeVec{data_type}) => { + let dt = Box::into_raw(data_type); + match unsafe{dt.as_ref()} { + Some(&FieldType::FieldTypeString) => { + Some(quote!{ + let mut #field_label : Vec = vec![]; + }) + }, + Some(&FieldType::FieldTypeStruct{struct_name}) => { + Some(quote!{ + let mut #field_label : Vec<#struct_name> = vec![]; + }) + }, + Some(&FieldType::FieldTypeVec{..}) => {unimplemented!();}, + None => {unimplemented!();}, + } + }, + None => None + } + + }) + .filter(|x| x.is_some()) + .map(|x| x.unwrap()) + .fold(Tokens::new(), |mut sum, val| {sum.append_all(val); sum}); + + Some(enum_fields) + } + Fields::Unnamed(ref _fields) => { + unimplemented!(); + } + } + }) + .filter(|x| x.is_some()) + .map(|x| x.unwrap()) + .fold(Tokens::new(), |mut sum, val| {sum.append_all(val); sum}); + + let fields : Tokens = data_enum.variants.iter().map(|ref variant| + { + let variant_attrs = YaSerdeAttribute::parse(&variant.attrs); + let renamed_variant_label = + match variant_attrs.rename { + Some(value) => Ident::new(&format!("{}", value), Span::call_site()), + None => variant.ident + }; + let variant_label_name = renamed_variant_label.to_string(); + + match variant.fields { + Fields::Unit => None, + Fields::Named(ref fields) => { + let enum_fields = fields.named.iter().map(|ref field| { + let field_attrs = YaSerdeAttribute::parse(&field.attrs); + let field_label = field.ident; + let renamed_field_label = + match field_attrs.rename { + Some(value) => Some(Ident::new(&format!("{}", value), Span::call_site())), + None => field.ident + }; + + let field_label_name = renamed_field_label.unwrap().to_string(); + match get_field_type(field) { + Some(FieldType::FieldTypeString) => { + Some(quote!{ + #variant_label_name => { + #[warn(unused_assignments)] + let mut local_level = 0; + let mut search_local_level = 0; + loop{ + match read.next() { + Ok(XmlEvent::StartElement{name, attributes, namespace: _namespace}) => { + if name.local_name == #field_label_name { + search_local_level += 1 + } + local_level += 1; + }, + Ok(XmlEvent::EndElement{name}) => { + local_level -= 1; + if name.local_name == #field_label_name { + break; + } + }, + Ok(xml::reader::XmlEvent::Characters(characters_content)) => { + if local_level == 1 && search_local_level == 1 { + #field_label = characters_content.trim().to_string(); + } + }, + _ => {}, + } + } + }, + }) + }, + Some(FieldType::FieldTypeStruct{struct_name: _struct_name}) => { + println!("{:?}", field); + Some(quote!{ + #field_label_name => { + println!("Start to parse {:?}", #field_label_name); + #[warn(unused_assignments)] + let mut local_level = 0; + let mut search_local_level = 0; + + loop{ + match read.next() { + Ok(XmlEvent::StartElement{name, attributes, namespace: _namespace}) => { + println!("Enum: start element = {:?}", name.local_name.as_str()); + if name.local_name == #field_label_name { + search_local_level += 1 + } + local_level += 1; + prev_level += 1; + }, + Ok(XmlEvent::EndElement{name}) => { + println!("Enum: end element = {:?}", name.local_name.as_str()); + local_level -= 1; + if name.local_name == #field_label_name { + break; + } + }, + Ok(xml::reader::XmlEvent::Characters(characters_content)) => { + println!("Enum: found value = {:?}", characters_content); + if local_level == 1 && search_local_level == 1 { + println!("found value = {:?}", characters_content); + #field_label = characters_content.trim().to_string(); + } + }, + _ => {}, + } + } + }, + }) + }, + data => { + println!("{:?}", data); + None} + } + + }) + .filter(|x| x.is_some()) + .map(|x| x.unwrap()) + .fold(Tokens::new(), |mut sum, val| {sum.append_all(val); sum}); + + Some(enum_fields) + }, + Fields::Unnamed(ref _fields) => {unimplemented!();} + } + }) + .filter(|x| x.is_some()) + .map(|x| x.unwrap()) + .fold(Tokens::new(), |mut sum, val| {sum.append_all(val); sum}); + + let match_to_enum : Tokens = data_enum.variants.iter().map(|ref variant| + { + let field_attrs = YaSerdeAttribute::parse(&variant.attrs); + let renamed_label = + match field_attrs.rename { + Some(value) => Ident::new(&format!("{}", value), Span::call_site()), + None => variant.ident + }; + let label = variant.ident; + let label_name = renamed_label.to_string(); + + match variant.fields { + Fields::Unit => { + Some(quote!{ + #label_name => { + simple_enum_value = Some(#name::#label); + } + }) + }, + Fields::Named(ref _fields) => { + None + } + Fields::Unnamed(ref _fields) => { + None + } + } + }) + .filter(|x| x.is_some()) + .map(|x| x.unwrap()) + .fold(Tokens::new(), |mut tokens, token| {tokens.append_all(token); tokens}); + + quote!{ + use xml::reader::XmlEvent; + + impl YaDeserialize for #name { + #[allow(unused_variables)] + fn derive_deserialize(read: &mut xml::EventReader, parent_attributes: Option<&Vec>) -> Result { + let mut prev_level = 0; + let mut current_level = 0; + #[warn(unused_assignments, unused_mut)] + let mut simple_enum_value = None; + + println!("Enum: start to parse {}", #root); + #variables + + loop { + match read.next() { + Ok(XmlEvent::StartDocument{..}) => { + }, + Ok(XmlEvent::EndDocument) => { + break; + }, + Ok(XmlEvent::StartElement{name, attributes, namespace: _namespace}) => { + println!("Enum: {} | {} - {}: {}", #root, prev_level, current_level, name.local_name.as_str()); + if prev_level == current_level { + match name.local_name.as_str() { + #root => { + let root_attributes = attributes.clone(); + let current_attributes = Some(&root_attributes); + + current_level += 1; + }, + #fields + _ => {} + }; + } + + prev_level += 1; + }, + Ok(XmlEvent::EndElement{name}) => { + println!("CLOSE {} | {} - {}: {}", #root, prev_level, current_level, name.local_name.as_str()); + + if prev_level == current_level { + println!("LEVEL BREAK {}", #root); + match simple_enum_value { + Some(value) => return Ok(value), + None => { + return Ok(#name::default()); + }, + } + } + prev_level -= 1; + }, + Ok(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 + _ => {} + } + } + }, + Ok(event) => { + println!("{:?}", event); + }, + Err(_msg) => { + break; + }, + } + } + + match simple_enum_value { + Some(value) => Ok(value), + None => { + Ok(#name::default()) + // Err("unable to load Enum value".to_string()) + }, + } + } + } + } +} diff --git a/yaserde_derive/src/de/expand_struct.rs b/yaserde_derive/src/de/expand_struct.rs index 93b103a..6856abe 100644 --- a/yaserde_derive/src/de/expand_struct.rs +++ b/yaserde_derive/src/de/expand_struct.rs @@ -224,6 +224,8 @@ pub fn parse(data_struct: &DataStruct, name: &Ident, root: &String) -> Tokens { let mut prev_level = 0; let mut current_level = 0; + println!("Struct: start to parse {}", #root); + #variables let current_attributes = parent_attributes; #attributes_loading @@ -236,7 +238,7 @@ pub fn parse(data_struct: &DataStruct, name: &Ident, root: &String) -> Tokens { break; }, Ok(XmlEvent::StartElement{name, attributes, namespace: _namespace}) => { - // println!("{} | {} - {}: {}", #root, prev_level, current_level, name.local_name.as_str()); + println!("Struct: {} | {} - {}: {}", #root, prev_level, current_level, name.local_name.as_str()); if prev_level == current_level { match name.local_name.as_str() { #root => { @@ -254,8 +256,9 @@ pub fn parse(data_struct: &DataStruct, name: &Ident, root: &String) -> Tokens { prev_level += 1; }, Ok(XmlEvent::EndElement{name}) => { + println!("Struct: end element {}", name); if #root == name.local_name.as_str() { - // println!("BREAK {}", #root); + println!("Struct: break for {}", #root); break; } prev_level -= 1; diff --git a/yaserde_derive/src/de/mod.rs b/yaserde_derive/src/de/mod.rs index b5caa58..37d72fe 100644 --- a/yaserde_derive/src/de/mod.rs +++ b/yaserde_derive/src/de/mod.rs @@ -1,4 +1,5 @@ +pub mod expand_enum; pub mod expand_struct; use attribute; @@ -20,8 +21,8 @@ pub fn expand_derive_deserialize(ast: &syn::DeriveInput) -> Result { expand_struct::parse(data_struct, &name, &root) }, - &syn::Data::Enum(ref _data_enum) => { - unimplemented!() + &syn::Data::Enum(ref data_enum) => { + expand_enum::parse(data_enum, &name, &root) }, &syn::Data::Union(ref _data_union) => { unimplemented!() diff --git a/yaserde_derive/src/lib.rs b/yaserde_derive/src/lib.rs index 02cc717..c805912 100644 --- a/yaserde_derive/src/lib.rs +++ b/yaserde_derive/src/lib.rs @@ -1,4 +1,4 @@ -#![recursion_limit="128"] +#![recursion_limit="256"] extern crate proc_macro; extern crate proc_macro2; diff --git a/yaserde_derive/src/ser/expand_enum.rs b/yaserde_derive/src/ser/expand_enum.rs index 6985c14..55978a7 100644 --- a/yaserde_derive/src/ser/expand_enum.rs +++ b/yaserde_derive/src/ser/expand_enum.rs @@ -10,9 +10,9 @@ use proc_macro2::Span; pub fn serialize(data_enum: &DataEnum, name: &Ident, root: &String) -> Tokens { let write_enum_content : Tokens = data_enum.variants.iter().map(|ref variant| { - let field_attrs = YaSerdeAttribute::parse(&variant.attrs); + let variant_attrs = YaSerdeAttribute::parse(&variant.attrs); let renamed_label = - match field_attrs.rename { + match variant_attrs.rename { Some(value) => Ident::new(&format!("{}", value), Span::call_site()), None => variant.ident }; @@ -51,7 +51,6 @@ pub fn serialize(data_enum: &DataEnum, name: &Ident, root: &String) -> Tokens { }; let field_label_name = renamed_field_label.unwrap().to_string(); - match get_field_type(field) { Some(FieldType::FieldTypeString) => Some(quote!{ @@ -71,9 +70,12 @@ pub fn serialize(data_enum: &DataEnum, name: &Ident, root: &String) -> Tokens { }), Some(FieldType::FieldTypeStruct{..}) => Some(quote!{ + let struct_start_event = XmlEvent::start_element(#field_label_name); + let _ret = writer.write(struct_start_event); + match self { &#name::#label{ref #field_label, ..} => { - match #field_label.derive_serialize(writer) { + match #field_label.derive_serialize(writer, true) { Ok(()) => {}, Err(msg) => { return Err(msg); @@ -82,18 +84,26 @@ pub fn serialize(data_enum: &DataEnum, name: &Ident, root: &String) -> Tokens { }, _ => {} } + + let struct_end_event = XmlEvent::end_element(); + let _ret = writer.write(struct_end_event); }), Some(FieldType::FieldTypeVec{..}) => Some(quote!{ match self { &#name::#label{ref #field_label, ..} => { for item in #field_label { - match item.derive_serialize(writer) { + let struct_start_event = XmlEvent::start_element(#field_label_name); + let _ret = writer.write(struct_start_event); + + match item.derive_serialize(writer, true) { Ok(()) => {}, Err(msg) => { return Err(msg); }, }; + let struct_end_event = XmlEvent::end_element(); + let _ret = writer.write(struct_end_event); } }, _ => {} @@ -127,22 +137,25 @@ pub fn serialize(data_enum: &DataEnum, name: &Ident, root: &String) -> Tokens { .map(|x| x.unwrap()) .fold(Tokens::new(), |mut tokens, token| {tokens.append_all(token); tokens}); - // println!("{:?}", write_enum_content); - quote! { use xml::writer::XmlEvent; impl YaSerialize for #name { #[allow(unused_variables)] - fn derive_serialize(&self, writer: &mut xml::EventWriter) -> Result<(), String> { - let struct_start_event = XmlEvent::start_element(#root); - let _ret = writer.write(struct_start_event); + fn derive_serialize(&self, writer: &mut xml::EventWriter, skip_start_end: bool) -> Result<(), String> { + if !skip_start_end { + let struct_start_event = XmlEvent::start_element(#root); + let _ret = writer.write(struct_start_event); + } + match self { #write_enum_content } - let struct_end_event = XmlEvent::end_element(); - let _ret = writer.write(struct_end_event); + if !skip_start_end { + let struct_end_event = XmlEvent::end_element(); + let _ret = writer.write(struct_end_event); + } Ok(()) } } diff --git a/yaserde_derive/src/ser/expand_struct.rs b/yaserde_derive/src/ser/expand_struct.rs index bb50aa5..f4e2f6c 100644 --- a/yaserde_derive/src/ser/expand_struct.rs +++ b/yaserde_derive/src/ser/expand_struct.rs @@ -68,7 +68,7 @@ pub fn serialize(data_struct: &DataStruct, name: &Ident, root: &String) -> Token }), Some(FieldType::FieldTypeStruct{..}) => Some(quote!{ - match self.#label.derive_serialize(writer) { + match self.#label.derive_serialize(writer, false) { Ok(()) => {}, Err(msg) => { return Err(msg); @@ -95,7 +95,7 @@ pub fn serialize(data_struct: &DataStruct, name: &Ident, root: &String) -> Token Some(&FieldType::FieldTypeStruct{..}) => { Some(quote!{ for item in &self.#label { - match item.derive_serialize(writer) { + match item.derive_serialize(writer, false) { Ok(()) => {}, Err(msg) => { return Err(msg); @@ -122,14 +122,18 @@ pub fn serialize(data_struct: &DataStruct, name: &Ident, root: &String) -> Token impl YaSerialize for #name { #[allow(unused_variables)] - fn derive_serialize(&self, writer: &mut xml::EventWriter) -> Result<(), String> { - let struct_start_event = XmlEvent::start_element(#root)#build_attributes; - let _ret = writer.write(struct_start_event); + fn derive_serialize(&self, writer: &mut xml::EventWriter, skip_start_end: bool) -> Result<(), String> { + if !skip_start_end { + let struct_start_event = XmlEvent::start_element(#root)#build_attributes; + let _ret = writer.write(struct_start_event); + } #struct_inspector - let struct_end_event = XmlEvent::end_element(); - let _ret = writer.write(struct_end_event); + if !skip_start_end { + let struct_end_event = XmlEvent::end_element(); + let _ret = writer.write(struct_end_event); + } Ok(()) } }