mirror of
https://github.com/lennart-k/rustical.git
synced 2025-12-13 18:12:27 +00:00
xml: Some restructuring
This commit is contained in:
@@ -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,
|
||||
}
|
||||
|
||||
|
||||
16
crates/xml/derive/src/common.rs
Normal file
16
crates/xml/derive/src/common.rs
Normal 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
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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),
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<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>>;
|
||||
|
||||
@@ -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<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)
|
||||
}
|
||||
}
|
||||
|
||||
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
crates/xml/src/unparsed.rs
Normal file
31
crates/xml/src/unparsed.rs
Normal 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()))
|
||||
}
|
||||
}
|
||||
@@ -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<Self, XmlError>;
|
||||
}
|
||||
|
||||
#[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<Self, XmlError>;
|
||||
}
|
||||
|
||||
macro_rules! impl_value_parse {
|
||||
($t:ty) => {
|
||||
impl ValueSerialize for $t {
|
||||
|
||||
Reference in New Issue
Block a user