From 0540b127bd8028059fbd4614f99ba26adc3700f0 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Arnaud Date: Sun, 13 May 2018 09:51:28 +0200 Subject: [PATCH] refactoring code to better support --- Cargo.toml | 1 + README.md | 13 + yaserde/Cargo.toml | 1 + yaserde/src/de/mod.rs | 150 ++++++++ yaserde/src/lib.rs | 28 +- yaserde/src/ser/mod.rs | 83 +++++ yaserde/tests/deserializer.rs | 140 +++++--- yaserde/tests/serializer.rs | 46 ++- yaserde_derive/src/de/expand_enum.rs | 207 ++++------- yaserde_derive/src/de/expand_struct.rs | 434 +++++++++++++++--------- yaserde_derive/src/field_type.rs | 33 +- yaserde_derive/src/ser/expand_enum.rs | 25 +- yaserde_derive/src/ser/expand_struct.rs | 35 +- yaserde_derive/src/ser/mod.rs | 1 - 14 files changed, 782 insertions(+), 415 deletions(-) create mode 100644 yaserde/src/de/mod.rs create mode 100644 yaserde/src/ser/mod.rs diff --git a/Cargo.toml b/Cargo.toml index fe4f64d..093f44f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,4 +2,5 @@ members = [ "yaserde", "yaserde_derive", + "dump", ] diff --git a/README.md b/README.md index c37340f..58d2401 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,15 @@ # yaserde Yet Another Serializer/Deserializer + + +- [ ] Option +- [ ] Enum + +- [ ] Visitor Type -> String / String -> Type +- [ ] namespace + +- [ ] + + +std::str::FromStr +std::string::ToString diff --git a/yaserde/Cargo.toml b/yaserde/Cargo.toml index ac3a624..9b489f1 100644 --- a/yaserde/Cargo.toml +++ b/yaserde/Cargo.toml @@ -14,6 +14,7 @@ readme = "../README.md" yaserde_derive = { version = "0.1", path = "../yaserde_derive", optional = true } regex = "0.2" xml-rs = "0.7.0" +log = "0.4.1" [dev-dependencies] yaserde_derive = { version = "0.1", path = "../yaserde_derive" } diff --git a/yaserde/src/de/mod.rs b/yaserde/src/de/mod.rs new file mode 100644 index 0000000..3ad0b7e --- /dev/null +++ b/yaserde/src/de/mod.rs @@ -0,0 +1,150 @@ + +use std::io::Read; +use xml::reader::{EventReader, ParserConfig, XmlEvent}; +use xml::name::OwnedName; +use YaDeserialize; + +pub fn from_str(s: &str) -> Result { + from_reader(s.as_bytes()) +} + +pub fn from_reader(reader: R) -> Result { + T::deserialize(&mut Deserializer::new_from_reader(reader)) +} + +pub struct Deserializer { + depth: usize, + reader: EventReader, + peeked: Option, + is_map_value: bool, +} + +impl<'de, R: Read> Deserializer { + pub fn new(reader: EventReader) -> Self { + Deserializer { + depth: 0, + reader: reader, + peeked: None, + is_map_value: false, + } + } + + pub fn new_from_reader(reader: R) -> Self { + let config = ParserConfig::new() + .trim_whitespace(true) + .whitespace_to_characters(true) + .cdata_to_characters(true) + .ignore_comments(true) + .coalesce_characters(true); + + Self::new(EventReader::new_with_config(reader, config)) + } + + pub fn peek(&mut self) -> Result<&XmlEvent, String> { + if self.peeked.is_none() { + self.peeked = Some(self.inner_next()?); + } + + if let Some(ref next) = self.peeked { + Ok(&next) + } else { + Err(String::from("unable to peek next item")) + } + } + + pub fn inner_next(&mut self) -> Result { + loop { + if let Ok(next) = self.reader.next() { + match next { + XmlEvent::StartDocument { .. } | + XmlEvent::ProcessingInstruction { .. } | + XmlEvent::Comment(_) => { /* skip */ }, + other => return Ok(other), + } + } else { + println!("{:?}", self.peeked); + return Err(String::from("bad content")); + } + } + } + + pub fn next(&mut self) -> Result { + let next = if let Some(peeked) = self.peeked.take() { + peeked + } else { + self.inner_next()? + }; + match next { + XmlEvent::StartElement { .. } => { + self.depth += 1; + }, + XmlEvent::EndElement { .. } => { + self.depth -= 1; + }, + _ => {}, + } + debug!("Fetched {:?}", next); + Ok(next) + } + + pub fn set_map_value(&mut self) { + self.is_map_value = true; + } + + pub fn unset_map_value(&mut self) -> bool { + ::std::mem::replace(&mut self.is_map_value, false) + } + + pub fn read_inner_value Result>( + &mut self, + f: F, + ) -> Result { + if self.unset_map_value() { + if let Ok(XmlEvent::StartElement { name, .. }) = self.next() { + let result = f(self)?; + self.expect_end_element(name)?; + Ok(result) + } else { + Err(format!("Internal error: Bad Event")) + } + } else { + f(self) + } + } + + pub fn expect_end_element(&mut self, start_name: OwnedName) -> Result<(), String> { + if let XmlEvent::EndElement{ name, .. } = self.next()? { + if name == start_name { + Ok(()) + } else { + Err(format!( + "End tag didn't match the start tag <{}>", + name.local_name, + start_name.local_name + )) + } + } else { + Err(String::from(format!( + "Unexpected token ", + start_name.local_name + ))) + } + } + + // fn prepare_parse_type>(&mut self) -> Result { + // if let XmlEvent::StartElement { .. } = *self.peek()? { + // self.set_map_value() + // } + // self.read_inner_value::(|this| { + // if let XmlEvent::EndElement { .. } = *this.peek()? { + // return Err( + // ErrorKind::UnexpectedToken("EndElement".into(), "Characters".into()).into(), + // ); + // } + + // expect!(this.next()?, XmlEvent::Characters(s) => { + // return Ok(s) + // }) + // }) + // } +} diff --git a/yaserde/src/lib.rs b/yaserde/src/lib.rs index 91028b2..5b9df7d 100644 --- a/yaserde/src/lib.rs +++ b/yaserde/src/lib.rs @@ -1,4 +1,6 @@ +#[macro_use] +extern crate log; extern crate xml; #[cfg(feature = "yaserde_derive")] #[allow(unused_imports)] @@ -6,13 +8,31 @@ extern crate xml; extern crate yaserde_derive; use std::io::{Read, Write}; -use xml::{EventReader, EventWriter}; -use xml::attribute::OwnedAttribute; + +pub mod de; +pub mod ser; pub trait YaDeserialize : Sized { - fn derive_deserialize(read: &mut EventReader, parent_attributes: Option<&Vec>) -> Result; + fn deserialize(reader: &mut de::Deserializer) -> Result; } pub trait YaSerialize : Sized { - fn derive_serialize(&self, read: &mut EventWriter, skip_start_end: bool) -> Result<(), String>; + fn serialize(&self, writer: &mut ser::Serializer) -> Result<(), String>; +} + +pub trait Visitor<'de>: Sized { + /// The value produced by this visitor. + type Value; + + fn visit_str(self, v: &str) -> Result + { + Err(format!("Unexpected str {}", v)) + } + + #[inline] + #[cfg(any(feature = "std", feature = "alloc"))] + fn visit_string(self, v: String) -> Result + { + self.visit_str(&v) + } } diff --git a/yaserde/src/ser/mod.rs b/yaserde/src/ser/mod.rs new file mode 100644 index 0000000..9639cc7 --- /dev/null +++ b/yaserde/src/ser/mod.rs @@ -0,0 +1,83 @@ + +use std::str; +use std::io::{Cursor, Write}; +use xml::{EmitterConfig, EventWriter}; +use xml; +use xml::writer::XmlEvent; +use YaSerialize; + +pub fn to_string(model: &T) -> Result { + let buf = Cursor::new(Vec::new()); + let cursor = serialize_with_writer(model, buf).unwrap(); + let data = str::from_utf8(cursor.get_ref()).expect("Found invalid UTF-8"); + Ok(String::from(data)) +} + +pub fn serialize_with_writer(model: &T, writer: W) -> Result { + let mut serializer = Serializer::new_from_writer(writer); + match model.serialize(&mut serializer) { + Ok(()) => Ok(serializer.into_inner()), + Err(msg) => Err(msg), + } +} + +pub fn to_string_content(model: &T) -> Result { + let buf = Cursor::new(Vec::new()); + let cursor = serialize_with_writer_content(model, buf).unwrap(); + let data = str::from_utf8(cursor.get_ref()).expect("Found invalid UTF-8"); + Ok(String::from(data)) +} + +pub fn serialize_with_writer_content(model: &T, writer: W) -> Result { + let mut serializer = Serializer::new_for_inner(writer); + serializer.set_skip_start_end(true); + match model.serialize(&mut serializer) { + Ok(()) => Ok(serializer.into_inner()), + Err(msg) => Err(msg), + } +} + +pub struct Serializer { + writer: EventWriter, + skip_start_end: bool +} + +impl<'de, W: Write> Serializer { + pub fn new(writer: EventWriter) -> Self { + Serializer { + writer: writer, + skip_start_end: false + } + } + + pub fn new_from_writer(writer: W) -> Self { + let config = EmitterConfig::new() + .cdata_to_characters(true); + + Self::new(EventWriter::new_with_config(writer, config)) + } + + pub fn new_for_inner(writer: W) -> Self { + let config = EmitterConfig::new() + .write_document_declaration(false); + + Self::new(EventWriter::new_with_config(writer, config)) + } + + pub fn into_inner(self) -> W { + self.writer.into_inner() + } + + pub fn skip_start_end(&self) -> bool { + self.skip_start_end + } + + pub fn set_skip_start_end(&mut self, state: bool) { + self.skip_start_end = state; + } + + pub fn write<'a, E>(&mut self, event: E) -> xml::writer::Result<()> + where E: Into> { + self.writer.write(event) + } +} diff --git a/yaserde/tests/deserializer.rs b/yaserde/tests/deserializer.rs index a462a2c..c423f34 100644 --- a/yaserde/tests/deserializer.rs +++ b/yaserde/tests/deserializer.rs @@ -3,16 +3,16 @@ extern crate yaserde; #[macro_use] extern crate yaserde_derive; extern crate xml; +#[macro_use] +extern crate log; use std::io::Read; -use xml::reader::EventReader; use yaserde::YaDeserialize; +use yaserde::de::from_str; macro_rules! convert_and_validate { ($content:expr, $struct:tt, $model:expr) => { - let mut parser = EventReader::from_str($content); - - let loaded = $struct::derive_deserialize(&mut parser, None); + let loaded : Result<$struct, String> = from_str($content); assert_eq!(loaded, Ok($model)); } } @@ -20,54 +20,59 @@ macro_rules! convert_and_validate { #[test] fn de_basic() { #[derive(YaDeserialize, PartialEq, Debug)] - #[yaserde(root="base")] - pub struct XmlStruct { - item: String + #[yaserde(root="book")] + pub struct Book { + author: String, + title: String, } - let content = "something"; - convert_and_validate!(content, XmlStruct, XmlStruct{ - item: "something".to_string() + let content = "Antoine de Saint-ExupéryLittle prince"; + convert_and_validate!(content, Book, Book{ + author: String::from("Antoine de Saint-Exupéry"), + title: String::from("Little prince") + }); + + let content = "Little princeAntoine de Saint-Exupéry"; + convert_and_validate!(content, Book, Book{ + author: String::from("Antoine de Saint-Exupéry"), + title: String::from("Little prince") }); } #[test] fn de_list_of_items() { #[derive(YaDeserialize, PartialEq, Debug)] - #[yaserde(root="base")] - pub struct XmlStruct { - items: Vec + #[yaserde(root="library")] + pub struct Library { + books: Vec } - let content = "something1something2"; - convert_and_validate!(content, XmlStruct, XmlStruct{ - items: vec![ - "something1".to_string(), - "something2".to_string() + let content = "Little PrinceHarry Potter"; + convert_and_validate!(content, Library, Library{ + books: vec![ + String::from("Little Prince"), + String::from("Harry Potter") ] }); #[derive(YaDeserialize, PartialEq, Debug)] - #[yaserde(root="base")] - pub struct XmlStructOfStruct { - items: Vec + #[yaserde(root="libraries")] + pub struct Libraries { + library: Vec } - - #[derive(YaDeserialize, PartialEq, Debug)] - #[yaserde(root="items")] - pub struct SubStruct { - field: String - } - - let content = "something1something2"; - convert_and_validate!(content, XmlStructOfStruct, XmlStructOfStruct{ - items: vec![ - SubStruct{ - field: "something1".to_string() + let content = "Little PrinceHarry Potter"; + convert_and_validate!(content, Libraries, Libraries{ + library: vec![ + Library{ + books: vec![ + String::from("Little Prince") + ] }, - SubStruct{ - field: "something2".to_string() + Library{ + books: vec![ + String::from("Harry Potter") + ] } ] }); @@ -189,6 +194,12 @@ fn de_enum() { background: Color } + #[derive(YaDeserialize, PartialEq, Debug)] + #[yaserde(root="base")] + pub struct Colors { + items: Vec + } + #[derive(YaDeserialize, PartialEq, Debug)] #[yaserde(root="color")] pub enum Color { @@ -219,20 +230,59 @@ fn de_enum() { } } - #[derive(YaDeserialize, PartialEq, Debug)] - pub enum Alpha { - Transparent, - Opaque, - } +// #[derive(YaDeserialize, PartialEq, Debug)] +// pub enum Alpha { +// Transparent, +// Opaque, +// } - impl Default for Alpha { - fn default() -> Alpha { - Alpha::Transparent - } - } +// impl Default for Alpha { +// fn default() -> Alpha { +// Alpha::Transparent +// } +// } + + + // let content = "Black"; + // convert_and_validate!(content, XmlStruct, XmlStruct{ + // background: Color::Black + // }); let content = "Black"; convert_and_validate!(content, XmlStruct, XmlStruct{ background: Color::Black }); + + let content = "BlackWhite"; + convert_and_validate!(content, Colors, Colors{ + items: vec![Color::Black, Color::White] + }); +} + +#[test] +fn de_attribute_enum() { + #[derive(YaDeserialize, PartialEq, Debug)] + #[yaserde(root="base")] + pub struct XmlStruct { + #[yaserde(attribute)] + background: Color + } + + #[derive(YaDeserialize, PartialEq, Debug)] + #[yaserde(root="color")] + pub enum Color { + White, + Black, + } + + impl Default for Color { + fn default() -> Color { + Color::White + } + } + + let content = ""; + convert_and_validate!(content, XmlStruct, XmlStruct{ + background: Color::Black + }); } diff --git a/yaserde/tests/serializer.rs b/yaserde/tests/serializer.rs index e48588d..2a2e7d8 100644 --- a/yaserde/tests/serializer.rs +++ b/yaserde/tests/serializer.rs @@ -3,24 +3,17 @@ extern crate yaserde; #[macro_use] extern crate yaserde_derive; extern crate xml; +#[macro_use] +extern crate log; -use std::str; -use std::io::Cursor; use std::io::Write; -use xml::writer::EventWriter; use yaserde::YaSerialize; +use yaserde::ser::to_string; 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, false); - - let buffer = writer.into_inner(); - let cursor = buffer.get_ref(); - - let data = str::from_utf8(cursor).expect("Found invalid UTF-8"); - assert_eq!(data, $content); + let data : Result = to_string(&$model); + assert_eq!(data, Ok(String::from($content))); ) } @@ -36,7 +29,7 @@ fn ser_basic() { item: "something".to_string() }; - let content = "something".to_string(); + let content = "something"; convert_and_validate!(model, content); } @@ -55,7 +48,7 @@ fn ser_list_of_items() { ] }; - let content = "something1something2".to_string(); + let content = "something1something2"; convert_and_validate!(model, content); @@ -265,3 +258,28 @@ fn ser_enum() { let content = "true0128255OpaqueOpaqueTransparent"; convert_and_validate!(model, content); } + + +#[test] +fn ser_attribute_enum() { + #[derive(YaSerialize, PartialEq, Debug)] + #[yaserde(root="base")] + pub struct XmlStruct { + #[yaserde(attribute)] + color: Color + } + + #[derive(YaSerialize, PartialEq, Debug)] + #[yaserde(root="color")] + pub enum Color { + #[yaserde(rename="pink")] + Pink, + } + + let model = XmlStruct{ + color: Color::Pink + }; + + let content = ""; + convert_and_validate!(model, content); +} diff --git a/yaserde_derive/src/de/expand_enum.rs b/yaserde_derive/src/de/expand_enum.rs index 8a4d0e1..c132ff0 100644 --- a/yaserde_derive/src/de/expand_enum.rs +++ b/yaserde_derive/src/de/expand_enum.rs @@ -19,11 +19,13 @@ pub fn parse(data_enum: &DataEnum, name: &Ident, root: &String) -> Tokens { match get_field_type(field) { Some(FieldType::FieldTypeString) => { Some(quote!{ + #[allow(unused_mut)] let mut #field_label : String = "".to_string(); }) }, Some(FieldType::FieldTypeStruct{struct_name}) => { Some(quote!{ + #[allow(unused_mut)] let mut #field_label : #struct_name = #struct_name::default(); }) }, @@ -32,11 +34,13 @@ pub fn parse(data_enum: &DataEnum, name: &Ident, root: &String) -> Tokens { match unsafe{dt.as_ref()} { Some(&FieldType::FieldTypeString) => { Some(quote!{ + #[allow(unused_mut)] let mut #field_label : Vec = vec![]; }) }, Some(&FieldType::FieldTypeStruct{struct_name}) => { Some(quote!{ + #[allow(unused_mut)] let mut #field_label : Vec<#struct_name> = vec![]; }) }, @@ -63,113 +67,43 @@ pub fn parse(data_enum: &DataEnum, name: &Ident, root: &String) -> Tokens { .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(); - + let enum_visitors: 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_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 label = field.ident; + // let label_name = label.unwrap().to_string(); + // let visitor_label = Ident::new(&format!("__Visitor{}", label_name), Span::call_site()); - 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; + // struct #visitor_label; + // impl<'de> Visitor<'de> for #visitor_label { + // type Value = String; - 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(); - } - }, - _ => {}, - } - } - }, + // fn visit_str(self, v: &str) -> Result { + // match v { + // _ => Err("unable to match \"{}\" with enum {}", v, #label_name) + // } + // Ok(String::from(v)) + // } + // } }) }, - data => { - println!("{:?}", data); - 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!();} + } + Fields::Unnamed(ref _fields) => { + unimplemented!(); + } } }) .filter(|x| x.is_some()) @@ -195,10 +129,7 @@ pub fn parse(data_enum: &DataEnum, name: &Ident, root: &String) -> Tokens { } }) }, - Fields::Named(ref _fields) => { - None - } - Fields::Unnamed(ref _fields) => { + _ => { None } } @@ -212,67 +143,54 @@ pub fn parse(data_enum: &DataEnum, name: &Ident, root: &String) -> Tokens { 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)] + fn deserialize(reader: &mut yaserde::de::Deserializer) -> Result { + let named_element = + if let XmlEvent::StartElement{name, ..} = reader.peek()?.to_owned() { + name.local_name.to_owned() + } else { + String::from(#root) + }; + debug!("Enum: start to parse {:?}", named_element); + + #[allow(unused_assignments, unused_mut)] let mut simple_enum_value = None; - println!("Enum: start to parse {}", #root); #variables + #enum_visitors 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); + match reader.peek()?.to_owned() { + XmlEvent::StartElement{name, attributes, namespace: _namespace} => { + debug!("Enum: {}: {}", named_element, name.local_name.as_str()); + if name.local_name == named_element { + let _next = reader.next(); - 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 - _ => {} + if let XmlEvent::Characters(content) = reader.peek()?.to_owned() { + match content.as_str() { + #match_to_enum + _ => {} + } } } }, - Ok(event) => { - println!("{:?}", event); + XmlEvent::EndElement{name} => { + if name.local_name.as_str() == named_element { + break; + } + let _root = reader.next(); }, - Err(_msg) => { - break; + 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 => { + return Err(format!("unknown event {:?}", event)) }, } } @@ -281,7 +199,6 @@ pub fn parse(data_enum: &DataEnum, name: &Ident, root: &String) -> Tokens { 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 6856abe..22961a6 100644 --- a/yaserde_derive/src/de/expand_struct.rs +++ b/yaserde_derive/src/de/expand_struct.rs @@ -7,17 +7,19 @@ use syn::DataStruct; use proc_macro2::Span; pub fn parse(data_struct: &DataStruct, name: &Ident, root: &String) -> Tokens { - let variables : Tokens = data_struct.fields.iter().map(|ref field| + let variables: Tokens = data_struct.fields.iter().map(|ref field| { 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::FieldTypeStruct{struct_name}) => { Some(quote!{ + #[allow(unused_mut, non_snake_case, non_camel_case_types)] let mut #label : #struct_name = #struct_name::default(); }) }, @@ -26,11 +28,13 @@ pub fn parse(data_struct: &DataStruct, name: &Ident, root: &String) -> Tokens { match unsafe{dt.as_ref()} { Some(&FieldType::FieldTypeString) => { Some(quote!{ + #[allow(unused_mut)] let mut #label : Vec = vec![]; }) }, Some(&FieldType::FieldTypeStruct{struct_name}) => { Some(quote!{ + #[allow(unused_mut)] let mut #label : Vec<#struct_name> = vec![]; }) }, @@ -45,114 +49,42 @@ pub fn parse(data_struct: &DataStruct, name: &Ident, root: &String) -> Tokens { .map(|x| x.unwrap()) .fold(Tokens::new(), |mut sum, val| {sum.append_all(val); sum}); - let attributes_loading: Tokens = data_struct.fields.iter().map(|ref field| - match get_field_type(field) { - Some(FieldType::FieldTypeString) => { - let label = field.ident; - let field_attrs = YaSerdeAttribute::parse(&field.attrs); - - match (field_attrs.attribute, field_attrs.rename) { - (true, Some(value)) => { - let label_name = Ident::new(&format!("{}", value), Span::call_site()).to_string(); - Some(quote!{ - match current_attributes { - Some(attributes) => - for attr in attributes { - if attr.name.local_name == #label_name { - #label = attr.value.to_owned(); - } - }, - None => {}, - } - }) - }, - (true, None) => { - let label_name = field.ident.unwrap().to_string(); - Some(quote!{ - match current_attributes { - Some(attributes) => - for attr in attributes { - if attr.name.local_name == #label_name { - #label = attr.value.to_owned(); - } - }, - None => {}, - } - }) - } - _ => None - } - } - _ => { - None - } - }) - .filter(|x| x.is_some()) - .map(|x| x.unwrap()) - .fold(Tokens::new(), |mut sum, val| {sum.append_all(val); sum}); - - let assign_text_field: Tokens = data_struct.fields.iter().map(|ref field| - match get_field_type(field) { - Some(FieldType::FieldTypeString) => { - let label = field.ident; - let field_attrs = YaSerdeAttribute::parse(&field.attrs); - - match field_attrs.text { - true => { - Some(quote!{ - #label = characters_content.to_owned(); - }) - }, - false => None - } - } - _ => { - None - } - }) - .filter(|x| x.is_some()) - .map(|x| x.unwrap()) - .fold(Tokens::new(), |mut sum, val| {sum.append_all(val); sum}); - - let fields : Tokens = data_struct.fields.iter().map(|ref field| + let field_visitors: Tokens = data_struct.fields.iter().map(|ref field| { - let field_attrs = YaSerdeAttribute::parse(&field.attrs); let label = field.ident; - let renamed_label = - match field_attrs.rename { - Some(value) => Some(Ident::new(&format!("{}", value), Span::call_site())), - None => field.ident - }; + let label_name = label.unwrap().to_string(); + let visitor_label = Ident::new(&format!("__Visitor{}", label_name), Span::call_site()); - let label_name = renamed_label.unwrap().to_string(); match get_field_type(field) { Some(FieldType::FieldTypeString) => { Some(quote!{ - #label_name => { - match read.next() { - Ok(xml::reader::XmlEvent::Characters(characters_content)) => { - #label = characters_content.trim().to_string(); - }, - _ => {}, + #[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)) } - }, + } }) }, Some(FieldType::FieldTypeStruct{struct_name}) => { - let struct_ident = Ident::new(&format!("{}", struct_name), Span::def_site()); + let struct_id = struct_name.to_string(); + let struct_ident = Ident::new(&format!("__Visitor_{}_{}", label_name, struct_name), Span::call_site()); Some(quote!{ - #label_name => { - match #struct_ident::derive_deserialize(read, Some(&attributes)) { - Ok(parsed_structure) => { - prev_level -= 1; - #label = parsed_structure; - }, - Err(msg) => { - return Err(msg); - }, + #[allow(non_snake_case, non_camel_case_types)] + struct #struct_ident; + impl<'de> Visitor<'de> for #struct_ident { + type Value = #struct_name; + + fn visit_str(self, v: &str) -> Result { + let content = "<".to_string() + #struct_id + ">" + v + ""; + let value : Result<#struct_name, String> = yaserde::de::from_str(&content); + value } - }, + } }) }, Some(FieldType::FieldTypeVec{data_type}) => { @@ -160,34 +92,30 @@ pub fn parse(data_struct: &DataStruct, name: &Ident, root: &String) -> Tokens { match unsafe{dt.as_ref()} { Some(&FieldType::FieldTypeString) => { Some(quote!{ - #label_name => { - match read.next() { - Ok(xml::reader::XmlEvent::Characters(characters_content)) => { - #label.push(characters_content.trim().to_string()); - }, - _ => {}, + #[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)) } - }, + } }) - }, + } Some(&FieldType::FieldTypeStruct{struct_name}) => { let struct_ident = Ident::new(&format!("{}", struct_name), Span::def_site()); Some(quote!{ - #label_name => { - match #struct_ident::derive_deserialize(read, Some(&attributes)) { - Ok(parsed_item) => { - prev_level -= 1; - #label.push(parsed_item); - }, - Err(msg) => { - return Err(msg); - }, - } - }, + #[allow(non_snake_case, non_camel_case_types)] + struct #visitor_label; + impl<'de> Visitor<'de> for #visitor_label { + type Value = #struct_ident; + } }) - }, - Some(&FieldType::FieldTypeVec{..}) => {unimplemented!();}, - None => {unimplemented!();}, + } + _ => { + None + } } }, _ => None @@ -197,7 +125,197 @@ pub fn parse(data_struct: &DataStruct, name: &Ident, root: &String) -> Tokens { .map(|x| x.unwrap()) .fold(Tokens::new(), |mut sum, val| {sum.append_all(val); sum}); - let struct_builder : Tokens = data_struct.fields.iter().map(|ref field| + let call_visitors: Tokens = data_struct.fields.iter().map(|ref field| + { + let field_attrs = YaSerdeAttribute::parse(&field.attrs); + let label = field.ident; + + if field_attrs.attribute { + return None; + } + + 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!{ + #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 + } + } + }) + }, + Some(FieldType::FieldTypeStruct{struct_name}) => { + Some(quote!{ + #label_name => { + reader.set_map_value(); + match #struct_name::deserialize(reader) { + Ok(parsed_item) => { + #label = parsed_item; + let _root = reader.next(); + }, + Err(msg) => { + return Err(msg); + }, + } + } + }) + }, + Some(FieldType::FieldTypeVec{data_type}) => { + 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) + } + } + }) + } + Some(&FieldType::FieldTypeStruct{struct_name}) => { + let struct_ident = Ident::new(&format!("{}", struct_name), Span::def_site()); + Some(quote!{ + #label_name => { + reader.set_map_value(); + match #struct_ident::deserialize(reader) { + Ok(parsed_item) => { + #label.push(parsed_item); + let _root = reader.next(); + }, + Err(msg) => { + return Err(msg); + }, + } + } + }) + } + _ => unimplemented!() + } + }, + _ => None + } + }) + .filter(|x| x.is_some()) + .map(|x| x.unwrap()) + .fold(Tokens::new(), |mut sum, val| {sum.append_all(val); sum}); + + let attributes_loading: Tokens = data_struct.fields.iter().map(|ref field| { + let field_attrs = YaSerdeAttribute::parse(&field.attrs); + if !field_attrs.attribute { + return None; + } + + 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() + } else { + field.ident.unwrap().to_string() + }; + + match get_field_type(field) { + Some(FieldType::FieldTypeString) => { + Some(quote!{ + for attr in attributes { + if attr.name.local_name == #label_name { + #label = attr.value.to_owned(); + } + } + }) + } + Some(FieldType::FieldTypeStruct{struct_name}) => { + let struct_ident = Ident::new(&format!("__Visitor_{}_{}", field_ident, struct_name), Span::call_site()); + + Some(quote!{ + for attr in attributes { + if attr.name.local_name == #label_name { + let visitor = #struct_ident{}; + match visitor.visit_str(&attr.value) { + Ok(value) => {#label = value;} + Err(msg) => {return Err(msg);} + } + } + } + }) + } + _ => { + None + } + }}) + .filter(|x| x.is_some()) + .map(|x| x.unwrap()) + .fold(Tokens::new(), |mut sum, val| {sum.append_all(val); sum}); + + let set_text: Tokens = data_struct.fields.iter().map(|ref field| + { + let label = field.ident; + 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::FieldTypeStruct{..}) | + Some(FieldType::FieldTypeVec{..})| + None => None, + } + }) + .filter(|x| x.is_some()) + .map(|x| x.unwrap()) + .fold(Tokens::new(), |mut tokens, token| {tokens.append_all(token); tokens}); + + let struct_builder: Tokens = data_struct.fields.iter().map(|ref field| { let label = field.ident; @@ -217,64 +335,52 @@ pub fn parse(data_struct: &DataStruct, name: &Ident, root: &String) -> Tokens { quote! { use xml::reader::XmlEvent; + use yaserde::Visitor; 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; - - println!("Struct: start to parse {}", #root); + fn deserialize(reader: &mut yaserde::de::Deserializer) -> Result { + let named_element = + if let XmlEvent::StartElement{name, ..} = reader.peek()?.to_owned() { + name.local_name.to_owned() + } else { + String::from(#root) + }; + debug!("Struct: start to parse {:?}", named_element); #variables - let current_attributes = parent_attributes; - #attributes_loading + #field_visitors loop { - match read.next() { - Ok(XmlEvent::StartDocument{..}) => { - }, - Ok(XmlEvent::EndDocument) => { - break; - }, - Ok(XmlEvent::StartElement{name, attributes, namespace: _namespace}) => { - println!("Struct: {} | {} - {}: {}", #root, prev_level, current_level, name.local_name.as_str()); - if prev_level == current_level { - match name.local_name.as_str() { - #root => { - let root_attributes = attributes.clone(); - let current_attributes = Some(&root_attributes); - #attributes_loading - - current_level += 1; - }, - #fields - _ => {} - }; + match reader.peek()?.to_owned() { + XmlEvent::StartElement{ref name, ref attributes, ..} => { + match name.local_name.as_str() { + #call_visitors + named_element => { + let _root = reader.next(); + } + // name => { + // return Err(format!("unknown key {}", name)) + // } } - - prev_level += 1; - }, - Ok(XmlEvent::EndElement{name}) => { - println!("Struct: end element {}", name); - if #root == name.local_name.as_str() { - println!("Struct: break for {}", #root); + #attributes_loading + } + XmlEvent::EndElement{ref name} => { + if name.local_name == named_element { break; } - prev_level -= 1; + let _root = reader.next(); + } + XmlEvent::Characters(ref text_content) => { + #set_text + let _root = reader.next(); + } + event => { + return Err(format!("unknown event {:?}", event)) } - Ok(xml::reader::XmlEvent::Characters(characters_content)) => { - if prev_level == current_level { - #assign_text_field - } - }, - Ok(_event) => { - }, - Err(_msg) => { - break; - }, } } + Ok(#name{#struct_builder}) } } diff --git a/yaserde_derive/src/field_type.rs b/yaserde_derive/src/field_type.rs index 5b9601c..a7d279c 100644 --- a/yaserde_derive/src/field_type.rs +++ b/yaserde_derive/src/field_type.rs @@ -51,30 +51,17 @@ pub fn get_field_type(field: &syn::Field) -> Option { } fn get_vec_type(t: &syn::PathSegment) -> Option { - match t.arguments { - syn::PathArguments::AngleBracketed(ref args) => { - match args.args.first() { - Some(Pair::End(tt)) => { - match tt { - &syn::GenericArgument::Type(ref argument) => { - match argument { - &Path(ref path2) => { - match path2.path.segments.first() { - Some(Pair::End(ttt)) => { - Some(ttt.ident) - }, - _ => None - } - }, - _ => None - } - }, - _ => None + if let syn::PathArguments::AngleBracketed(ref args) = t.arguments { + if let Some(Pair::End(tt)) = args.args.first() { + if let &syn::GenericArgument::Type(ref argument) = tt { + if let &Path(ref path2) = argument { + if let Some(Pair::End(ttt)) = path2.path.segments.first() { + return Some(ttt.ident) } - }, - _ => None + } } - }, - _ => None + } } + + None } diff --git a/yaserde_derive/src/ser/expand_enum.rs b/yaserde_derive/src/ser/expand_enum.rs index 55978a7..cc57078 100644 --- a/yaserde_derive/src/ser/expand_enum.rs +++ b/yaserde_derive/src/ser/expand_enum.rs @@ -75,11 +75,9 @@ pub fn serialize(data_enum: &DataEnum, name: &Ident, root: &String) -> Tokens { match self { &#name::#label{ref #field_label, ..} => { - match #field_label.derive_serialize(writer, true) { - Ok(()) => {}, - Err(msg) => { - return Err(msg); - }, + writer.set_skip_start_end(true); + if let Err(msg) = #field_label.serialize(writer) { + return Err(msg); }; }, _ => {} @@ -96,11 +94,9 @@ pub fn serialize(data_enum: &DataEnum, name: &Ident, root: &String) -> Tokens { 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); - }, + writer.set_skip_start_end(true); + if let Err(msg) = item.serialize(writer) { + return Err(msg); }; let struct_end_event = XmlEvent::end_element(); let _ret = writer.write(struct_end_event); @@ -142,8 +138,10 @@ pub fn serialize(data_enum: &DataEnum, name: &Ident, root: &String) -> Tokens { impl YaSerialize for #name { #[allow(unused_variables)] - fn derive_serialize(&self, writer: &mut xml::EventWriter, skip_start_end: bool) -> Result<(), String> { - if !skip_start_end { + fn serialize(&self, writer: &mut yaserde::ser::Serializer) -> Result<(), String> { + error!("Enum: start to expand {:?}", #root); + + if !writer.skip_start_end() { let struct_start_event = XmlEvent::start_element(#root); let _ret = writer.write(struct_start_event); } @@ -152,10 +150,11 @@ pub fn serialize(data_enum: &DataEnum, name: &Ident, root: &String) -> Tokens { #write_enum_content } - if !skip_start_end { + if !writer.skip_start_end() { let struct_end_event = XmlEvent::end_element(); let _ret = writer.write(struct_end_event); } + writer.set_skip_start_end(false); Ok(()) } } diff --git a/yaserde_derive/src/ser/expand_struct.rs b/yaserde_derive/src/ser/expand_struct.rs index f4e2f6c..c2136b2 100644 --- a/yaserde_derive/src/ser/expand_struct.rs +++ b/yaserde_derive/src/ser/expand_struct.rs @@ -5,6 +5,7 @@ use quote::Tokens; use syn::Ident; use syn::DataStruct; use proc_macro2::Span; +use std::string::ToString; pub fn serialize(data_struct: &DataStruct, name: &Ident, root: &String) -> Tokens { let build_attributes : Tokens = data_struct.fields.iter().map(|ref field| @@ -27,7 +28,25 @@ pub fn serialize(data_struct: &DataStruct, name: &Ident, root: &String) -> Token Some(quote!{ .attr(#label_name, &self.#label) }), - _ => None + Some(FieldType::FieldTypeStruct{struct_name: _struct_name}) => + Some(quote!{ + .attr(#label_name, &*{ + use std::mem; + match yaserde::ser::to_string_content(&self.#label) { + Ok(value) => { + unsafe { + let ret : &'static str = mem::transmute(&value as &str); + mem::forget(value); + ret + } + }, + Err(msg) => return Err("Unable to serialize content".to_owned()), + } + }) + }), + _ => { + None + } } }) .filter(|x| x.is_some()) @@ -68,7 +87,8 @@ pub fn serialize(data_struct: &DataStruct, name: &Ident, root: &String) -> Token }), Some(FieldType::FieldTypeStruct{..}) => Some(quote!{ - match self.#label.derive_serialize(writer, false) { + writer.set_skip_start_end(false); + match self.#label.serialize(writer) { Ok(()) => {}, Err(msg) => { return Err(msg); @@ -95,7 +115,8 @@ 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, false) { + writer.set_skip_start_end(false); + match item.serialize(writer) { Ok(()) => {}, Err(msg) => { return Err(msg); @@ -122,15 +143,17 @@ 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, skip_start_end: bool) -> Result<(), String> { - if !skip_start_end { + fn serialize(&self, writer: &mut yaserde::ser::Serializer) -> Result<(), String> { + error!("Struct: start to expand {:?}", #root); + + if !writer.skip_start_end() { let struct_start_event = XmlEvent::start_element(#root)#build_attributes; let _ret = writer.write(struct_start_event); } #struct_inspector - if !skip_start_end { + if !writer.skip_start_end() { let struct_end_event = XmlEvent::end_element(); let _ret = writer.write(struct_end_event); } diff --git a/yaserde_derive/src/ser/mod.rs b/yaserde_derive/src/ser/mod.rs index 8d4e9b8..f21ed76 100644 --- a/yaserde_derive/src/ser/mod.rs +++ b/yaserde_derive/src/ser/mod.rs @@ -3,7 +3,6 @@ pub mod expand_enum; pub mod expand_struct; use attribute; - use proc_macro2::Span; use quote; use syn;