From d5c66ed233b0a3bef43dbd35e291dbbad0afd297 Mon Sep 17 00:00:00 2001 From: Lennart <18233294+lennart-k@users.noreply.github.com> Date: Wed, 15 Jan 2025 18:24:23 +0100 Subject: [PATCH] xml: Some restructuring --- crates/xml/derive/src/attrs.rs | 3 +- crates/xml/derive/src/common.rs | 16 ++++++ crates/xml/derive/src/field.rs | 2 +- crates/xml/derive/src/lib.rs | 19 +------ crates/xml/src/de.rs | 20 ++++++++ crates/xml/src/lib.rs | 91 ++------------------------------- crates/xml/src/se.rs | 50 ++++++++++++++++-- crates/xml/src/unparsed.rs | 31 +++++++++++ crates/xml/src/value.rs | 17 +++--- 9 files changed, 128 insertions(+), 121 deletions(-) create mode 100644 crates/xml/derive/src/common.rs create mode 100644 crates/xml/src/unparsed.rs diff --git a/crates/xml/derive/src/attrs.rs b/crates/xml/derive/src/attrs.rs index 0c5b39b..2cb17aa 100644 --- a/crates/xml/derive/src/attrs.rs +++ b/crates/xml/derive/src/attrs.rs @@ -28,7 +28,8 @@ pub struct VariantAttrs { #[darling(attributes(xml))] pub struct EnumAttrs { #[darling(flatten)] - pub container: ContainerAttrs, + // TODO: implement ns_strict + pub _container: ContainerAttrs, pub untagged: Flag, } diff --git a/crates/xml/derive/src/common.rs b/crates/xml/derive/src/common.rs new file mode 100644 index 0000000..6657a0b --- /dev/null +++ b/crates/xml/derive/src/common.rs @@ -0,0 +1,16 @@ +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 +} diff --git a/crates/xml/derive/src/field.rs b/crates/xml/derive/src/field.rs index 9973c2a..5f5aa39 100644 --- a/crates/xml/derive/src/field.rs +++ b/crates/xml/derive/src/field.rs @@ -324,7 +324,7 @@ impl Field { (FieldType::Untagged, false) => Some(quote! { #serializer(&self.#target_field_index, None, None, namespaces, writer)?; }), - // TODO: Think about what to do here + // We ignore this :) (FieldType::TagName | FieldType::Namespace, _) => None, } } diff --git a/crates/xml/derive/src/lib.rs b/crates/xml/derive/src/lib.rs index 6f2d1ec..4b6759c 100644 --- a/crates/xml/derive/src/lib.rs +++ b/crates/xml/derive/src/lib.rs @@ -2,33 +2,18 @@ use core::panic; use syn::{parse_macro_input, DeriveInput}; pub(crate) mod attrs; +mod common; mod field; mod variant; mod xml_enum; mod xml_struct; +pub(crate) use common::*; 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 { let input = parse_macro_input!(input as DeriveInput); diff --git a/crates/xml/src/de.rs b/crates/xml/src/de.rs index fcdcb3f..2c52a1b 100644 --- a/crates/xml/src/de.rs +++ b/crates/xml/src/de.rs @@ -72,3 +72,23 @@ impl XmlDocument for T { } } } + +impl XmlDeserialize for () { + fn deserialize( + reader: &mut quick_xml::NsReader, + start: &BytesStart, + empty: bool, + ) -> Result { + if empty { + return Ok(()); + } + let mut buf = Vec::new(); + loop { + match reader.read_event_into(&mut buf)? { + Event::End(e) if e.name() == start.name() => return Ok(()), + Event::Eof => return Err(XmlError::Eof), + _ => {} + }; + } + } +} diff --git a/crates/xml/src/lib.rs b/crates/xml/src/lib.rs index a5481f2..c65cbe9 100644 --- a/crates/xml/src/lib.rs +++ b/crates/xml/src/lib.rs @@ -1,11 +1,10 @@ -use quick_xml::events::{BytesStart, Event}; -use quick_xml::name::{Namespace, QName}; +use quick_xml::name::Namespace; use std::collections::HashMap; -use std::io::BufRead; pub mod de; mod error; pub mod se; +mod unparsed; mod value; pub use de::XmlDeserialize; @@ -13,94 +12,10 @@ pub use de::XmlDocument; pub use error::XmlError; pub use se::XmlSerialize; pub use se::XmlSerializeRoot; +pub use unparsed::Unparsed; pub use value::{ParseValueError, ValueDeserialize, ValueSerialize}; pub use xml_derive::XmlRootTag; -impl XmlDeserialize for () { - fn deserialize( - reader: &mut quick_xml::NsReader, - start: &BytesStart, - empty: bool, - ) -> Result { - if empty { - return Ok(()); - } - let mut buf = Vec::new(); - loop { - match reader.read_event_into(&mut buf)? { - Event::End(e) if e.name() == start.name() => return Ok(()), - Event::Eof => return Err(XmlError::Eof), - _ => {} - }; - } - } -} - -impl XmlSerialize for () { - fn serialize( - &self, - ns: Option, - tag: Option<&[u8]>, - namespaces: &HashMap, - writer: &mut quick_xml::Writer, - ) -> std::io::Result<()> { - let prefix = ns - .map(|ns| namespaces.get(&ns)) - .unwrap_or(None) - .map(|prefix| { - if !prefix.is_empty() { - [*prefix, b":"].concat() - } else { - Vec::new() - } - }); - let has_prefix = prefix.is_some(); - let tagname = tag.map(|tag| [&prefix.unwrap_or_default(), tag].concat()); - let qname = tagname.as_ref().map(|tagname| QName(tagname)); - if let Some(qname) = &qname { - let mut bytes_start = BytesStart::from(qname.to_owned()); - if !has_prefix { - if let Some(ns) = &ns { - bytes_start.push_attribute((b"xmlns".as_ref(), ns.as_ref())); - } - } - writer.write_event(Event::Empty(bytes_start))?; - } - Ok(()) - } - - #[allow(refining_impl_trait)] - fn attributes<'a>(&self) -> Option>> { - None - } -} - -// TODO: actually implement -#[derive(Debug, Clone, PartialEq)] -pub struct Unparsed(BytesStart<'static>); - -impl Unparsed { - pub fn tag_name(&self) -> String { - // TODO: respect namespace? - String::from_utf8_lossy(self.0.local_name().as_ref()).to_string() - } -} - -impl XmlDeserialize for Unparsed { - fn deserialize( - reader: &mut quick_xml::NsReader, - start: &BytesStart, - empty: bool, - ) -> Result { - // let reader_cloned = NsReader::from_reader(reader.get_ref().to_owned()); - if !empty { - let mut buf = vec![]; - reader.read_to_end_into(start.name(), &mut buf)?; - } - Ok(Self(start.to_owned())) - } -} - pub trait XmlRootTag { fn root_tag() -> &'static [u8]; fn root_ns() -> Option>; diff --git a/crates/xml/src/se.rs b/crates/xml/src/se.rs index 9283223..a790b9a 100644 --- a/crates/xml/src/se.rs +++ b/crates/xml/src/se.rs @@ -1,9 +1,10 @@ -use std::collections::HashMap; - -use quick_xml::{events::attributes::Attribute, name::Namespace}; -pub use xml_derive::XmlSerialize; - use crate::XmlRootTag; +use quick_xml::{ + events::{attributes::Attribute, BytesStart, Event}, + name::{Namespace, QName}, +}; +use std::collections::HashMap; +pub use xml_derive::XmlSerialize; pub trait XmlSerialize { fn serialize( @@ -54,3 +55,42 @@ impl XmlSerializeRoot for T { self.serialize(Self::root_ns(), Some(Self::root_tag()), &namespaces, writer) } } + +impl XmlSerialize for () { + fn serialize( + &self, + ns: Option, + tag: Option<&[u8]>, + namespaces: &HashMap, + writer: &mut quick_xml::Writer, + ) -> std::io::Result<()> { + let prefix = ns + .map(|ns| namespaces.get(&ns)) + .unwrap_or(None) + .map(|prefix| { + if !prefix.is_empty() { + [*prefix, b":"].concat() + } else { + Vec::new() + } + }); + let has_prefix = prefix.is_some(); + let tagname = tag.map(|tag| [&prefix.unwrap_or_default(), tag].concat()); + let qname = tagname.as_ref().map(|tagname| QName(tagname)); + if let Some(qname) = &qname { + let mut bytes_start = BytesStart::from(qname.to_owned()); + if !has_prefix { + if let Some(ns) = &ns { + bytes_start.push_attribute((b"xmlns".as_ref(), ns.as_ref())); + } + } + writer.write_event(Event::Empty(bytes_start))?; + } + Ok(()) + } + + #[allow(refining_impl_trait)] + fn attributes<'a>(&self) -> Option>> { + None + } +} diff --git a/crates/xml/src/unparsed.rs b/crates/xml/src/unparsed.rs new file mode 100644 index 0000000..bdb371e --- /dev/null +++ b/crates/xml/src/unparsed.rs @@ -0,0 +1,31 @@ +use std::io::BufRead; + +use quick_xml::events::BytesStart; + +use crate::{XmlDeserialize, XmlError}; + +// TODO: actually implement +#[derive(Debug, Clone, PartialEq)] +pub struct Unparsed(BytesStart<'static>); + +impl Unparsed { + pub fn tag_name(&self) -> String { + // TODO: respect namespace? + String::from_utf8_lossy(self.0.local_name().as_ref()).to_string() + } +} + +impl XmlDeserialize for Unparsed { + fn deserialize( + reader: &mut quick_xml::NsReader, + start: &BytesStart, + empty: bool, + ) -> Result { + // let reader_cloned = NsReader::from_reader(reader.get_ref().to_owned()); + if !empty { + let mut buf = vec![]; + reader.read_to_end_into(start.name(), &mut buf)?; + } + Ok(Self(start.to_owned())) + } +} diff --git a/crates/xml/src/value.rs b/crates/xml/src/value.rs index e9f0966..6363c9f 100644 --- a/crates/xml/src/value.rs +++ b/crates/xml/src/value.rs @@ -1,3 +1,4 @@ +use crate::{XmlDeserialize, XmlError, XmlSerialize}; use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event}; use quick_xml::name::{Namespace, QName}; use std::collections::HashMap; @@ -5,7 +6,13 @@ use std::num::{ParseFloatError, ParseIntError}; use std::{convert::Infallible, io::BufRead}; use thiserror::Error; -use crate::{XmlError, XmlDeserialize, XmlSerialize}; +pub trait ValueSerialize { + fn serialize(&self) -> String; +} + +pub trait ValueDeserialize: Sized { + fn deserialize(val: &str) -> Result; +} #[derive(Debug, Error)] pub enum ParseValueError { @@ -17,14 +24,6 @@ pub enum ParseValueError { ParseFloatError(#[from] ParseFloatError), } -pub trait ValueSerialize: Sized { - fn serialize(&self) -> String; -} - -pub trait ValueDeserialize: Sized { - fn deserialize(val: &str) -> Result; -} - macro_rules! impl_value_parse { ($t:ty) => { impl ValueSerialize for $t {