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)); +}