rustical_xml/
value.rs

1use crate::{XmlDeserialize, XmlError, XmlSerialize};
2use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event};
3use quick_xml::name::Namespace;
4use std::collections::HashMap;
5use std::num::{ParseFloatError, ParseIntError};
6use std::{convert::Infallible, io::BufRead};
7use thiserror::Error;
8
9pub trait ValueSerialize {
10    fn serialize(&self) -> String;
11}
12
13pub trait ValueDeserialize: Sized {
14    fn deserialize(val: &str) -> Result<Self, XmlError>;
15}
16
17#[derive(Debug, Error)]
18pub enum ParseValueError {
19    #[error(transparent)]
20    Infallible(#[from] Infallible),
21    #[error(transparent)]
22    ParseIntError(#[from] ParseIntError),
23    #[error(transparent)]
24    ParseFloatError(#[from] ParseFloatError),
25    #[error("{0}")]
26    Other(String),
27}
28
29macro_rules! impl_value_parse {
30    ($t:ty) => {
31        impl ValueSerialize for $t {
32            fn serialize(&self) -> String {
33                self.to_string()
34            }
35        }
36
37        impl ValueDeserialize for $t {
38            fn deserialize(val: &str) -> Result<Self, XmlError> {
39                val.parse()
40                    .map_err(ParseValueError::from)
41                    .map_err(XmlError::from)
42            }
43        }
44    };
45}
46
47impl_value_parse!(String);
48impl_value_parse!(i8);
49impl_value_parse!(u8);
50impl_value_parse!(i16);
51impl_value_parse!(u16);
52impl_value_parse!(f32);
53impl_value_parse!(i32);
54impl_value_parse!(u32);
55impl_value_parse!(f64);
56impl_value_parse!(i64);
57impl_value_parse!(u64);
58impl_value_parse!(isize);
59impl_value_parse!(usize);
60
61impl ValueSerialize for &str {
62    fn serialize(&self) -> String {
63        (*self).to_string()
64    }
65}
66
67impl<T: ValueDeserialize> XmlDeserialize for T {
68    fn deserialize<R: BufRead>(
69        reader: &mut quick_xml::NsReader<R>,
70        _start: &BytesStart,
71        empty: bool,
72    ) -> Result<Self, XmlError> {
73        let mut string = String::new();
74
75        if !empty {
76            let mut buf = Vec::new();
77            loop {
78                match reader.read_event_into(&mut buf)? {
79                    Event::Text(bytes_text) => {
80                        let text = bytes_text.decode()?;
81                        string.push_str(&text);
82                    }
83                    Event::CData(cdata) => {
84                        let text = String::from_utf8(cdata.to_vec())?;
85                        string.push_str(&text);
86                    }
87                    Event::GeneralRef(gref) => {
88                        if let Some(char) = gref.resolve_char_ref()? {
89                            string.push(char);
90                        } else if let Some(text) =
91                            quick_xml::escape::resolve_xml_entity(&gref.xml_content()?)
92                        {
93                            string.push_str(text);
94                        } else {
95                            return Err(XmlError::UnsupportedEvent("invalid XML ref"));
96                        }
97                    }
98                    Event::End(_) => break,
99                    Event::Eof => return Err(XmlError::Eof),
100                    _ => return Err(XmlError::UnsupportedEvent("todo")),
101                }
102            }
103        }
104
105        ValueDeserialize::deserialize(&string)
106    }
107}
108
109impl<T: ValueSerialize> XmlSerialize for T {
110    fn serialize(
111        &self,
112        ns: Option<Namespace>,
113        tag: Option<&str>,
114        namespaces: &HashMap<Namespace, &str>,
115        writer: &mut quick_xml::Writer<&mut Vec<u8>>,
116    ) -> std::io::Result<()> {
117        let prefix = ns.and_then(|ns| namespaces.get(&ns)).map(|prefix| {
118            if prefix.is_empty() {
119                String::new()
120            } else {
121                [*prefix, ":"].concat()
122            }
123        });
124        let has_prefix = prefix.is_some();
125        let tagname = tag.map(|tag| [&prefix.unwrap_or_default(), tag].concat());
126        if let Some(tagname) = tagname.as_ref() {
127            let mut bytes_start = BytesStart::new(tagname);
128            if !has_prefix && let Some(ns) = &ns {
129                bytes_start.push_attribute((b"xmlns".as_ref(), ns.as_ref()));
130            }
131            writer.write_event(Event::Start(bytes_start))?;
132        }
133        writer.write_event(Event::Text(BytesText::new(&self.serialize())))?;
134        if let Some(tagname) = tagname {
135            writer.write_event(Event::End(BytesEnd::new(tagname)))?;
136        }
137        Ok(())
138    }
139
140    fn attributes<'a>(&self) -> Option<Vec<quick_xml::events::attributes::Attribute<'a>>> {
141        None
142    }
143}