From 4a619827925dc7e219d0cbd20ec157c14bcb25a4 Mon Sep 17 00:00:00 2001
From: rsdy
Date: Tue, 27 Sep 2022 12:21:05 +0100
Subject: [PATCH] Add enum integration test and fix ser/de logic
---
instant-xml-macros/src/case.rs | 2 +-
instant-xml-macros/src/de.rs | 39 ++++++++++++++++++++++------------
instant-xml-macros/src/lib.rs | 6 +++---
instant-xml-macros/src/ser.rs | 2 ++
instant-xml/tests/rename.rs | 28 ++++++++++++++++++++++++
5 files changed, 59 insertions(+), 18 deletions(-)
diff --git a/instant-xml-macros/src/case.rs b/instant-xml-macros/src/case.rs
index a6191f7..540a141 100644
--- a/instant-xml-macros/src/case.rs
+++ b/instant-xml-macros/src/case.rs
@@ -1,4 +1,4 @@
-//! Originally from https://raw.githubusercontent.com/serde-rs/serde/master/serde_derive/src/internals/case.rs
+//! Originally from
//! Code to convert the Rust-styled field/variant (e.g. `my_field`, `MyType`) to the
//! case of the source (e.g. `my-field`, `MY_FIELD`).
diff --git a/instant-xml-macros/src/de.rs b/instant-xml-macros/src/de.rs
index 2d59c8c..47358cf 100644
--- a/instant-xml-macros/src/de.rs
+++ b/instant-xml-macros/src/de.rs
@@ -1,6 +1,6 @@
use proc_macro2::{Ident, Span, TokenStream};
use quote::{quote, ToTokens};
-use syn::spanned::Spanned;
+use syn::{spanned::Spanned, ImplGenerics};
use super::{discard_lifetimes, ContainerMeta, FieldMeta, Namespace, VariantMeta};
@@ -11,22 +11,37 @@ pub(crate) fn from_xml(input: &syn::DeriveInput) -> TokenStream {
Err(e) => return e.to_compile_error(),
};
+ let mut xml_generics = input.generics.clone();
+ let mut xml = syn::LifetimeDef::new(syn::Lifetime::new("'xml", Span::call_site()));
+ xml.bounds
+ .extend(xml_generics.lifetimes().map(|lt| lt.lifetime.clone()));
+ xml_generics.params.push(xml.into());
+
+ let (xml_impl_generics, _, _) = xml_generics.split_for_impl();
+
match &input.data {
syn::Data::Struct(_) if meta.scalar => {
syn::Error::new(input.span(), "scalar structs are unsupported!").to_compile_error()
}
- syn::Data::Struct(ref data) => deserialize_struct(input, data, meta, ident),
+ syn::Data::Struct(ref data) => {
+ deserialize_struct(input, data, meta, ident, xml_impl_generics)
+ }
syn::Data::Enum(_) if !meta.scalar => {
syn::Error::new(input.span(), "non-scalar enums are currently unsupported!")
.to_compile_error()
}
- syn::Data::Enum(ref data) => deserialize_enum(input, data, meta),
+ syn::Data::Enum(ref data) => deserialize_enum(input, data, meta, xml_impl_generics),
_ => todo!(),
}
}
#[rustfmt::skip]
-fn deserialize_enum(input: &syn::DeriveInput, data: &syn::DataEnum, meta: ContainerMeta) -> TokenStream {
+fn deserialize_enum(
+ input: &syn::DeriveInput,
+ data: &syn::DataEnum,
+ meta: ContainerMeta,
+ xml_impl_generics: ImplGenerics
+) -> TokenStream {
let ident = &input.ident;
let mut variants = TokenStream::new();
@@ -38,19 +53,21 @@ fn deserialize_enum(input: &syn::DeriveInput, data: &syn::DataEnum, meta: Contai
};
let serialize_as = meta.serialize_as;
- variants.extend(quote!(Ok(#serialize_as) => #ident::#v_ident,));
+ variants.extend(quote!(Ok(#serialize_as) => Ok(#ident::#v_ident),));
}
- let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
+ let (_, ty_generics, where_clause) = input.generics.split_for_impl();
quote!(
- impl #impl_generics FromXml<'xml> for #ident #ty_generics #where_clause {
+ impl #xml_impl_generics FromXml<'xml> for #ident #ty_generics #where_clause {
fn deserialize<'cx>(deserializer: &'cx mut ::instant_xml::Deserializer<'cx, 'xml>) -> Result {
match deserializer.take_str() {
#variants
_ => Err(::instant_xml::Error::UnexpectedValue)
}
}
+
+ const KIND: ::instant_xml::Kind = ::instant_xml::Kind::Scalar;
}
)
}
@@ -60,20 +77,14 @@ fn deserialize_struct(
data: &syn::DataStruct,
container_meta: ContainerMeta,
ident: &Ident,
+ xml_impl_generics: ImplGenerics,
) -> TokenStream {
let default_namespace = match &container_meta.ns.uri {
Some(ns) => quote!(#ns),
None => quote!(""),
};
- let mut xml_generics = input.generics.clone();
- let mut xml = syn::LifetimeDef::new(syn::Lifetime::new("'xml", Span::call_site()));
- xml.bounds
- .extend(xml_generics.lifetimes().map(|lt| lt.lifetime.clone()));
- xml_generics.params.push(xml.into());
-
let (_, ty_generics, where_clause) = input.generics.split_for_impl();
- let (xml_impl_generics, _, _) = xml_generics.split_for_impl();
let mut namespaces_map = quote!(let mut namespaces_map = std::collections::HashMap::new(););
for (k, v) in container_meta.ns.prefixes.iter() {
diff --git a/instant-xml-macros/src/lib.rs b/instant-xml-macros/src/lib.rs
index 5a4b1d4..5899b04 100644
--- a/instant-xml-macros/src/lib.rs
+++ b/instant-xml-macros/src/lib.rs
@@ -684,7 +684,7 @@ mod tests {
};
assert_eq!(super::ser::to_xml(&input).to_string(),
-"impl ToXml for TestEnum { fn serialize < W : :: core :: fmt :: Write + ? :: core :: marker :: Sized > (& self , serializer : & mut instant_xml :: Serializer < W > ,) -> Result < () , instant_xml :: Error > { serializer . write_str (match self { TestEnum :: Foo => \"Foo\" , TestEnum :: Bar => \"Bar\" , TestEnum :: Baz => \"1\" , }) } }"
+"impl ToXml for TestEnum { fn serialize < W : :: core :: fmt :: Write + ? :: core :: marker :: Sized > (& self , serializer : & mut instant_xml :: Serializer < W > ,) -> Result < () , instant_xml :: Error > { serializer . write_str (match self { TestEnum :: Foo => \"Foo\" , TestEnum :: Bar => \"Bar\" , TestEnum :: Baz => \"1\" , }) } const KIND : :: instant_xml :: Kind = :: instant_xml :: Kind :: Scalar ; }"
)
}
@@ -701,7 +701,7 @@ mod tests {
};
assert_eq!(super::de::from_xml(&input).to_string(),
-"impl FromXml < 'xml > for TestEnum { fn deserialize < 'cx > (deserializer : & 'cx mut :: instant_xml :: Deserializer < 'cx , 'xml >) -> Result < Self , :: instant_xml :: Error > { match deserializer . take_str () { Ok (\"Foo\") => TestEnum :: Foo , Ok (\"Bar\") => TestEnum :: Bar , Ok (\"1\") => TestEnum :: Baz , _ => Err (:: instant_xml :: Error :: UnexpectedValue) } } }"
+"impl < 'xml > FromXml < 'xml > for TestEnum { fn deserialize < 'cx > (deserializer : & 'cx mut :: instant_xml :: Deserializer < 'cx , 'xml >) -> Result < Self , :: instant_xml :: Error > { match deserializer . take_str () { Ok (\"Foo\") => Ok (TestEnum :: Foo) , Ok (\"Bar\") => Ok (TestEnum :: Bar) , Ok (\"1\") => Ok (TestEnum :: Baz) , _ => Err (:: instant_xml :: Error :: UnexpectedValue) } } const KIND : :: instant_xml :: Kind = :: instant_xml :: Kind :: Scalar ; }"
)
}
@@ -789,7 +789,7 @@ mod tests {
Bar,
Baz
}
- }).to_string(), "impl ToXml for TestEnum { fn serialize < W : :: core :: fmt :: Write + ? :: core :: marker :: Sized > (& self , serializer : & mut instant_xml :: Serializer < W > ,) -> Result < () , instant_xml :: Error > { serializer . write_str (match self { TestEnum :: Foo => \"1\" , TestEnum :: Bar => \"BAR\" , TestEnum :: Baz => \"BAZ\" , }) } }");
+ }).to_string(), "impl ToXml for TestEnum { fn serialize < W : :: core :: fmt :: Write + ? :: core :: marker :: Sized > (& self , serializer : & mut instant_xml :: Serializer < W > ,) -> Result < () , instant_xml :: Error > { serializer . write_str (match self { TestEnum :: Foo => \"1\" , TestEnum :: Bar => \"BAR\" , TestEnum :: Baz => \"BAZ\" , }) } const KIND : :: instant_xml :: Kind = :: instant_xml :: Kind :: Scalar ; }");
}
#[test]
diff --git a/instant-xml-macros/src/ser.rs b/instant-xml-macros/src/ser.rs
index d4b0ca1..eb2a6c7 100644
--- a/instant-xml-macros/src/ser.rs
+++ b/instant-xml-macros/src/ser.rs
@@ -56,6 +56,8 @@ fn serialize_enum(
) -> Result<(), instant_xml::Error> {
serializer.write_str(match self { #variants })
}
+
+ const KIND: ::instant_xml::Kind = ::instant_xml::Kind::Scalar;
}
)
}
diff --git a/instant-xml/tests/rename.rs b/instant-xml/tests/rename.rs
index 4a4abbb..dd38774 100644
--- a/instant-xml/tests/rename.rs
+++ b/instant-xml/tests/rename.rs
@@ -41,3 +41,31 @@ fn rename_all_struct() {
assert_eq!(to_string(&instance).unwrap(), serialized);
assert_eq!(from_str::(serialized), Ok(instance));
}
+
+#[test]
+fn rename_all_enum_variant() {
+ #[derive(Debug, PartialEq, Eq, ToXml, FromXml)]
+ #[xml(scalar, rename_all = "snake_case")]
+ pub enum TestEnum {
+ SnakeCased,
+ ThisToo,
+ }
+
+ #[derive(Debug, PartialEq, Eq, ToXml, FromXml)]
+ #[xml(rename_all = "UPPERCASE")]
+ pub struct TestStruct {
+ field_1: TestEnum,
+ #[xml(attribute)]
+ field_2: TestEnum,
+ }
+
+ let serialized =
+ r#"snake_cased"#;
+ let instance = TestStruct {
+ field_1: TestEnum::SnakeCased,
+ field_2: TestEnum::ThisToo,
+ };
+
+ assert_eq!(to_string(&instance).unwrap(), serialized);
+ assert_eq!(from_str::(serialized), Ok(instance));
+}