Skip to main content

rustical_xml/
value.rs

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