Merge pull request #182 from YBeaugnon/main
Support for internally tagged enum
This commit is contained in:
commit
177fa8e5a7
@ -357,3 +357,41 @@ fn unnamed_enum() {
|
|||||||
serialize_and_validate!(model, content);
|
serialize_and_validate!(model, content);
|
||||||
deserialize_and_validate!(content, model, XmlStruct);
|
deserialize_and_validate!(content, model, XmlStruct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn tagged_enum() {
|
||||||
|
#[derive(Debug, PartialEq, YaSerialize, YaDeserialize, Default)]
|
||||||
|
#[yaserde(tag = "type")]
|
||||||
|
#[yaserde(rename = "foobar")]
|
||||||
|
enum XmlEnum {
|
||||||
|
#[default]
|
||||||
|
#[yaserde(rename = "foo")]
|
||||||
|
Foo,
|
||||||
|
#[yaserde(rename = "bar")]
|
||||||
|
Bar,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, YaSerialize, YaDeserialize, Default)]
|
||||||
|
#[yaserde(rename = "base")]
|
||||||
|
struct XmlStruct {
|
||||||
|
#[yaserde(rename = "foobar")]
|
||||||
|
foo_bar: XmlEnum,
|
||||||
|
}
|
||||||
|
|
||||||
|
let model = XmlEnum::Foo;
|
||||||
|
let content = "<foobar type=\"foo\" />";
|
||||||
|
serialize_and_validate!(model, content);
|
||||||
|
deserialize_and_validate!(content, model, XmlEnum);
|
||||||
|
|
||||||
|
let model = XmlEnum::Bar;
|
||||||
|
let content = "<foobar type=\"bar\" />";
|
||||||
|
serialize_and_validate!(model, content);
|
||||||
|
deserialize_and_validate!(content, model, XmlEnum);
|
||||||
|
|
||||||
|
let model = XmlStruct {
|
||||||
|
foo_bar: XmlEnum::Foo,
|
||||||
|
};
|
||||||
|
let content = "<base><foobar type=\"foo\" /></base>";
|
||||||
|
serialize_and_validate!(model, content);
|
||||||
|
deserialize_and_validate!(content, model, XmlStruct);
|
||||||
|
}
|
||||||
|
|||||||
@ -12,6 +12,7 @@ pub struct YaSerdeAttribute {
|
|||||||
pub namespaces: BTreeMap<Option<String>, String>,
|
pub namespaces: BTreeMap<Option<String>, String>,
|
||||||
pub prefix: Option<String>,
|
pub prefix: Option<String>,
|
||||||
pub rename: Option<String>,
|
pub rename: Option<String>,
|
||||||
|
pub tag: Option<String>,
|
||||||
pub skip_serializing: bool,
|
pub skip_serializing: bool,
|
||||||
pub skip_serializing_if: Option<String>,
|
pub skip_serializing_if: Option<String>,
|
||||||
pub text: bool,
|
pub text: bool,
|
||||||
@ -40,6 +41,7 @@ impl YaSerdeAttribute {
|
|||||||
let mut namespaces = BTreeMap::new();
|
let mut namespaces = BTreeMap::new();
|
||||||
let mut prefix = None;
|
let mut prefix = None;
|
||||||
let mut rename = None;
|
let mut rename = None;
|
||||||
|
let mut tag = None;
|
||||||
let mut skip_serializing = false;
|
let mut skip_serializing = false;
|
||||||
let mut skip_serializing_if = None;
|
let mut skip_serializing_if = None;
|
||||||
let mut text = false;
|
let mut text = false;
|
||||||
@ -82,6 +84,9 @@ impl YaSerdeAttribute {
|
|||||||
"rename" => {
|
"rename" => {
|
||||||
rename = get_value(&mut attr_iter);
|
rename = get_value(&mut attr_iter);
|
||||||
}
|
}
|
||||||
|
"tag" => {
|
||||||
|
tag = get_value(&mut attr_iter);
|
||||||
|
}
|
||||||
"skip_serializing" => {
|
"skip_serializing" => {
|
||||||
skip_serializing = true;
|
skip_serializing = true;
|
||||||
}
|
}
|
||||||
@ -107,6 +112,7 @@ impl YaSerdeAttribute {
|
|||||||
namespaces,
|
namespaces,
|
||||||
prefix,
|
prefix,
|
||||||
rename,
|
rename,
|
||||||
|
tag,
|
||||||
skip_serializing,
|
skip_serializing,
|
||||||
skip_serializing_if,
|
skip_serializing_if,
|
||||||
text,
|
text,
|
||||||
@ -182,6 +188,7 @@ fn parse_empty_attributes() {
|
|||||||
namespaces: BTreeMap::new(),
|
namespaces: BTreeMap::new(),
|
||||||
prefix: None,
|
prefix: None,
|
||||||
rename: None,
|
rename: None,
|
||||||
|
tag: None,
|
||||||
skip_serializing: false,
|
skip_serializing: false,
|
||||||
skip_serializing_if: None,
|
skip_serializing_if: None,
|
||||||
text: false,
|
text: false,
|
||||||
@ -232,6 +239,7 @@ fn parse_attributes() {
|
|||||||
namespaces: BTreeMap::new(),
|
namespaces: BTreeMap::new(),
|
||||||
prefix: None,
|
prefix: None,
|
||||||
rename: None,
|
rename: None,
|
||||||
|
tag: None,
|
||||||
skip_serializing: false,
|
skip_serializing: false,
|
||||||
skip_serializing_if: None,
|
skip_serializing_if: None,
|
||||||
text: false,
|
text: false,
|
||||||
@ -282,6 +290,7 @@ fn only_parse_yaserde_attributes() {
|
|||||||
namespaces: BTreeMap::new(),
|
namespaces: BTreeMap::new(),
|
||||||
prefix: None,
|
prefix: None,
|
||||||
rename: None,
|
rename: None,
|
||||||
|
tag: None,
|
||||||
skip_serializing: false,
|
skip_serializing: false,
|
||||||
skip_serializing_if: None,
|
skip_serializing_if: None,
|
||||||
text: false,
|
text: false,
|
||||||
@ -338,6 +347,7 @@ fn parse_attributes_with_values() {
|
|||||||
namespaces,
|
namespaces,
|
||||||
prefix: None,
|
prefix: None,
|
||||||
rename: None,
|
rename: None,
|
||||||
|
tag: None,
|
||||||
skip_serializing: false,
|
skip_serializing: false,
|
||||||
skip_serializing_if: None,
|
skip_serializing_if: None,
|
||||||
text: false,
|
text: false,
|
||||||
|
|||||||
@ -24,6 +24,20 @@ pub fn parse(
|
|||||||
|
|
||||||
let flatten = root_attributes.flatten;
|
let flatten = root_attributes.flatten;
|
||||||
|
|
||||||
|
let element_name = if let Some(tag) = &root_attributes.tag {
|
||||||
|
quote! {
|
||||||
|
attributes
|
||||||
|
.iter()
|
||||||
|
.find(|attr| attr.name.local_name.as_str() == #tag)
|
||||||
|
.ok_or(format!("Expected enum tagged with {}, found {:?}", #tag, event))?
|
||||||
|
.value.as_str()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {
|
||||||
|
name.local_name.as_str()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
impl ::yaserde::YaDeserialize for #name {
|
impl ::yaserde::YaDeserialize for #name {
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
@ -50,7 +64,7 @@ pub fn parse(
|
|||||||
::yaserde::__derive_trace!("Enum {} @ {}: matching {:?}", stringify!(#name), start_depth, event);
|
::yaserde::__derive_trace!("Enum {} @ {}: matching {:?}", stringify!(#name), start_depth, event);
|
||||||
match event {
|
match event {
|
||||||
::yaserde::__xml::reader::XmlEvent::StartElement { ref name, ref attributes, .. } => {
|
::yaserde::__xml::reader::XmlEvent::StartElement { ref name, ref attributes, .. } => {
|
||||||
match name.local_name.as_str() {
|
match #element_name {
|
||||||
#match_to_enum
|
#match_to_enum
|
||||||
_named_element => {
|
_named_element => {
|
||||||
let _root = reader.next_event();
|
let _root = reader.next_event();
|
||||||
|
|||||||
@ -26,6 +26,21 @@ pub fn serialize(
|
|||||||
.map(|variant| -> TokenStream {
|
.map(|variant| -> TokenStream {
|
||||||
let _attrs = crate::common::YaSerdeAttribute::parse(&variant.attrs);
|
let _attrs = crate::common::YaSerdeAttribute::parse(&variant.attrs);
|
||||||
|
|
||||||
|
let add_tag = if let Some(tag) = &root_attributes.tag {
|
||||||
|
let attrs = crate::common::YaSerdeAttribute::parse(&variant.attrs);
|
||||||
|
let label = variant.ident.clone();
|
||||||
|
let element_name = attrs.xml_element_name(&variant.ident);
|
||||||
|
quote! {
|
||||||
|
match self {
|
||||||
|
#name::#label { .. } => {
|
||||||
|
let tag = ::yaserde::__xml::name::OwnedName::local(#tag);
|
||||||
|
child_attributes.push(::yaserde::__xml::attribute::OwnedAttribute::new(tag, #element_name));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { quote!() };
|
||||||
|
|
||||||
let all_fields = variant
|
let all_fields = variant
|
||||||
.fields
|
.fields
|
||||||
.iter()
|
.iter()
|
||||||
@ -39,7 +54,7 @@ pub fn serialize(
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
attribute_fields
|
let add_attributes : TokenStream = attribute_fields
|
||||||
.iter()
|
.iter()
|
||||||
.map(|field| {
|
.map(|field| {
|
||||||
let label = variant.ident.clone();
|
let label = variant.ident.clone();
|
||||||
@ -79,7 +94,9 @@ pub fn serialize(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect()
|
.collect();
|
||||||
|
|
||||||
|
quote!( #add_attributes #add_tag)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
@ -109,10 +126,16 @@ fn inner_enum_inspector(
|
|||||||
let label_name = build_label_name(label, &variant_attrs, &root_attributes.default_namespace);
|
let label_name = build_label_name(label, &variant_attrs, &root_attributes.default_namespace);
|
||||||
|
|
||||||
match variant.fields {
|
match variant.fields {
|
||||||
Fields::Unit => quote! {
|
Fields::Unit => {
|
||||||
&#name::#label => {
|
if let Some(_tag) = &root_attributes.tag {
|
||||||
let data_event = ::yaserde::__xml::writer::XmlEvent::characters(#label_name);
|
quote! { #name::#label => {} }
|
||||||
writer.write(data_event).map_err(|e| e.to_string())?;
|
} else {
|
||||||
|
quote! {
|
||||||
|
#name::#label => {
|
||||||
|
let data_event = ::yaserde::__xml::writer::XmlEvent::characters(#label_name);
|
||||||
|
writer.write(data_event).map_err(|e| e.to_string())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Fields::Named(ref fields) => {
|
Fields::Named(ref fields) => {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user