support flatten attributes

This commit is contained in:
Marc-Antoine Arnaud
2020-06-07 15:16:46 +02:00
parent 429c2db493
commit 7569408245
9 changed files with 272 additions and 129 deletions

View File

@@ -1,5 +1,5 @@
use crate::common::{Field, YaSerdeAttribute, YaSerdeField};
use crate::ser::{implement_deserializer::implement_deserializer, label::build_label_name};
use crate::ser::{implement_serializer::implement_serializer, label::build_label_name};
use proc_macro2::TokenStream;
use syn::DataEnum;
use syn::Fields;
@@ -13,7 +13,7 @@ pub fn serialize(
) -> TokenStream {
let inner_enum_inspector = inner_enum_inspector(data_enum, name, root_attributes);
implement_deserializer(
implement_serializer(
name,
root,
root_attributes,

View File

@@ -1,6 +1,6 @@
use crate::common::{Field, YaSerdeAttribute, YaSerdeField};
use crate::ser::{element::*, implement_deserializer::implement_deserializer};
use crate::ser::{element::*, implement_serializer::implement_serializer};
use proc_macro2::TokenStream;
use syn::DataStruct;
use syn::Ident;
@@ -11,45 +11,20 @@ pub fn serialize(
root: &str,
root_attributes: &YaSerdeAttribute,
) -> TokenStream {
let build_attributes: TokenStream = data_struct
let append_attributes: TokenStream = data_struct
.fields
.iter()
.map(|field| YaSerdeField::new(field.clone()))
.filter(|field| field.is_attribute())
.filter(|field| field.is_attribute() || field.is_flatten())
.map(|field| {
let label = field.label();
let label_name = field.renamed_label(root_attributes);
match field.get_type() {
Field::FieldString
| Field::FieldBool
| Field::FieldI8
| Field::FieldU8
| Field::FieldI16
| Field::FieldU16
| Field::FieldI32
| Field::FieldU32
| Field::FieldI64
| Field::FieldU64
| Field::FieldF32
| Field::FieldF64 => Some(field.ser_wrap_default_attribute(
Some(quote!(self.#label.to_string())),
quote!({
struct_start_event.attr(#label_name, &yaserde_inner)
}),
)),
Field::FieldOption { data_type } => match *data_type {
Field::FieldString => Some(field.ser_wrap_default_attribute(
None,
quote!({
if let Some(ref value) = self.#label {
struct_start_event.attr(#label_name, value)
} else {
struct_start_event
}
}),
)),
Field::FieldBool
if field.is_attribute() {
let label_name = field.renamed_label(root_attributes);
match field.get_type() {
Field::FieldString
| Field::FieldBool
| Field::FieldI8
| Field::FieldU8
| Field::FieldI16
@@ -59,55 +34,96 @@ pub fn serialize(
| Field::FieldI64
| Field::FieldU64
| Field::FieldF32
| Field::FieldF64 => Some(field.ser_wrap_default_attribute(
Some(quote!(self.#label.map_or_else(|| String::new(), |v| v.to_string()))),
| Field::FieldF64 => field.ser_wrap_default_attribute(
Some(quote!(self.#label.to_string())),
quote!({
if let Some(ref value) = self.#label {
struct_start_event.attr(#label_name, &yaserde_inner)
} else {
struct_start_event
}
struct_start_event.attr(#label_name, &yaserde_inner)
}),
)),
Field::FieldVec { .. } => {
let item_ident = Ident::new("yaserde_item", field.get_span());
let inner = enclose_formatted_characters(&item_ident, label_name);
Some(field.ser_wrap_default_attribute(
),
Field::FieldOption { data_type } => match *data_type {
Field::FieldString => field.ser_wrap_default_attribute(
None,
quote!({
if let Some(ref yaserde_list) = self.#label {
for yaserde_item in yaserde_list.iter() {
#inner
}
if let Some(ref value) = self.#label {
struct_start_event.attr(#label_name, value)
} else {
struct_start_event
}
}),
))
}
Field::FieldStruct { .. } => Some(field.ser_wrap_default_attribute(
Some(quote!(self.#label
.as_ref()
.map_or_else(|| Ok(String::new()), |v| yaserde::ser::to_string_content(v))?)),
),
Field::FieldBool
| Field::FieldI8
| Field::FieldU8
| Field::FieldI16
| Field::FieldU16
| Field::FieldI32
| Field::FieldU32
| Field::FieldI64
| Field::FieldU64
| Field::FieldF32
| Field::FieldF64 => field.ser_wrap_default_attribute(
Some(quote!(self.#label.map_or_else(|| String::new(), |v| v.to_string()))),
quote!({
if let Some(ref value) = self.#label {
struct_start_event.attr(#label_name, &yaserde_inner)
} else {
struct_start_event
}
}),
),
Field::FieldVec { .. } => {
let item_ident = Ident::new("yaserde_item", field.get_span());
let inner = enclose_formatted_characters(&item_ident, label_name);
field.ser_wrap_default_attribute(
None,
quote!({
if let Some(ref yaserde_list) = self.#label {
for yaserde_item in yaserde_list.iter() {
#inner
}
}
}),
)
}
Field::FieldStruct { .. } => field.ser_wrap_default_attribute(
Some(quote!(self.#label
.as_ref()
.map_or_else(|| Ok(String::new()), |v| yaserde::ser::to_string_content(v))?)),
quote!({
if let Some(ref yaserde_struct) = self.#label {
struct_start_event.attr(#label_name, &yaserde_inner)
} else {
struct_start_event
}
}),
),
Field::FieldOption { .. } => unimplemented!(),
},
Field::FieldStruct { .. } => field.ser_wrap_default_attribute(
Some(quote!(yaserde::ser::to_string_content(&self.#label)?)),
quote!({
if let Some(ref yaserde_struct) = self.#label {
struct_start_event.attr(#label_name, &yaserde_inner)
} else {
struct_start_event
}
struct_start_event.attr(#label_name, &yaserde_inner)
}),
)),
Field::FieldOption { .. } => unimplemented!(),
},
Field::FieldStruct { .. } => Some(field.ser_wrap_default_attribute(
Some(quote!(yaserde::ser::to_string_content(&self.#label)?)),
quote!({
struct_start_event.attr(#label_name, &yaserde_inner)
}),
)),
Field::FieldVec { .. } => None,
),
Field::FieldVec { .. } => {
// TODO
quote!()
}
}
} else {
match field.get_type() {
Field::FieldStruct { .. } => {
quote!(
let (attributes, namespace) = self.#label.serialize_attributes(vec![], xml::namespace::Namespace::empty())?;
child_attributes_namespace.extend(&namespace);
child_attributes.extend(attributes);
)
}
_ => quote!()
}
}
})
.filter_map(|x| x)
.collect();
let struct_inspector: TokenStream = data_struct
@@ -267,11 +283,11 @@ pub fn serialize(
.filter_map(|x| x)
.collect();
implement_deserializer(
implement_serializer(
name,
root,
root_attributes,
build_attributes,
append_attributes,
struct_inspector,
)
}

View File

@@ -1,43 +0,0 @@
use crate::common::YaSerdeAttribute;
use crate::ser::namespace::generate_namespaces_definition;
use proc_macro2::Ident;
use proc_macro2::TokenStream;
pub fn implement_deserializer(
name: &Ident,
root: &str,
attributes: &YaSerdeAttribute,
attributes_inspector: TokenStream,
inner_inspector: TokenStream,
) -> TokenStream {
let namespaces_definition = generate_namespaces_definition(attributes);
let flatten = attributes.flatten;
quote! {
use xml::writer::XmlEvent;
impl YaSerialize for #name {
#[allow(unused_variables)]
fn serialize<W: Write>(&self, writer: &mut yaserde::ser::Serializer<W>)
-> Result<(), String> {
let skip = writer.skip_start_end();
if !#flatten && !skip {
let yaserde_label = writer.get_start_event_name().unwrap_or_else(|| #root.to_string());
let struct_start_event = XmlEvent::start_element(yaserde_label.as_ref())#namespaces_definition;
#attributes_inspector
writer.write(struct_start_event).map_err(|e| e.to_string())?;
}
#inner_inspector
if !#flatten && !skip {
let struct_end_event = XmlEvent::end_element();
writer.write(struct_end_event).map_err(|e| e.to_string())?;
}
Ok(())
}
}
}
}

View File

@@ -0,0 +1,87 @@
use crate::common::YaSerdeAttribute;
use crate::ser::namespace::generate_namespaces_definition;
use proc_macro2::Ident;
use proc_macro2::TokenStream;
pub fn implement_serializer(
name: &Ident,
root: &str,
attributes: &YaSerdeAttribute,
append_attributes: TokenStream,
inner_inspector: TokenStream,
) -> TokenStream {
let namespaces_definition = generate_namespaces_definition(attributes);
let flatten = attributes.flatten;
quote! {
use xml::writer::XmlEvent;
impl<'a> YaSerialize<'a> for #name {
#[allow(unused_variables)]
fn serialize<W: Write>(&self, writer: &mut yaserde::ser::Serializer<W>)
-> Result<(), String> {
let skip = writer.skip_start_end();
if !#flatten && !skip {
let mut child_attributes = vec![];
let mut child_attributes_namespace = xml::namespace::Namespace::empty();
let yaserde_label = writer.get_start_event_name().unwrap_or_else(|| #root.to_string());
let struct_start_event = XmlEvent::start_element(yaserde_label.as_ref())#namespaces_definition;
#append_attributes
let event : xml::writer::events::XmlEvent = struct_start_event.into();
if let xml::writer::events::XmlEvent::StartElement{name, attributes, namespace} = event {
let mut attributes: Vec<xml::attribute::OwnedAttribute> = attributes.into_owned().to_vec().iter().map(|k| k.to_owned()).collect();
attributes.extend(child_attributes);
let all_attributes = attributes.iter().map(|ca| ca.borrow()).collect();
let mut all_namespaces = namespace.into_owned();
all_namespaces.extend(&child_attributes_namespace);
writer.write(xml::writer::events::XmlEvent::StartElement{
name,
attributes: std::borrow::Cow::Owned(all_attributes),
namespace: std::borrow::Cow::Owned(all_namespaces)
}).map_err(|e| e.to_string())?;
} else {
unreachable!()
}
}
#inner_inspector
if !#flatten && !skip {
let struct_end_event = XmlEvent::end_element();
writer.write(struct_end_event).map_err(|e| e.to_string())?;
}
Ok(())
}
fn serialize_attributes(&self, mut source_attributes: Vec<xml::attribute::OwnedAttribute>, mut source_namespace: xml::namespace::Namespace) -> Result<(Vec<xml::attribute::OwnedAttribute>, xml::namespace::Namespace), String> {
let mut child_attributes : Vec<xml::attribute::OwnedAttribute> = vec![];
let mut child_attributes_namespace = xml::namespace::Namespace::empty();
let struct_start_event = XmlEvent::start_element("temporary_element_to_generate_attributes")#namespaces_definition;
#append_attributes
let event : xml::writer::events::XmlEvent = struct_start_event.into();
if let xml::writer::events::XmlEvent::StartElement{attributes, namespace, ..} = event {
source_namespace.extend(&namespace.into_owned());
source_namespace.extend(&child_attributes_namespace);
let a: Vec<xml::attribute::OwnedAttribute> = attributes.into_owned().to_vec().iter().map(|k| k.to_owned()).collect();
source_attributes.extend(a);
source_attributes.extend(child_attributes);
Ok((source_attributes, source_namespace))
} else {
unreachable!();
}
}
}
}
}

View File

@@ -1,7 +1,7 @@
pub mod element;
pub mod expand_enum;
pub mod expand_struct;
pub mod implement_deserializer;
pub mod implement_serializer;
pub mod label;
pub mod namespace;