Skip to content

Commit

Permalink
xml: Some restructuring
Browse files Browse the repository at this point in the history
  • Loading branch information
lennart-k committed Jan 15, 2025
1 parent d74f0ba commit d5c66ed
Show file tree
Hide file tree
Showing 9 changed files with 127 additions and 120 deletions.
3 changes: 2 additions & 1 deletion crates/xml/derive/src/attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}

Expand Down
16 changes: 16 additions & 0 deletions crates/xml/derive/src/common.rs
Original file line number Diff line number Diff line change
@@ -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
}
2 changes: 1 addition & 1 deletion crates/xml/derive/src/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
}
Expand Down
19 changes: 2 additions & 17 deletions crates/xml/derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
20 changes: 20 additions & 0 deletions crates/xml/src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
_ => {}
};
}
}
}
91 changes: 3 additions & 88 deletions crates/xml/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,106 +1,21 @@
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;
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<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 {
fn root_tag() -> &'static [u8];
fn root_ns() -> Option<Namespace<'static>>;
Expand Down
48 changes: 44 additions & 4 deletions crates/xml/src/se.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use crate::XmlRootTag;
use quick_xml::{
events::{attributes::Attribute, BytesStart, Event},
name::{Namespace, QName},
};
use std::collections::HashMap;

use quick_xml::{events::attributes::Attribute, name::Namespace};
pub use xml_derive::XmlSerialize;

use crate::XmlRootTag;

pub trait XmlSerialize {
fn serialize<W: std::io::Write>(
&self,
Expand Down Expand Up @@ -54,3 +55,42 @@ impl<T: XmlSerialize + XmlRootTag> XmlSerializeRoot for T {
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
}
}
31 changes: 31 additions & 0 deletions crates/xml/src/unparsed.rs
Original file line number Diff line number Diff line change
@@ -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()))
}
}
17 changes: 8 additions & 9 deletions crates/xml/src/value.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
use crate::{XmlDeserialize, XmlError, XmlSerialize};
use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event};
use quick_xml::name::{Namespace, QName};
use std::collections::HashMap;
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<Self, XmlError>;
}

#[derive(Debug, Error)]
pub enum ParseValueError {
Expand All @@ -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<Self, XmlError>;
}

macro_rules! impl_value_parse {
($t:ty) => {
impl ValueSerialize for $t {
Expand Down

0 comments on commit d5c66ed

Please sign in to comment.