start to deserialize enum

This commit is contained in:
Marc-Antoine Arnaud 2018-04-29 15:16:28 +02:00
parent 5c3910c420
commit 6adbd71ebb
9 changed files with 395 additions and 28 deletions

View File

@ -14,5 +14,5 @@ pub trait YaDeserialize : Sized {
}
pub trait YaSerialize : Sized {
fn derive_serialize<W: Write>(&self, read: &mut EventWriter<W>) -> Result<(), String>;
fn derive_serialize<W: Write>(&self, read: &mut EventWriter<W>, skip_start_end: bool) -> Result<(), String>;
}

View File

@ -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 = "<?xml version=\"1.0\" encoding=\"utf-8\"?><base><background>Black</background></base>";
convert_and_validate!(content, XmlStruct, XmlStruct{
background: Color::Black
});
}

View File

@ -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 = "<?xml version=\"1.0\" encoding=\"utf-8\"?><base><color><custom><enabled>true</enabled><RGBColor><red>0</red><green>128</green><blue>255</blue></RGBColor><Alpha>Opaque</Alpha><Alpha>Opaque</Alpha><Alpha>Transparent</Alpha></custom></color></base>";
let content = "<?xml version=\"1.0\" encoding=\"utf-8\"?><base><color><custom><enabled>true</enabled><color><red>0</red><green>128</green><blue>255</blue></color><alpha>Opaque</alpha><alphas>Opaque</alphas><alphas>Transparent</alphas></custom></color></base>";
convert_and_validate!(model, content);
}

View File

@ -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<String> = 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<R: Read>(read: &mut xml::EventReader<R>, parent_attributes: Option<&Vec<xml::attribute::OwnedAttribute>>) -> Result<Self, String> {
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())
},
}
}
}
}
}

View File

@ -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;

View File

@ -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<quote::Tokens
&syn::Data::Struct(ref data_struct) => {
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!()

View File

@ -1,4 +1,4 @@
#![recursion_limit="128"]
#![recursion_limit="256"]
extern crate proc_macro;
extern crate proc_macro2;

View File

@ -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<W: Write>(&self, writer: &mut xml::EventWriter<W>) -> Result<(), String> {
let struct_start_event = XmlEvent::start_element(#root);
let _ret = writer.write(struct_start_event);
fn derive_serialize<W: Write>(&self, writer: &mut xml::EventWriter<W>, 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(())
}
}

View File

@ -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<W: Write>(&self, writer: &mut xml::EventWriter<W>) -> Result<(), String> {
let struct_start_event = XmlEvent::start_element(#root)#build_attributes;
let _ret = writer.write(struct_start_event);
fn derive_serialize<W: Write>(&self, writer: &mut xml::EventWriter<W>, 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(())
}
}