From 98ed1a3fc50422e7f239ed82412b305c6712169f Mon Sep 17 00:00:00 2001 From: Lennart <18233294+lennart-k@users.noreply.github.com> Date: Mon, 23 Dec 2024 13:02:59 +0100 Subject: [PATCH] xml: Implement XmlDocument for tagged enums and fix small bug --- crates/xml/derive/src/de/de_enum.rs | 33 +++++++++++++++++++++++++++++ crates/xml/derive/src/lib.rs | 12 +++++++++++ crates/xml/src/de.rs | 3 ++- crates/xml/src/lib.rs | 1 + crates/xml/tests/de_enum.rs | 17 +++++++++++++++ 5 files changed, 65 insertions(+), 1 deletion(-) diff --git a/crates/xml/derive/src/de/de_enum.rs b/crates/xml/derive/src/de/de_enum.rs index 8e22b64..fc548e9 100644 --- a/crates/xml/derive/src/de/de_enum.rs +++ b/crates/xml/derive/src/de/de_enum.rs @@ -1,3 +1,5 @@ +use core::panic; + use super::attrs::EnumAttrs; use crate::de::attrs::VariantAttrs; use darling::{FromDeriveInput, FromVariant}; @@ -219,4 +221,35 @@ impl Enum { } } } + + 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(); + let event = reader.read_event_into(&mut buf)?; + let empty = matches!(event, Event::Empty(_)); + + match event { + Event::Start(start) | Event::Empty(start) => { + return Self::deserialize(&mut reader, &start, empty); + } + _ => {} + }; + Err(::rustical_xml::XmlDeError::UnknownError) + } + } + } + } } diff --git a/crates/xml/derive/src/lib.rs b/crates/xml/derive/src/lib.rs index 862cabf..6674c70 100644 --- a/crates/xml/derive/src/lib.rs +++ b/crates/xml/derive/src/lib.rs @@ -39,3 +39,15 @@ pub fn derive_xml_root_tag(input: proc_macro::TokenStream) -> proc_macro::TokenS } .into() } + +#[proc_macro_derive(XmlDocument, attributes(xml))] +pub fn derive_xml_document(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let input = parse_macro_input!(input as DeriveInput); + + match &input.data { + syn::Data::Struct(_) => panic!("Struct not supported, use XmlRootTag instead"), + syn::Data::Enum(e) => Enum::parse(&input, e).impl_xml_document(), + syn::Data::Union(_) => panic!("Union not supported as root"), + } + .into() +} diff --git a/crates/xml/src/de.rs b/crates/xml/src/de.rs index 546ee76..513d179 100644 --- a/crates/xml/src/de.rs +++ b/crates/xml/src/de.rs @@ -2,6 +2,7 @@ use quick_xml::name::Namespace; use quick_xml::name::ResolveResult; use std::io::BufRead; pub use xml_derive::XmlDeserialize; +pub use xml_derive::XmlDocument; pub use xml_derive::XmlRootTag; use quick_xml::events::{BytesStart, Event}; @@ -74,7 +75,7 @@ impl XmlDocument for T { { let mut buf = Vec::new(); let event = reader.read_event_into(&mut buf)?; - let empty = event.is_empty(); + let empty = matches!(event, Event::Empty(_)); match event { Event::Start(start) | Event::Empty(start) => { let (ns, name) = reader.resolve_element(start.name()); diff --git a/crates/xml/src/lib.rs b/crates/xml/src/lib.rs index 2b8896d..62997df 100644 --- a/crates/xml/src/lib.rs +++ b/crates/xml/src/lib.rs @@ -7,6 +7,7 @@ mod value; pub use de::XmlDeError; pub use de::XmlDeserialize; +pub use de::XmlDocument; pub use de::XmlRootTag; pub use se::XmlSerialize; pub use value::Value; diff --git a/crates/xml/tests/de_enum.rs b/crates/xml/tests/de_enum.rs index bcc93b4..67dabba 100644 --- a/crates/xml/tests/de_enum.rs +++ b/crates/xml/tests/de_enum.rs @@ -96,3 +96,20 @@ fn test_tagged_enum_complex() { .unwrap(); dbg!(asd); } + +#[test] +fn test_enum_document() { + #[derive(Debug, XmlDeserialize, XmlDocument, PartialEq)] + enum Document { + Hello, + Goodbye, + } + assert_eq!( + Document::parse_str(r"").unwrap(), + Document::Hello + ); + assert_eq!( + Document::parse_str(r"").unwrap(), + Document::Goodbye + ); +}