parent
1a67c4907d
commit
4e03b57723
@ -183,7 +183,7 @@ fn ser_struct_default_namespace_via_attribute() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn de_struct_namespace_nested() {
|
||||
fn ser_struct_namespace_nested() {
|
||||
#[derive(YaSerialize, Default, PartialEq, Debug)]
|
||||
#[yaserde(prefix = "nsa", namespace = "nsa: http://www.sample.com/ns/a")]
|
||||
struct A {
|
||||
|
||||
68
yaserde/tests/ser_skip.rs
Normal file
68
yaserde/tests/ser_skip.rs
Normal file
@ -0,0 +1,68 @@
|
||||
extern crate log;
|
||||
extern crate xml;
|
||||
extern crate yaserde;
|
||||
#[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_skip_serializing_if_for_struct() {
|
||||
#[derive(YaSerialize, PartialEq, Debug)]
|
||||
#[yaserde(root = "base")]
|
||||
pub struct XmlStruct {
|
||||
#[yaserde(skip_serializing_if = "check_string_function")]
|
||||
string_item: String,
|
||||
#[yaserde(skip_serializing_if = "check_bool_function")]
|
||||
bool_item: bool,
|
||||
#[yaserde(skip_serializing_if = "check_f32_function")]
|
||||
f32_item: f32,
|
||||
#[yaserde(skip_serializing_if = "check_option_string_function")]
|
||||
option_string_item: Option<String>,
|
||||
}
|
||||
|
||||
impl XmlStruct {
|
||||
fn check_string_function(&self, value: &String) -> bool {
|
||||
value == "something"
|
||||
}
|
||||
|
||||
fn check_option_string_function(&self, value: &Option<String>) -> bool {
|
||||
value == &Some("something".to_string())
|
||||
}
|
||||
|
||||
fn check_bool_function(&self, value: &bool) -> bool {
|
||||
value == &true
|
||||
}
|
||||
|
||||
fn check_f32_function(&self, value: &f32) -> bool {
|
||||
value == &0.0
|
||||
}
|
||||
}
|
||||
|
||||
let model = XmlStruct {
|
||||
string_item: "something".to_string(),
|
||||
bool_item: true,
|
||||
f32_item: 0.0,
|
||||
option_string_item: Some("something".to_string()),
|
||||
};
|
||||
|
||||
let content = "<?xml version=\"1.0\" encoding=\"utf-8\"?><base />";
|
||||
convert_and_validate!(model, content);
|
||||
}
|
||||
@ -14,6 +14,7 @@ pub struct YaSerdeAttribute {
|
||||
pub prefix: Option<String>,
|
||||
pub root: Option<String>,
|
||||
pub rename: Option<String>,
|
||||
pub skip_serializing_if: Option<String>,
|
||||
pub text: bool,
|
||||
}
|
||||
|
||||
@ -41,6 +42,7 @@ impl YaSerdeAttribute {
|
||||
let mut prefix = None;
|
||||
let mut rename = None;
|
||||
let mut root = None;
|
||||
let mut skip_serializing_if = None;
|
||||
let mut text = false;
|
||||
|
||||
for attr in attrs.iter() {
|
||||
@ -85,6 +87,9 @@ impl YaSerdeAttribute {
|
||||
"root" => {
|
||||
root = get_value(&mut attr_iter);
|
||||
}
|
||||
"skip_serializing_if" => {
|
||||
skip_serializing_if = get_value(&mut attr_iter);
|
||||
}
|
||||
"text" => {
|
||||
text = true;
|
||||
}
|
||||
@ -106,6 +111,7 @@ impl YaSerdeAttribute {
|
||||
prefix,
|
||||
rename,
|
||||
root,
|
||||
skip_serializing_if,
|
||||
text,
|
||||
}
|
||||
}
|
||||
@ -126,6 +132,7 @@ fn parse_empty_attributes() {
|
||||
prefix: None,
|
||||
root: None,
|
||||
rename: None,
|
||||
skip_serializing_if: None,
|
||||
text: false,
|
||||
},
|
||||
attrs
|
||||
@ -175,6 +182,7 @@ fn parse_attributes() {
|
||||
prefix: None,
|
||||
root: None,
|
||||
rename: None,
|
||||
skip_serializing_if: None,
|
||||
text: false,
|
||||
},
|
||||
attrs
|
||||
@ -228,6 +236,7 @@ fn parse_attributes_with_values() {
|
||||
prefix: None,
|
||||
root: None,
|
||||
rename: None,
|
||||
skip_serializing_if: None,
|
||||
text: false,
|
||||
},
|
||||
attrs
|
||||
|
||||
@ -1,55 +1,50 @@
|
||||
use attribute::*;
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
|
||||
pub fn enclose_formatted_characters(label: &Ident, label_name: String) -> TokenStream {
|
||||
quote! {
|
||||
let start_event = XmlEvent::start_element(#label_name);
|
||||
let _ret = writer.write(start_event);
|
||||
|
||||
let yas_value = format!("{}", &self.#label);
|
||||
let data_event = XmlEvent::characters(&yas_value);
|
||||
let _ret = writer.write(data_event);
|
||||
|
||||
let end_event = XmlEvent::end_element();
|
||||
let _ret = writer.write(end_event);
|
||||
}
|
||||
enclose_xml_event(label_name, quote!(format!("{}", &self.#label)))
|
||||
}
|
||||
|
||||
pub fn enclose_formatted_characters_for_value(label: &Ident, label_name: String) -> TokenStream {
|
||||
quote! {
|
||||
let start_event = XmlEvent::start_element(#label_name);
|
||||
let _ret = writer.write(start_event);
|
||||
|
||||
let value = format!("{}", #label);
|
||||
let data_event = XmlEvent::characters(&value);
|
||||
let _ret = writer.write(data_event);
|
||||
|
||||
let end_event = XmlEvent::end_element();
|
||||
let _ret = writer.write(end_event);
|
||||
}
|
||||
enclose_xml_event(label_name, quote!(format!("{}", #label)))
|
||||
}
|
||||
|
||||
pub fn enclose_characters(label: &Option<Ident>, label_name: String) -> TokenStream {
|
||||
enclose_xml_event(label_name, quote!(format!("{}", self.#label)))
|
||||
}
|
||||
|
||||
pub fn enclose_xml_event(label_name: String, yaserde_format: TokenStream) -> TokenStream {
|
||||
quote! {
|
||||
let start_event = XmlEvent::start_element(#label_name);
|
||||
let _ret = writer.write(start_event);
|
||||
writer.write(start_event).map_err(|e| e.to_string())?;
|
||||
|
||||
let value = format!("{}", self.#label);
|
||||
let data_event = XmlEvent::characters(&value);
|
||||
let _ret = writer.write(data_event);
|
||||
let yaserde_value = #yaserde_format;
|
||||
let data_event = XmlEvent::characters(&yaserde_value);
|
||||
writer.write(data_event).map_err(|e| e.to_string())?;
|
||||
|
||||
let end_event = XmlEvent::end_element();
|
||||
let _ret = writer.write(end_event);
|
||||
writer.write(end_event).map_err(|e| e.to_string())?;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn serialize_element(
|
||||
label: &Option<Ident>,
|
||||
label_name: String,
|
||||
default: &Option<String>,
|
||||
conditions: &TokenStream,
|
||||
) -> Option<TokenStream> {
|
||||
let inner = enclose_characters(label, label_name);
|
||||
|
||||
if let Some(ref d) = default {
|
||||
Some(quote! {
|
||||
#conditions {
|
||||
#inner
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn condition_generator(label: &Option<Ident>, attributes: &YaSerdeAttribute) -> TokenStream {
|
||||
let mut conditions = None;
|
||||
|
||||
if let Some(ref d) = attributes.default {
|
||||
let default_function = Ident::new(
|
||||
&d,
|
||||
label
|
||||
@ -57,14 +52,23 @@ pub fn serialize_element(
|
||||
.map_or(Span::call_site(), |ident| ident.span()),
|
||||
);
|
||||
|
||||
Some(quote! {
|
||||
if self.#label != #default_function() {
|
||||
#inner
|
||||
}
|
||||
})
|
||||
} else {
|
||||
Some(quote! {
|
||||
#inner
|
||||
})
|
||||
conditions = Some(quote!(self.#label != #default_function()))
|
||||
}
|
||||
|
||||
if let Some(ref s) = attributes.skip_serializing_if {
|
||||
let skip_if_function = Ident::new(
|
||||
&s,
|
||||
label
|
||||
.as_ref()
|
||||
.map_or(Span::call_site(), |ident| ident.span()),
|
||||
);
|
||||
|
||||
conditions = if let Some(prev_conditions) = conditions {
|
||||
Some(quote!(!#skip_if_function() && #prev_conditions))
|
||||
} else {
|
||||
Some(quote!(!self.#skip_if_function(&self.#label)))
|
||||
};
|
||||
}
|
||||
|
||||
conditions.map(|c| quote!(if #c)).unwrap_or(quote!())
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ pub fn serialize(
|
||||
Fields::Unit => Some(quote! {
|
||||
&#name::#label => {
|
||||
let data_event = XmlEvent::characters(#label_name);
|
||||
let _ret = writer.write(data_event);
|
||||
writer.write(data_event).map_err(|e| e.to_string())?;
|
||||
}
|
||||
}),
|
||||
Fields::Named(ref fields) => {
|
||||
@ -50,7 +50,7 @@ pub fn serialize(
|
||||
if field_attrs.text {
|
||||
return Some(quote!(
|
||||
let data_event = XmlEvent::characters(&self.#field_label);
|
||||
let _ret = writer.write(data_event);
|
||||
writer.write(data_event).map_err(|e| e.to_string())?;
|
||||
));
|
||||
}
|
||||
|
||||
@ -61,19 +61,21 @@ pub fn serialize(
|
||||
let field_label_name = renamed_field_label.unwrap().to_string();
|
||||
|
||||
match get_field_type(field) {
|
||||
Some(FieldType::FieldTypeString) => Some(quote! {
|
||||
match self {
|
||||
&#name::#label{ref #field_label, ..} => {
|
||||
let struct_start_event = XmlEvent::start_element(#field_label_name);
|
||||
let _ret = writer.write(struct_start_event);
|
||||
Some(FieldType::FieldTypeString) => Some({
|
||||
quote! {
|
||||
match self {
|
||||
&#name::#label{ref #field_label, ..} => {
|
||||
let struct_start_event = XmlEvent::start_element(#field_label_name);
|
||||
writer.write(struct_start_event).map_err(|e| e.to_string())?;
|
||||
|
||||
let data_event = XmlEvent::characters(#field_label);
|
||||
let _ret = writer.write(data_event);
|
||||
let data_event = XmlEvent::characters(#field_label);
|
||||
writer.write(data_event).map_err(|e| e.to_string())?;
|
||||
|
||||
let struct_end_event = XmlEvent::end_element();
|
||||
let _ret = writer.write(struct_end_event);
|
||||
},
|
||||
_ => {},
|
||||
let struct_end_event = XmlEvent::end_element();
|
||||
writer.write(struct_end_event).map_err(|e| e.to_string())?;
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}),
|
||||
Some(FieldType::FieldTypeStruct { .. }) => Some(quote! {
|
||||
@ -123,24 +125,24 @@ pub fn serialize(
|
||||
let write_element = |action: &TokenStream| {
|
||||
quote! {
|
||||
let struct_start_event = XmlEvent::start_element(#label_name);
|
||||
let _ret = writer.write(struct_start_event);
|
||||
writer.write(struct_start_event).map_err(|e| e.to_string())?;
|
||||
|
||||
#action
|
||||
|
||||
let struct_end_event = XmlEvent::end_element();
|
||||
let _ret = writer.write(struct_end_event);
|
||||
writer.write(struct_end_event).map_err(|e| e.to_string())?;
|
||||
}
|
||||
};
|
||||
|
||||
let write_string_chars = quote! {
|
||||
let data_event = XmlEvent::characters(item);
|
||||
let _ret = writer.write(data_event);
|
||||
writer.write(data_event).map_err(|e| e.to_string())?;
|
||||
};
|
||||
|
||||
let write_simple_type = write_element("e! {
|
||||
let s = item.to_string();
|
||||
let data_event = XmlEvent::characters(&s);
|
||||
let _ret = writer.write(data_event);
|
||||
writer.write(data_event).map_err(|e| e.to_string())?;
|
||||
});
|
||||
|
||||
let serialize = quote! {
|
||||
@ -239,10 +241,10 @@ pub fn serialize(
|
||||
if !skip {
|
||||
if let Some(label) = writer.get_start_event_name() {
|
||||
let struct_start_event = XmlEvent::start_element(label.as_ref());
|
||||
let _ret = writer.write(struct_start_event);
|
||||
writer.write(struct_start_event).map_err(|e| e.to_string())?;
|
||||
} else {
|
||||
let struct_start_event = XmlEvent::start_element(#root)#add_namespaces;
|
||||
let _ret = writer.write(struct_start_event);
|
||||
writer.write(struct_start_event).map_err(|e| e.to_string())?;
|
||||
}
|
||||
}
|
||||
|
||||
@ -252,7 +254,7 @@ pub fn serialize(
|
||||
|
||||
if !skip {
|
||||
let struct_end_event = XmlEvent::end_element();
|
||||
let _ret = writer.write(struct_end_event);
|
||||
writer.write(struct_end_event).map_err(|e| e.to_string())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@ -126,7 +126,7 @@ pub fn serialize(
|
||||
}
|
||||
}
|
||||
FieldType::FieldTypeVec { .. } => {
|
||||
let item_ident = Ident::new("yas_item", field.span());
|
||||
let item_ident = Ident::new("yaserde_item", field.span());
|
||||
let inner = enclose_formatted_characters(&item_ident, label_name);
|
||||
|
||||
if let Some(ref d) = field_attrs.default {
|
||||
@ -134,8 +134,8 @@ pub fn serialize(
|
||||
|
||||
Some(quote! {
|
||||
if self.#label != #default_function() {
|
||||
if let Some(ref yas_list) = self.#label {
|
||||
for yas_item in yas_list.iter() {
|
||||
if let Some(ref yaserde_list) = self.#label {
|
||||
for yaserde_item in yaserde_list.iter() {
|
||||
#inner
|
||||
}
|
||||
}
|
||||
@ -143,7 +143,7 @@ pub fn serialize(
|
||||
})
|
||||
} else {
|
||||
Some(quote! {
|
||||
for yas_item in &self.#label {
|
||||
for yaserde_item in &self.#label {
|
||||
#inner
|
||||
}
|
||||
})
|
||||
@ -236,11 +236,12 @@ pub fn serialize(
|
||||
if field_attrs.text {
|
||||
return Some(quote!(
|
||||
let data_event = XmlEvent::characters(&self.#label);
|
||||
let _ret = writer.write(data_event);
|
||||
writer.write(data_event).map_err(|e| e.to_string())?;
|
||||
));
|
||||
}
|
||||
|
||||
let label_name = build_label_name(&field, &field_attrs);
|
||||
let conditions = condition_generator(label, &field_attrs);
|
||||
|
||||
get_field_type(field).and_then(|f| match f {
|
||||
FieldType::FieldTypeString
|
||||
@ -254,7 +255,7 @@ pub fn serialize(
|
||||
| FieldType::FieldTypeI64
|
||||
| FieldType::FieldTypeU64
|
||||
| FieldType::FieldTypeF32
|
||||
| FieldType::FieldTypeF64 => serialize_element(label, label_name, &field_attrs.default),
|
||||
| FieldType::FieldTypeF64 => serialize_element(label, label_name, &conditions),
|
||||
FieldType::FieldTypeOption { data_type } => match *data_type {
|
||||
FieldType::FieldTypeString
|
||||
| FieldType::FieldTypeBool
|
||||
@ -268,52 +269,30 @@ pub fn serialize(
|
||||
| FieldType::FieldTypeU64
|
||||
| FieldType::FieldTypeF32
|
||||
| FieldType::FieldTypeF64 => {
|
||||
let item_ident = Ident::new("yas_item", field.span());
|
||||
let item_ident = Ident::new("yaserde_item", field.span());
|
||||
let inner = enclose_formatted_characters_for_value(&item_ident, label_name);
|
||||
|
||||
if let Some(ref d) = field_attrs.default {
|
||||
let default_function = Ident::new(&d, field.span());
|
||||
|
||||
Some(quote! {
|
||||
if self.#label != #default_function() {
|
||||
if let Some(ref yas_item) = self.#label {
|
||||
#inner
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
Some(quote! {
|
||||
if let Some(ref yas_item) = self.#label {
|
||||
Some(quote! {
|
||||
#conditions {
|
||||
if let Some(ref yaserde_item) = self.#label {
|
||||
#inner
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
FieldType::FieldTypeVec { .. } => {
|
||||
let item_ident = Ident::new("yas_item", field.span());
|
||||
let item_ident = Ident::new("yaserde_item", field.span());
|
||||
let inner = enclose_formatted_characters_for_value(&item_ident, label_name);
|
||||
|
||||
if let Some(ref d) = field_attrs.default {
|
||||
let default_function = Ident::new(&d, field.span());
|
||||
|
||||
Some(quote! {
|
||||
if self.#label != #default_function() {
|
||||
if let Some(ref yas_items) = &self.#label {
|
||||
for yas_item in yas_items.iter() {
|
||||
#inner
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
Some(quote! {
|
||||
if let Some(ref yas_items) = &self.#label {
|
||||
for yas_item in yas_items.iter() {
|
||||
Some(quote! {
|
||||
#conditions {
|
||||
if let Some(ref yaserde_items) = &self.#label {
|
||||
for yaserde_item in yaserde_items.iter() {
|
||||
#inner
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
FieldType::FieldTypeStruct { .. } => Some(if field_attrs.flatten {
|
||||
quote! {
|
||||
@ -334,26 +313,26 @@ pub fn serialize(
|
||||
}),
|
||||
_ => unimplemented!(),
|
||||
},
|
||||
FieldType::FieldTypeStruct { .. } => Some(if field_attrs.flatten {
|
||||
quote! {
|
||||
writer.set_start_event_name(None);
|
||||
writer.set_skip_start_end(true);
|
||||
FieldType::FieldTypeStruct { .. } => {
|
||||
let (start_event, skip_start) = if field_attrs.flatten {
|
||||
(quote!(None), true)
|
||||
} else {
|
||||
(quote!(Some(#label_name.to_string())), false)
|
||||
};
|
||||
|
||||
Some(quote! {
|
||||
writer.set_start_event_name(#start_event);
|
||||
writer.set_skip_start_end(#skip_start);
|
||||
self.#label.serialize(writer)?;
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
writer.set_start_event_name(Some(#label_name.to_string()));
|
||||
writer.set_skip_start_end(false);
|
||||
self.#label.serialize(writer)?;
|
||||
}
|
||||
}),
|
||||
})
|
||||
}
|
||||
FieldType::FieldTypeVec { data_type } => match *data_type {
|
||||
FieldType::FieldTypeString => {
|
||||
let item_ident = Ident::new("yas_item", field.span());
|
||||
let item_ident = Ident::new("yaserde_item", field.span());
|
||||
let inner = enclose_formatted_characters_for_value(&item_ident, label_name);
|
||||
|
||||
Some(quote! {
|
||||
for yas_item in &self.#label {
|
||||
for yaserde_item in &self.#label {
|
||||
#inner
|
||||
}
|
||||
})
|
||||
@ -369,11 +348,11 @@ pub fn serialize(
|
||||
| FieldType::FieldTypeU64
|
||||
| FieldType::FieldTypeF32
|
||||
| FieldType::FieldTypeF64 => {
|
||||
let item_ident = Ident::new("yas_item", field.span());
|
||||
let item_ident = Ident::new("yaserde_item", field.span());
|
||||
let inner = enclose_formatted_characters_for_value(&item_ident, label_name);
|
||||
|
||||
Some(quote! {
|
||||
for yas_item in &self.#label {
|
||||
for yaserde_item in &self.#label {
|
||||
#inner
|
||||
}
|
||||
})
|
||||
@ -413,17 +392,17 @@ pub fn serialize(
|
||||
let skip = writer.skip_start_end();
|
||||
|
||||
if !skip {
|
||||
let label = writer.get_start_event_name().unwrap_or_else(|| #root.to_string());
|
||||
let struct_start_event = XmlEvent::start_element(label.as_ref())#add_namespaces;
|
||||
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;
|
||||
#build_attributes
|
||||
let _ret = writer.write(struct_start_event);
|
||||
writer.write(struct_start_event).map_err(|e| e.to_string())?;
|
||||
}
|
||||
|
||||
#struct_inspector
|
||||
|
||||
if !skip {
|
||||
let struct_end_event = XmlEvent::end_element();
|
||||
let _ret = writer.write(struct_end_event);
|
||||
writer.write(struct_end_event).map_err(|e| e.to_string())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
Loading…
Reference in New Issue
Block a user