xml: Some restructuring

This commit is contained in:
Lennart
2025-01-15 18:24:23 +01:00
parent d74f0ba660
commit d5c66ed233
9 changed files with 128 additions and 121 deletions

View File

@@ -28,7 +28,8 @@ pub struct VariantAttrs {
#[darling(attributes(xml))] #[darling(attributes(xml))]
pub struct EnumAttrs { pub struct EnumAttrs {
#[darling(flatten)] #[darling(flatten)]
pub container: ContainerAttrs, // TODO: implement ns_strict
pub _container: ContainerAttrs,
pub untagged: Flag, pub untagged: Flag,
} }

View File

@@ -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
}

View File

@@ -324,7 +324,7 @@ impl Field {
(FieldType::Untagged, false) => Some(quote! { (FieldType::Untagged, false) => Some(quote! {
#serializer(&self.#target_field_index, None, None, namespaces, writer)?; #serializer(&self.#target_field_index, None, None, namespaces, writer)?;
}), }),
// TODO: Think about what to do here // We ignore this :)
(FieldType::TagName | FieldType::Namespace, _) => None, (FieldType::TagName | FieldType::Namespace, _) => None,
} }
} }

View File

@@ -2,33 +2,18 @@ use core::panic;
use syn::{parse_macro_input, DeriveInput}; use syn::{parse_macro_input, DeriveInput};
pub(crate) mod attrs; pub(crate) mod attrs;
mod common;
mod field; mod field;
mod variant; mod variant;
mod xml_enum; mod xml_enum;
mod xml_struct; mod xml_struct;
pub(crate) use common::*;
pub(crate) use field::Field; pub(crate) use field::Field;
pub(crate) use variant::Variant; pub(crate) use variant::Variant;
pub(crate) use xml_enum::Enum; pub(crate) use xml_enum::Enum;
pub(crate) use xml_struct::NamedStruct; 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))] #[proc_macro_derive(XmlDeserialize, attributes(xml))]
pub fn derive_xml_deserialize(input: proc_macro::TokenStream) -> proc_macro::TokenStream { pub fn derive_xml_deserialize(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput); let input = parse_macro_input!(input as DeriveInput);

View File

@@ -72,3 +72,23 @@ impl<T: XmlRootTag + XmlDeserialize> XmlDocument for T {
} }
} }
} }
impl XmlDeserialize for () {
fn deserialize<R: BufRead>(
reader: &mut quick_xml::NsReader<R>,
start: &BytesStart,
empty: bool,
) -> Result<Self, XmlError> {
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),
_ => {}
};
}
}
}

View File

@@ -1,11 +1,10 @@
use quick_xml::events::{BytesStart, Event}; use quick_xml::name::Namespace;
use quick_xml::name::{Namespace, QName};
use std::collections::HashMap; use std::collections::HashMap;
use std::io::BufRead;
pub mod de; pub mod de;
mod error; mod error;
pub mod se; pub mod se;
mod unparsed;
mod value; mod value;
pub use de::XmlDeserialize; pub use de::XmlDeserialize;
@@ -13,94 +12,10 @@ pub use de::XmlDocument;
pub use error::XmlError; pub use error::XmlError;
pub use se::XmlSerialize; pub use se::XmlSerialize;
pub use se::XmlSerializeRoot; pub use se::XmlSerializeRoot;
pub use unparsed::Unparsed;
pub use value::{ParseValueError, ValueDeserialize, ValueSerialize}; pub use value::{ParseValueError, ValueDeserialize, ValueSerialize};
pub use xml_derive::XmlRootTag; pub use xml_derive::XmlRootTag;
impl XmlDeserialize for () {
fn deserialize<R: BufRead>(
reader: &mut quick_xml::NsReader<R>,
start: &BytesStart,
empty: bool,
) -> Result<Self, XmlError> {
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<W: std::io::Write>(
&self,
ns: Option<Namespace>,
tag: Option<&[u8]>,
namespaces: &HashMap<Namespace, &[u8]>,
writer: &mut quick_xml::Writer<W>,
) -> 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<Vec<quick_xml::events::attributes::Attribute<'a>>> {
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<R: BufRead>(
reader: &mut quick_xml::NsReader<R>,
start: &BytesStart,
empty: bool,
) -> Result<Self, XmlError> {
// 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 { pub trait XmlRootTag {
fn root_tag() -> &'static [u8]; fn root_tag() -> &'static [u8];
fn root_ns() -> Option<Namespace<'static>>; fn root_ns() -> Option<Namespace<'static>>;

View File

@@ -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 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 { pub trait XmlSerialize {
fn serialize<W: std::io::Write>( fn serialize<W: std::io::Write>(
@@ -54,3 +55,42 @@ impl<T: XmlSerialize + XmlRootTag> XmlSerializeRoot for T {
self.serialize(Self::root_ns(), Some(Self::root_tag()), &namespaces, writer) self.serialize(Self::root_ns(), Some(Self::root_tag()), &namespaces, writer)
} }
} }
impl XmlSerialize for () {
fn serialize<W: std::io::Write>(
&self,
ns: Option<Namespace>,
tag: Option<&[u8]>,
namespaces: &HashMap<Namespace, &[u8]>,
writer: &mut quick_xml::Writer<W>,
) -> 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<Vec<quick_xml::events::attributes::Attribute<'a>>> {
None
}
}

View File

@@ -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<R: BufRead>(
reader: &mut quick_xml::NsReader<R>,
start: &BytesStart,
empty: bool,
) -> Result<Self, XmlError> {
// 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()))
}
}

View File

@@ -1,3 +1,4 @@
use crate::{XmlDeserialize, XmlError, XmlSerialize};
use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event}; use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event};
use quick_xml::name::{Namespace, QName}; use quick_xml::name::{Namespace, QName};
use std::collections::HashMap; use std::collections::HashMap;
@@ -5,7 +6,13 @@ use std::num::{ParseFloatError, ParseIntError};
use std::{convert::Infallible, io::BufRead}; use std::{convert::Infallible, io::BufRead};
use thiserror::Error; use thiserror::Error;
use crate::{XmlError, XmlDeserialize, XmlSerialize}; pub trait ValueSerialize {
fn serialize(&self) -> String;
}
pub trait ValueDeserialize: Sized {
fn deserialize(val: &str) -> Result<Self, XmlError>;
}
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum ParseValueError { pub enum ParseValueError {
@@ -17,14 +24,6 @@ pub enum ParseValueError {
ParseFloatError(#[from] ParseFloatError), ParseFloatError(#[from] ParseFloatError),
} }
pub trait ValueSerialize: Sized {
fn serialize(&self) -> String;
}
pub trait ValueDeserialize: Sized {
fn deserialize(val: &str) -> Result<Self, XmlError>;
}
macro_rules! impl_value_parse { macro_rules! impl_value_parse {
($t:ty) => { ($t:ty) => {
impl ValueSerialize for $t { impl ValueSerialize for $t {