mirror of
https://github.com/lennart-k/rustical.git
synced 2025-12-13 22:52:22 +00:00
xml: Some restructuring
This commit is contained in:
@@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
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! {
|
(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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
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>>;
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
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::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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user