xml: Implement XmlDeserialize for values

This commit is contained in:
Lennart
2024-12-23 13:45:46 +01:00
parent 98ed1a3fc5
commit 8e0a25b223
2 changed files with 85 additions and 14 deletions

View File

@@ -1,9 +1,10 @@
use std::convert::Infallible; use quick_xml::events::{BytesStart, Event};
use std::num::ParseIntError; use std::num::{ParseFloatError, ParseIntError};
use std::str::FromStr; use std::str::FromStr;
use std::{convert::Infallible, io::BufRead};
use thiserror::Error; use thiserror::Error;
use crate::XmlDeError; use crate::{XmlDeError, XmlDeserialize};
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum ParseValueError { pub enum ParseValueError {
@@ -11,6 +12,8 @@ pub enum ParseValueError {
Infallible(#[from] Infallible), Infallible(#[from] Infallible),
#[error(transparent)] #[error(transparent)]
ParseIntError(#[from] ParseIntError), ParseIntError(#[from] ParseIntError),
#[error(transparent)]
ParseFloatError(#[from] ParseFloatError),
} }
pub trait Value: Sized { pub trait Value: Sized {
@@ -18,16 +21,60 @@ pub trait Value: Sized {
fn deserialize(val: &str) -> Result<Self, XmlDeError>; fn deserialize(val: &str) -> Result<Self, XmlDeError>;
} }
impl<E, T: FromStr<Err = E> + ToString> Value for T macro_rules! impl_value_parse {
where ($t:ty) => {
ParseValueError: From<E>, impl Value for $t {
{
fn serialize(&self) -> String { fn serialize(&self) -> String {
self.to_string() self.to_string()
} }
fn deserialize(val: &str) -> Result<Self, XmlDeError> { fn deserialize(val: &str) -> Result<Self, XmlDeError> {
val.parse() val.parse()
.map_err(ParseValueError::from) .map_err(ParseValueError::from)
.map_err(XmlDeError::from) .map_err(XmlDeError::from)
} }
} }
};
}
impl_value_parse!(String);
impl_value_parse!(i8);
impl_value_parse!(u8);
impl_value_parse!(i16);
impl_value_parse!(u16);
impl_value_parse!(f32);
impl_value_parse!(i32);
impl_value_parse!(u32);
impl_value_parse!(f64);
impl_value_parse!(i64);
impl_value_parse!(u64);
impl_value_parse!(isize);
impl_value_parse!(usize);
impl<T: Value> XmlDeserialize for T {
fn deserialize<R: BufRead>(
reader: &mut quick_xml::NsReader<R>,
start: &BytesStart,
empty: bool,
) -> Result<Self, XmlDeError> {
let mut string = String::new();
if !empty {
let mut buf = Vec::new();
loop {
match reader.read_event_into(&mut buf)? {
Event::Text(text) => {
if !start.is_empty() {
// Content already written
return Err(XmlDeError::UnsupportedEvent("todo"));
}
string = String::from_utf8_lossy(text.as_ref()).to_string();
}
_ => return Err(XmlDeError::UnsupportedEvent("todo")),
};
}
}
<Self as Value>::deserialize(&string)
}
}

View File

@@ -229,3 +229,27 @@ fn test_struct_unparsed() {
) )
.unwrap(); .unwrap();
} }
#[test]
fn test_xml_values() {
#[derive(XmlDeserialize, XmlRootTag, PartialEq, Debug)]
#[xml(root = b"document", ns_strict)]
struct Document {
href: String,
}
let doc = Document::parse_str(
r#"
<document>
<href>/asd</href>
</document>
"#,
)
.unwrap();
assert_eq!(
doc,
Document {
href: "/asd".to_owned()
}
);
}