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(text) => {
96                        string.push_str(&text);
97                    }
98                    Event::CData(cdata) => {
99                        string.push_str(&cdata);
100                    }
101                    Event::GeneralRef(gref) => {
102                        if let Some(char) = gref.resolve_char_ref()? {
103                            string.push(char);
104                        } else if let Some(text) =
105                            quick_xml::escape::resolve_xml_entity(&gref.xml11_content())
106                        {
107                            string.push_str(text);
108                        } else {
109                            return Err(XmlError::UnsupportedEvent("invalid XML ref"));
110                        }
111                    }
112                    Event::End(_) => break,
113                    Event::Eof => return Err(XmlError::Eof),
114                    _ => return Err(XmlError::UnsupportedEvent("todo")),
115                }
116            }
117        }
118
119        ValueDeserialize::deserialize(&string)
120    }
121}
122
123impl<T: ValueSerialize> XmlSerialize for T {
124    fn serialize(
125        &self,
126        ns: Option<Namespace>,
127        tag: Option<&str>,
128        namespaces: &HashMap<Namespace, &str>,
129        writer: &mut quick_xml::Writer<&mut Vec<u8>>,
130    ) -> std::io::Result<()> {
131        let prefix = ns.and_then(|ns| namespaces.get(&ns)).map(|prefix| {
132            if prefix.is_empty() {
133                String::new()
134            } else {
135                [*prefix, ":"].concat()
136            }
137        });
138        let has_prefix = prefix.is_some();
139        let tagname = tag.map(|tag| [&prefix.unwrap_or_default(), tag].concat());
140        if let Some(tagname) = tagname.as_ref() {
141            let mut bytes_start = BytesStart::new(tagname);
142            if !has_prefix && let Some(ns) = &ns {
143                bytes_start.push_attribute(("xmlns", ns.as_ref()));
144            }
145            writer.write_event(Event::Start(bytes_start))?;
146        }
147        writer.write_event(Event::Text(BytesText::new(&self.serialize())))?;
148        if let Some(tagname) = tagname {
149            writer.write_event(Event::End(BytesEnd::new(tagname)))?;
150        }
151        Ok(())
152    }
153
154    fn attributes<'a>(&self) -> Option<Vec<quick_xml::events::attributes::Attribute<'a>>> {
155        None
156    }
157}