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 std::num::ParseIntError;
use quick_xml::events::{BytesStart, Event};
use std::num::{ParseFloatError, ParseIntError};
use std::str::FromStr;
use std::{convert::Infallible, io::BufRead};
use thiserror::Error;
use crate::XmlDeError;
use crate::{XmlDeError, XmlDeserialize};
#[derive(Debug, Error)]
pub enum ParseValueError {
@@ -11,6 +12,8 @@ pub enum ParseValueError {
Infallible(#[from] Infallible),
#[error(transparent)]
ParseIntError(#[from] ParseIntError),
#[error(transparent)]
ParseFloatError(#[from] ParseFloatError),
}
pub trait Value: Sized {
@@ -18,16 +21,60 @@ pub trait Value: Sized {
fn deserialize(val: &str) -> Result<Self, XmlDeError>;
}
impl<E, T: FromStr<Err = E> + ToString> Value for T
where
ParseValueError: From<E>,
{
fn serialize(&self) -> String {
self.to_string()
}
fn deserialize(val: &str) -> Result<Self, XmlDeError> {
val.parse()
.map_err(ParseValueError::from)
.map_err(XmlDeError::from)
macro_rules! impl_value_parse {
($t:ty) => {
impl Value for $t {
fn serialize(&self) -> String {
self.to_string()
}
fn deserialize(val: &str) -> Result<Self, XmlDeError> {
val.parse()
.map_err(ParseValueError::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();
}
#[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()
}
);
}