diff --git a/crates/xml/derive/src/de/attrs.rs b/crates/xml/derive/src/attrs.rs similarity index 100% rename from crates/xml/derive/src/de/attrs.rs rename to crates/xml/derive/src/attrs.rs diff --git a/crates/xml/derive/src/de/mod.rs b/crates/xml/derive/src/de/mod.rs deleted file mode 100644 index 59561e9..0000000 --- a/crates/xml/derive/src/de/mod.rs +++ /dev/null @@ -1,25 +0,0 @@ -pub mod attrs; -mod de_enum; -mod de_struct; -mod field; - -pub use de_enum::Enum; -pub use de_struct::NamedStruct; -pub use field::Field; - -pub fn get_generic_type(ty: &syn::Type) -> Option<&syn::Type> { - if let syn::Type::Path(syn::TypePath { path, .. }) = ty { - if let Some(seg) = path.segments.last() { - if let syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { - args, - .. - }) = &seg.arguments - { - if let Some(syn::GenericArgument::Type(t)) = &args.first() { - return Some(t); - } - } - } - } - None -} diff --git a/crates/xml/derive/src/de/field.rs b/crates/xml/derive/src/field.rs similarity index 100% rename from crates/xml/derive/src/de/field.rs rename to crates/xml/derive/src/field.rs diff --git a/crates/xml/derive/src/lib.rs b/crates/xml/derive/src/lib.rs index 6674c70..6f2d1ec 100644 --- a/crates/xml/derive/src/lib.rs +++ b/crates/xml/derive/src/lib.rs @@ -1,8 +1,33 @@ use core::panic; use syn::{parse_macro_input, DeriveInput}; -mod de; -use de::{Enum, NamedStruct}; +pub(crate) mod attrs; +mod field; +mod variant; +mod xml_enum; +mod xml_struct; + +pub(crate) use field::Field; +pub(crate) use variant::Variant; +pub(crate) use xml_enum::Enum; +pub(crate) use xml_struct::NamedStruct; + +pub(crate) fn get_generic_type(ty: &syn::Type) -> Option<&syn::Type> { + if let syn::Type::Path(syn::TypePath { path, .. }) = ty { + if let Some(seg) = path.segments.last() { + if let syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { + args, + .. + }) = &seg.arguments + { + if let Some(syn::GenericArgument::Type(t)) = &args.first() { + return Some(t); + } + } + } + } + None +} #[proc_macro_derive(XmlDeserialize, attributes(xml))] pub fn derive_xml_deserialize(input: proc_macro::TokenStream) -> proc_macro::TokenStream { diff --git a/crates/xml/derive/src/de/de_enum.rs b/crates/xml/derive/src/variant.rs similarity index 50% rename from crates/xml/derive/src/de/de_enum.rs rename to crates/xml/derive/src/variant.rs index e407cc0..d024ad0 100644 --- a/crates/xml/derive/src/de/de_enum.rs +++ b/crates/xml/derive/src/variant.rs @@ -1,15 +1,12 @@ -use core::panic; - -use super::{attrs::EnumAttrs, get_generic_type}; -use crate::de::attrs::VariantAttrs; -use darling::{FromDeriveInput, FromVariant}; use heck::ToKebabCase; use quote::quote; -use syn::{DataEnum, DeriveInput, Fields, FieldsUnnamed}; +use syn::{Fields, FieldsUnnamed}; + +use super::{attrs::VariantAttrs, get_generic_type}; pub struct Variant { - variant: syn::Variant, - attrs: VariantAttrs, + pub variant: syn::Variant, + pub attrs: VariantAttrs, } impl Variant { @@ -38,7 +35,7 @@ impl Variant { "struct variants are not supported, please use a tuple variant with a struct" ), Fields::Unit => syn::Type::Path(syn::parse_str("::rustical_xml::Unit").unwrap()), - Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => { + Fields::Unnamed(syn::FieldsUnnamed { unnamed, .. }) => { if unnamed.len() != 1 { panic!("tuple variants should contain exactly one element"); } @@ -176,150 +173,3 @@ impl Variant { }) } } - -pub struct Enum { - attrs: EnumAttrs, - variants: Vec, - ident: syn::Ident, - generics: syn::Generics, -} - -impl Enum { - fn impl_de_untagged(&self) -> proc_macro2::TokenStream { - let (impl_generics, type_generics, where_clause) = self.generics.split_for_impl(); - let name = &self.ident; - - let variant_branches = self - .variants - .iter() - .filter_map(|variant| variant.untagged_branch()); - - quote! { - impl #impl_generics ::rustical_xml::XmlDeserialize for #name #type_generics #where_clause { - fn deserialize( - reader: &mut quick_xml::NsReader, - start: &quick_xml::events::BytesStart, - empty: bool - ) -> Result { - #(#variant_branches);* - - Err(rustical_xml::XmlDeError::UnknownError) - } - } - } - } - - fn impl_de_tagged(&self) -> proc_macro2::TokenStream { - let (impl_generics, type_generics, where_clause) = self.generics.split_for_impl(); - let name = &self.ident; - - let variant_branches = self.variants.iter().filter_map(Variant::tagged_branch); - - quote! { - impl #impl_generics ::rustical_xml::XmlDeserialize for #name #type_generics #where_clause { - fn deserialize( - reader: &mut quick_xml::NsReader, - start: &quick_xml::events::BytesStart, - empty: bool - ) -> Result { - let (_ns, name) = reader.resolve_element(start.name()); - - match name.as_ref() { - #(#variant_branches),* - name => { - // Handle invalid variant name - Err(rustical_xml::XmlDeError::InvalidVariant(String::from_utf8_lossy(name).to_string())) - } - } - } - } - } - } - - pub fn impl_de(&self) -> proc_macro2::TokenStream { - match self.attrs.untagged.is_present() { - true => self.impl_de_untagged(), - false => self.impl_de_tagged(), - } - } - - pub fn parse(input: &DeriveInput, data: &DataEnum) -> Self { - let attrs = EnumAttrs::from_derive_input(input).unwrap(); - - Self { - variants: data - .variants - .iter() - .map(|variant| Variant { - attrs: VariantAttrs::from_variant(variant).unwrap(), - variant: variant.to_owned(), - }) - .collect(), - attrs, - ident: input.ident.to_owned(), - generics: input.generics.to_owned(), - } - } - - pub fn impl_se(&self) -> proc_macro2::TokenStream { - let (impl_generics, type_generics, where_clause) = self.generics.split_for_impl(); - let ident = &self.ident; - - // TODO: Implement attributes - quote! { - impl #impl_generics ::rustical_xml::XmlSerialize for #ident #type_generics #where_clause { - fn serialize( - &self, - tag: Option<&[u8]>, - writer: &mut ::quick_xml::Writer - ) -> ::std::io::Result<()> { - use ::quick_xml::events::{BytesEnd, BytesStart, BytesText, Event}; - - let tag_str = tag.map(String::from_utf8_lossy); - - if let Some(tag) = &tag_str { - writer.write_event(Event::Start(BytesStart::new(tag.to_owned())))?; - } - if let Some(tag) = &tag_str { - writer.write_event(Event::End(BytesEnd::new(tag.to_owned())))?; - } - Ok(()) - } - } - } - } - - pub fn impl_xml_document(&self) -> proc_macro2::TokenStream { - if self.attrs.untagged.is_present() { - panic!("XmlDocument only supported for untagged enums"); - } - let (impl_generics, type_generics, where_clause) = self.generics.split_for_impl(); - let ident = &self.ident; - - quote! { - impl #impl_generics ::rustical_xml::XmlDocument for #ident #type_generics #where_clause { - fn parse(mut reader: ::quick_xml::NsReader) -> Result - where - Self: ::rustical_xml::XmlDeserialize - { - use ::quick_xml::events::Event; - - let mut buf = Vec::new(); - loop { - let event = reader.read_event_into(&mut buf)?; - let empty = matches!(event, Event::Empty(_)); - - match event { - Event::Decl(_) => { /* ignore this */ } - Event::Comment(_) => { /* ignore this */ } - Event::Start(start) | Event::Empty(start) => { - return ::deserialize(&mut reader, &start, empty); - } - _ => return Err(::rustical_xml::XmlDeError::UnknownError), - }; - } - } - } - } - } -} diff --git a/crates/xml/derive/src/xml_enum.rs b/crates/xml/derive/src/xml_enum.rs new file mode 100644 index 0000000..f440085 --- /dev/null +++ b/crates/xml/derive/src/xml_enum.rs @@ -0,0 +1,153 @@ +use super::{attrs::EnumAttrs, Variant}; +use crate::attrs::VariantAttrs; +use core::panic; +use darling::{FromDeriveInput, FromVariant}; +use quote::quote; +use syn::{DataEnum, DeriveInput}; + +pub struct Enum { + attrs: EnumAttrs, + variants: Vec, + ident: syn::Ident, + generics: syn::Generics, +} + +impl Enum { + fn impl_de_untagged(&self) -> proc_macro2::TokenStream { + let (impl_generics, type_generics, where_clause) = self.generics.split_for_impl(); + let name = &self.ident; + + let variant_branches = self + .variants + .iter() + .filter_map(|variant| variant.untagged_branch()); + + quote! { + impl #impl_generics ::rustical_xml::XmlDeserialize for #name #type_generics #where_clause { + fn deserialize( + reader: &mut quick_xml::NsReader, + start: &quick_xml::events::BytesStart, + empty: bool + ) -> Result { + #(#variant_branches);* + + Err(rustical_xml::XmlDeError::UnknownError) + } + } + } + } + + fn impl_de_tagged(&self) -> proc_macro2::TokenStream { + let (impl_generics, type_generics, where_clause) = self.generics.split_for_impl(); + let name = &self.ident; + + let variant_branches = self.variants.iter().filter_map(Variant::tagged_branch); + + quote! { + impl #impl_generics ::rustical_xml::XmlDeserialize for #name #type_generics #where_clause { + fn deserialize( + reader: &mut quick_xml::NsReader, + start: &quick_xml::events::BytesStart, + empty: bool + ) -> Result { + let (_ns, name) = reader.resolve_element(start.name()); + + match name.as_ref() { + #(#variant_branches),* + name => { + // Handle invalid variant name + Err(rustical_xml::XmlDeError::InvalidVariant(String::from_utf8_lossy(name).to_string())) + } + } + } + } + } + } + + pub fn impl_de(&self) -> proc_macro2::TokenStream { + match self.attrs.untagged.is_present() { + true => self.impl_de_untagged(), + false => self.impl_de_tagged(), + } + } + + pub fn parse(input: &DeriveInput, data: &DataEnum) -> Self { + let attrs = EnumAttrs::from_derive_input(input).unwrap(); + + Self { + variants: data + .variants + .iter() + .map(|variant| Variant { + attrs: VariantAttrs::from_variant(variant).unwrap(), + variant: variant.to_owned(), + }) + .collect(), + attrs, + ident: input.ident.to_owned(), + generics: input.generics.to_owned(), + } + } + + pub fn impl_se(&self) -> proc_macro2::TokenStream { + let (impl_generics, type_generics, where_clause) = self.generics.split_for_impl(); + let ident = &self.ident; + + // TODO: Implement attributes + quote! { + impl #impl_generics ::rustical_xml::XmlSerialize for #ident #type_generics #where_clause { + fn serialize( + &self, + tag: Option<&[u8]>, + writer: &mut ::quick_xml::Writer + ) -> ::std::io::Result<()> { + use ::quick_xml::events::{BytesEnd, BytesStart, BytesText, Event}; + + let tag_str = tag.map(String::from_utf8_lossy); + + if let Some(tag) = &tag_str { + writer.write_event(Event::Start(BytesStart::new(tag.to_owned())))?; + } + if let Some(tag) = &tag_str { + writer.write_event(Event::End(BytesEnd::new(tag.to_owned())))?; + } + Ok(()) + } + } + } + } + + pub fn impl_xml_document(&self) -> proc_macro2::TokenStream { + if self.attrs.untagged.is_present() { + panic!("XmlDocument only supported for untagged enums"); + } + let (impl_generics, type_generics, where_clause) = self.generics.split_for_impl(); + let ident = &self.ident; + + quote! { + impl #impl_generics ::rustical_xml::XmlDocument for #ident #type_generics #where_clause { + fn parse(mut reader: ::quick_xml::NsReader) -> Result + where + Self: ::rustical_xml::XmlDeserialize + { + use ::quick_xml::events::Event; + + let mut buf = Vec::new(); + loop { + let event = reader.read_event_into(&mut buf)?; + let empty = matches!(event, Event::Empty(_)); + + match event { + Event::Decl(_) => { /* ignore this */ } + Event::Comment(_) => { /* ignore this */ } + Event::Start(start) | Event::Empty(start) => { + return ::deserialize(&mut reader, &start, empty); + } + _ => return Err(::rustical_xml::XmlDeError::UnknownError), + }; + } + } + } + } + } +} diff --git a/crates/xml/derive/src/de/de_struct.rs b/crates/xml/derive/src/xml_struct.rs similarity index 99% rename from crates/xml/derive/src/de/de_struct.rs rename to crates/xml/derive/src/xml_struct.rs index 1c34290..33b1dcf 100644 --- a/crates/xml/derive/src/de/de_struct.rs +++ b/crates/xml/derive/src/xml_struct.rs @@ -1,5 +1,5 @@ -use crate::de::attrs::StructAttrs; -use crate::de::Field; +use crate::attrs::StructAttrs; +use crate::Field; use core::panic; use darling::FromDeriveInput; use quote::quote;