Switch from wrapped enums to forward enums
This commit is contained in:
parent
0a323ba302
commit
4ad194fc1f
|
@ -21,7 +21,7 @@ pub(crate) fn from_xml(input: &syn::DeriveInput) -> TokenStream {
|
|||
syn::Fields::Unit => deserialize_unit_struct(input, &meta),
|
||||
},
|
||||
(syn::Data::Enum(data), Some(Mode::Scalar)) => deserialize_scalar_enum(input, data, meta),
|
||||
(syn::Data::Enum(data), Some(Mode::Wrapped)) => deserialize_wrapped_enum(input, data, meta),
|
||||
(syn::Data::Enum(data), Some(Mode::Forward)) => deserialize_forward_enum(input, data, meta),
|
||||
(syn::Data::Struct(_), _) => {
|
||||
syn::Error::new(input.span(), "no enum mode allowed on struct type").to_compile_error()
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ fn deserialize_scalar_enum(
|
|||
)
|
||||
}
|
||||
|
||||
fn deserialize_wrapped_enum(
|
||||
fn deserialize_forward_enum(
|
||||
input: &syn::DeriveInput,
|
||||
data: &syn::DataEnum,
|
||||
meta: ContainerMeta,
|
||||
|
@ -99,6 +99,7 @@ fn deserialize_wrapped_enum(
|
|||
}
|
||||
|
||||
let ident = &input.ident;
|
||||
let mut matches = TokenStream::new();
|
||||
let mut variants = TokenStream::new();
|
||||
let mut borrowed = BTreeSet::new();
|
||||
for variant in data.variants.iter() {
|
||||
|
@ -126,6 +127,11 @@ fn deserialize_wrapped_enum(
|
|||
let mut no_lifetime_type = field.ty.clone();
|
||||
discard_lifetimes(&mut no_lifetime_type, &mut borrowed, false, true);
|
||||
|
||||
if !matches.is_empty() {
|
||||
matches.extend(quote!(||));
|
||||
}
|
||||
matches.extend(quote!(#no_lifetime_type::matches(id, field)));
|
||||
|
||||
if !variants.is_empty() {
|
||||
variants.extend(quote!(else));
|
||||
}
|
||||
|
@ -133,16 +139,13 @@ fn deserialize_wrapped_enum(
|
|||
let v_ident = &variant.ident;
|
||||
variants.extend(
|
||||
quote!(if <#no_lifetime_type as FromXml>::matches(id, None) {
|
||||
let mut nested = deserializer.nested(data);
|
||||
let mut value = None;
|
||||
#no_lifetime_type::deserialize(&mut nested, &mut value)?;
|
||||
#no_lifetime_type::deserialize(deserializer, &mut value)?;
|
||||
*into = value.map(#ident::#v_ident);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
let name = meta.tag();
|
||||
let default_ns = meta.default_namespace();
|
||||
let generics = meta.xml_generics(borrowed);
|
||||
let (xml_impl_generics, _, _) = generics.split_for_impl();
|
||||
let (_, ty_generics, where_clause) = input.generics.split_for_impl();
|
||||
|
@ -150,7 +153,7 @@ fn deserialize_wrapped_enum(
|
|||
impl #xml_impl_generics FromXml<'xml> for #ident #ty_generics #where_clause {
|
||||
#[inline]
|
||||
fn matches(id: ::instant_xml::Id<'_>, field: Option<::instant_xml::Id<'_>>) -> bool {
|
||||
id == ::instant_xml::Id { name: #name, ns: #default_ns }
|
||||
#matches
|
||||
}
|
||||
|
||||
fn deserialize<'cx>(
|
||||
|
@ -160,19 +163,9 @@ fn deserialize_wrapped_enum(
|
|||
use ::instant_xml::de::Node;
|
||||
use ::instant_xml::Error;
|
||||
|
||||
let node = match deserializer.next() {
|
||||
Some(result) => result?,
|
||||
None => return Err(Error::MissingValue(Self::KIND)),
|
||||
};
|
||||
|
||||
let data = match node {
|
||||
Node::Open(data) => data,
|
||||
_ => return Err(Error::UnexpectedState("unexpected node type for wrapped enum variant")),
|
||||
};
|
||||
|
||||
let id = deserializer.element_id(&data)?;
|
||||
let id = deserializer.parent();
|
||||
#variants else {
|
||||
return Err(Error::UnexpectedTag);
|
||||
return Err(Error::UnexpectedTag(format!("{:?}", id)));
|
||||
};
|
||||
|
||||
if let Some(_) = deserializer.next() {
|
||||
|
|
|
@ -300,8 +300,8 @@ fn discard_path_lifetimes(
|
|||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
enum Mode {
|
||||
Forward,
|
||||
Scalar,
|
||||
Wrapped,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -304,12 +304,12 @@ pub(crate) fn meta_items(attrs: &[syn::Attribute]) -> Vec<(MetaItem, Span)> {
|
|||
MetaState::Rename
|
||||
} else if id == "rename_all" {
|
||||
MetaState::RenameAll
|
||||
} else if id == "forward" {
|
||||
items.push((MetaItem::Mode(Mode::Forward), span));
|
||||
MetaState::Comma
|
||||
} else if id == "scalar" {
|
||||
items.push((MetaItem::Mode(Mode::Scalar), span));
|
||||
MetaState::Comma
|
||||
} else if id == "wrapped" {
|
||||
items.push((MetaItem::Mode(Mode::Wrapped), span));
|
||||
MetaState::Comma
|
||||
} else if id == "serialize_with" {
|
||||
MetaState::SerializeWith
|
||||
} else if id == "deserialize_with" {
|
||||
|
|
|
@ -16,7 +16,7 @@ pub fn to_xml(input: &syn::DeriveInput) -> proc_macro2::TokenStream {
|
|||
match (&input.data, meta.mode) {
|
||||
(syn::Data::Struct(data), None) => serialize_struct(input, data, meta),
|
||||
(syn::Data::Enum(data), Some(Mode::Scalar)) => serialize_scalar_enum(input, data, meta),
|
||||
(syn::Data::Enum(data), Some(Mode::Wrapped)) => serialize_wrapped_enum(input, data, meta),
|
||||
(syn::Data::Enum(data), Some(Mode::Forward)) => serialize_forward_enum(input, data, meta),
|
||||
(syn::Data::Struct(_), _) => {
|
||||
syn::Error::new(input.span(), "enum mode not allowed on struct type").to_compile_error()
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ fn serialize_scalar_enum(
|
|||
)
|
||||
}
|
||||
|
||||
fn serialize_wrapped_enum(
|
||||
fn serialize_forward_enum(
|
||||
input: &syn::DeriveInput,
|
||||
data: &syn::DataEnum,
|
||||
meta: ContainerMeta,
|
||||
|
@ -134,7 +134,6 @@ fn serialize_wrapped_enum(
|
|||
}
|
||||
|
||||
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
|
||||
let tag = meta.tag();
|
||||
quote!(
|
||||
impl #impl_generics ToXml for #ident #ty_generics #where_clause {
|
||||
fn serialize<W: ::core::fmt::Write + ?::core::marker::Sized>(
|
||||
|
@ -142,25 +141,10 @@ fn serialize_wrapped_enum(
|
|||
field: Option<::instant_xml::Id<'_>>,
|
||||
serializer: &mut instant_xml::Serializer<W>,
|
||||
) -> Result<(), instant_xml::Error> {
|
||||
// Start tag
|
||||
let prefix = serializer.write_start(#tag, #default_namespace)?;
|
||||
debug_assert_eq!(prefix, None);
|
||||
|
||||
// Set up element context, this will also emit namespace declarations
|
||||
#context
|
||||
let old = serializer.push(new)?;
|
||||
|
||||
// Finalize start element
|
||||
serializer.end_start()?;
|
||||
|
||||
match self {
|
||||
#variants
|
||||
}
|
||||
|
||||
// Close tag
|
||||
serializer.write_close(prefix, #tag)?;
|
||||
serializer.pop(old);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
};
|
||||
|
|
|
@ -75,6 +75,16 @@ impl<'cx, 'xml> Deserializer<'cx, 'xml> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn parent(&self) -> Id<'xml> {
|
||||
Id {
|
||||
ns: match self.prefix {
|
||||
Some(ns) => self.context.lookup(ns).unwrap(),
|
||||
None => self.context.default_ns(),
|
||||
},
|
||||
name: self.local,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn element_id(&self, element: &Element<'xml>) -> Result<Id<'xml>, Error> {
|
||||
self.context.element_id(element)
|
||||
|
|
|
@ -93,8 +93,8 @@ pub enum Error {
|
|||
UnexpectedEndOfStream,
|
||||
#[error("unexpected value")]
|
||||
UnexpectedValue(&'static str),
|
||||
#[error("unexpected tag")]
|
||||
UnexpectedTag,
|
||||
#[error("unexpected tag: {0}")]
|
||||
UnexpectedTag(String),
|
||||
#[error("missing tag")]
|
||||
MissingTag,
|
||||
#[error("missing value")]
|
||||
|
|
|
@ -3,7 +3,7 @@ use similar_asserts::assert_eq;
|
|||
use instant_xml::{from_str, to_string, FromXml, ToXml};
|
||||
|
||||
#[derive(Debug, Eq, FromXml, PartialEq, ToXml)]
|
||||
#[xml(wrapped)]
|
||||
#[xml(forward)]
|
||||
enum Foo {
|
||||
Bar(Bar),
|
||||
Baz(Baz),
|
||||
|
@ -22,7 +22,7 @@ struct Baz {
|
|||
#[test]
|
||||
fn wrapped_enum() {
|
||||
let v = Foo::Bar(Bar { bar: 42 });
|
||||
let xml = r#"<Foo><Bar><bar>42</bar></Bar></Foo>"#;
|
||||
let xml = r#"<Bar><bar>42</bar></Bar>"#;
|
||||
assert_eq!(xml, to_string(&v).unwrap());
|
||||
assert_eq!(v, from_str(xml).unwrap());
|
||||
}
|
Loading…
Reference in New Issue