add flatten support for root elements (Enum and Structs)
This commit is contained in:
parent
38e5d32b7e
commit
7b53515736
68
yaserde/tests/ser_flatten.rs
Normal file
68
yaserde/tests/ser_flatten.rs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#[macro_use]
|
||||||
|
extern crate yaserde_derive;
|
||||||
|
|
||||||
|
use std::io::Write;
|
||||||
|
use yaserde::ser::to_string;
|
||||||
|
use yaserde::YaSerialize;
|
||||||
|
|
||||||
|
macro_rules! convert_and_validate {
|
||||||
|
($model: expr, $content: expr) => {
|
||||||
|
let data: Result<String, String> = to_string(&$model);
|
||||||
|
assert_eq!(
|
||||||
|
data,
|
||||||
|
Ok(
|
||||||
|
String::from($content)
|
||||||
|
.split("\n")
|
||||||
|
.map(|s| s.trim())
|
||||||
|
.collect::<String>()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ser_root_flatten_struct() {
|
||||||
|
|
||||||
|
#[derive(YaSerialize, PartialEq, Debug)]
|
||||||
|
#[yaserde(flatten)]
|
||||||
|
pub struct Content {
|
||||||
|
binary_data: String,
|
||||||
|
string_data: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
let model = Content{
|
||||||
|
binary_data: "binary".to_string(),
|
||||||
|
string_data: "string".to_string(),
|
||||||
|
};
|
||||||
|
let content = r#"<?xml version="1.0" encoding="utf-8"?><binary_data>binary</binary_data><string_data>string</string_data>"#;
|
||||||
|
convert_and_validate!(model, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ser_root_flatten_enum() {
|
||||||
|
#[derive(YaSerialize, PartialEq, Debug)]
|
||||||
|
#[yaserde(flatten)]
|
||||||
|
pub enum Content {
|
||||||
|
Binary(Binary),
|
||||||
|
Data(Data),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(YaSerialize, PartialEq, Debug)]
|
||||||
|
pub struct Binary {
|
||||||
|
binary_data: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(YaSerialize, PartialEq, Debug)]
|
||||||
|
pub struct Data {
|
||||||
|
string_data: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
let model = Content::Binary(Binary{binary_data: "binary".to_string()});
|
||||||
|
let content = r#"<?xml version="1.0" encoding="utf-8"?><Binary><binary_data>binary</binary_data></Binary>"#;
|
||||||
|
convert_and_validate!(model, content);
|
||||||
|
|
||||||
|
|
||||||
|
let model = Content::Data(Data{string_data: "string".to_string()});
|
||||||
|
let content = r#"<?xml version="1.0" encoding="utf-8"?><Data><string_data>string</string_data></Data>"#;
|
||||||
|
convert_and_validate!(model, content);
|
||||||
|
}
|
||||||
@ -1,7 +1,6 @@
|
|||||||
use crate::attribute::*;
|
use crate::attribute::*;
|
||||||
use crate::field_type::*;
|
use crate::field_type::*;
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use std::collections::BTreeMap;
|
|
||||||
use syn::spanned::Spanned;
|
use syn::spanned::Spanned;
|
||||||
use syn::DataEnum;
|
use syn::DataEnum;
|
||||||
use syn::Fields;
|
use syn::Fields;
|
||||||
@ -11,8 +10,7 @@ pub fn serialize(
|
|||||||
data_enum: &DataEnum,
|
data_enum: &DataEnum,
|
||||||
name: &Ident,
|
name: &Ident,
|
||||||
root: &str,
|
root: &str,
|
||||||
namespaces: &BTreeMap<String, String>,
|
root_attributes: &YaSerdeAttribute,
|
||||||
default_namespace: &Option<String>,
|
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
let write_enum_content: TokenStream = data_enum
|
let write_enum_content: TokenStream = data_enum
|
||||||
.variants
|
.variants
|
||||||
@ -224,10 +222,10 @@ pub fn serialize(
|
|||||||
.filter_map(|x| x)
|
.filter_map(|x| x)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let add_namespaces: TokenStream = namespaces
|
let add_namespaces: TokenStream = root_attributes.namespaces
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(prefix, namespace)| {
|
.map(|(prefix, namespace)| {
|
||||||
if let Some(dn) = default_namespace {
|
if let Some(dn) = &root_attributes.default_namespace {
|
||||||
if dn == prefix {
|
if dn == prefix {
|
||||||
return Some(quote!(
|
return Some(quote!(
|
||||||
.default_ns(#namespace)
|
.default_ns(#namespace)
|
||||||
@ -241,6 +239,8 @@ pub fn serialize(
|
|||||||
.filter_map(|x| x)
|
.filter_map(|x| x)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
let flatten = root_attributes.flatten;
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
use xml::writer::XmlEvent;
|
use xml::writer::XmlEvent;
|
||||||
|
|
||||||
@ -250,7 +250,7 @@ pub fn serialize(
|
|||||||
-> Result<(), String> {
|
-> Result<(), String> {
|
||||||
let skip = writer.skip_start_end();
|
let skip = writer.skip_start_end();
|
||||||
|
|
||||||
if !skip {
|
if !#flatten && !skip {
|
||||||
if let Some(label) = writer.get_start_event_name() {
|
if let Some(label) = writer.get_start_event_name() {
|
||||||
let struct_start_event = XmlEvent::start_element(label.as_ref());
|
let struct_start_event = XmlEvent::start_element(label.as_ref());
|
||||||
writer.write(struct_start_event).map_err(|e| e.to_string())?;
|
writer.write(struct_start_event).map_err(|e| e.to_string())?;
|
||||||
@ -264,7 +264,7 @@ pub fn serialize(
|
|||||||
#write_enum_content
|
#write_enum_content
|
||||||
}
|
}
|
||||||
|
|
||||||
if !skip {
|
if !#flatten && !skip {
|
||||||
let struct_end_event = XmlEvent::end_element();
|
let struct_end_event = XmlEvent::end_element();
|
||||||
writer.write(struct_end_event).map_err(|e| e.to_string())?;
|
writer.write(struct_end_event).map_err(|e| e.to_string())?;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,6 @@ use crate::attribute::*;
|
|||||||
use crate::field_type::*;
|
use crate::field_type::*;
|
||||||
use crate::ser::element::*;
|
use crate::ser::element::*;
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use std::collections::BTreeMap;
|
|
||||||
use std::string::ToString;
|
use std::string::ToString;
|
||||||
use syn::spanned::Spanned;
|
use syn::spanned::Spanned;
|
||||||
use syn::DataStruct;
|
use syn::DataStruct;
|
||||||
@ -12,8 +11,7 @@ pub fn serialize(
|
|||||||
data_struct: &DataStruct,
|
data_struct: &DataStruct,
|
||||||
name: &Ident,
|
name: &Ident,
|
||||||
root: &str,
|
root: &str,
|
||||||
namespaces: &BTreeMap<String, String>,
|
root_attributes: &YaSerdeAttribute,
|
||||||
default_namespace: &Option<String>,
|
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
let build_attributes: TokenStream = data_struct
|
let build_attributes: TokenStream = data_struct
|
||||||
.fields
|
.fields
|
||||||
@ -26,7 +24,7 @@ pub fn serialize(
|
|||||||
|
|
||||||
let label = &field.ident;
|
let label = &field.ident;
|
||||||
|
|
||||||
let label_name = build_label_name(&field, &field_attrs, default_namespace);
|
let label_name = build_label_name(&field, &field_attrs, &root_attributes.default_namespace);
|
||||||
|
|
||||||
get_field_type(field).and_then(|f| match f {
|
get_field_type(field).and_then(|f| match f {
|
||||||
FieldType::FieldTypeString
|
FieldType::FieldTypeString
|
||||||
@ -205,10 +203,10 @@ pub fn serialize(
|
|||||||
.filter_map(|x| x)
|
.filter_map(|x| x)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let add_namespaces: TokenStream = namespaces
|
let add_namespaces: TokenStream = root_attributes.namespaces
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(prefix, namespace)| {
|
.map(|(prefix, namespace)| {
|
||||||
if let Some(dn) = default_namespace {
|
if let Some(dn) = &root_attributes.default_namespace {
|
||||||
if dn == prefix {
|
if dn == prefix {
|
||||||
return Some(quote!(
|
return Some(quote!(
|
||||||
.default_ns(#namespace)
|
.default_ns(#namespace)
|
||||||
@ -239,7 +237,7 @@ pub fn serialize(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let label_name = build_label_name(&field, &field_attrs, default_namespace);
|
let label_name = build_label_name(&field, &field_attrs, &root_attributes.default_namespace);
|
||||||
let conditions = condition_generator(label, &field_attrs);
|
let conditions = condition_generator(label, &field_attrs);
|
||||||
|
|
||||||
get_field_type(field).and_then(|f| match f {
|
get_field_type(field).and_then(|f| match f {
|
||||||
@ -381,6 +379,8 @@ pub fn serialize(
|
|||||||
.filter_map(|x| x)
|
.filter_map(|x| x)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
let flatten = root_attributes.flatten;
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
use xml::writer::XmlEvent;
|
use xml::writer::XmlEvent;
|
||||||
|
|
||||||
@ -390,7 +390,7 @@ pub fn serialize(
|
|||||||
-> Result<(), String> {
|
-> Result<(), String> {
|
||||||
let skip = writer.skip_start_end();
|
let skip = writer.skip_start_end();
|
||||||
|
|
||||||
if !skip {
|
if !#flatten && !skip {
|
||||||
let yaserde_label = writer.get_start_event_name().unwrap_or_else(|| #root.to_string());
|
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())#add_namespaces;
|
let struct_start_event = XmlEvent::start_element(yaserde_label.as_ref())#add_namespaces;
|
||||||
#build_attributes
|
#build_attributes
|
||||||
@ -399,7 +399,7 @@ pub fn serialize(
|
|||||||
|
|
||||||
#struct_inspector
|
#struct_inspector
|
||||||
|
|
||||||
if !skip {
|
if !#flatten && !skip {
|
||||||
let struct_end_event = XmlEvent::end_element();
|
let struct_end_event = XmlEvent::end_element();
|
||||||
writer.write(struct_end_event).map_err(|e| e.to_string())?;
|
writer.write(struct_end_event).map_err(|e| e.to_string())?;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@ pub mod element;
|
|||||||
pub mod expand_enum;
|
pub mod expand_enum;
|
||||||
pub mod expand_struct;
|
pub mod expand_struct;
|
||||||
|
|
||||||
use crate::attribute;
|
use crate::attribute::YaSerdeAttribute;
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use syn;
|
use syn;
|
||||||
use syn::Ident;
|
use syn::Ident;
|
||||||
@ -12,13 +12,13 @@ pub fn expand_derive_serialize(ast: &syn::DeriveInput) -> Result<TokenStream, St
|
|||||||
let attrs = &ast.attrs;
|
let attrs = &ast.attrs;
|
||||||
let data = &ast.data;
|
let data = &ast.data;
|
||||||
|
|
||||||
let root_attrs = attribute::YaSerdeAttribute::parse(attrs);
|
let root_attrs = YaSerdeAttribute::parse(attrs);
|
||||||
let root = root_attrs.clone().root.unwrap_or_else(|| name.to_string());
|
let root = root_attrs.clone().root.unwrap_or_else(|| name.to_string());
|
||||||
|
|
||||||
let prefix = if root_attrs.default_namespace == root_attrs.prefix {
|
let prefix = if root_attrs.default_namespace == root_attrs.prefix {
|
||||||
"".to_string()
|
"".to_string()
|
||||||
} else {
|
} else {
|
||||||
root_attrs
|
root_attrs.clone()
|
||||||
.prefix
|
.prefix
|
||||||
.map_or("".to_string(), |prefix| prefix + ":")
|
.map_or("".to_string(), |prefix| prefix + ":")
|
||||||
};
|
};
|
||||||
@ -30,15 +30,13 @@ pub fn expand_derive_serialize(ast: &syn::DeriveInput) -> Result<TokenStream, St
|
|||||||
data_struct,
|
data_struct,
|
||||||
name,
|
name,
|
||||||
&root,
|
&root,
|
||||||
&root_attrs.namespaces,
|
&root_attrs,
|
||||||
&root_attrs.default_namespace,
|
|
||||||
),
|
),
|
||||||
syn::Data::Enum(ref data_enum) => expand_enum::serialize(
|
syn::Data::Enum(ref data_enum) => expand_enum::serialize(
|
||||||
data_enum,
|
data_enum,
|
||||||
name,
|
name,
|
||||||
&root,
|
&root,
|
||||||
&root_attrs.namespaces,
|
&root_attrs,
|
||||||
&root_attrs.default_namespace,
|
|
||||||
),
|
),
|
||||||
syn::Data::Union(ref _data_union) => unimplemented!(),
|
syn::Data::Union(ref _data_union) => unimplemented!(),
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user