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
118            .map(|ns| namespaces.get(&ns))
119            .unwrap_or(None)
120            .map(|prefix| {
121                if !prefix.is_empty() {
122                    [*prefix, ":"].concat()
123                } else {
124                    String::new()
125                }
126            });
127        let has_prefix = prefix.is_some();
128        let tagname = tag.map(|tag| [&prefix.unwrap_or_default(), tag].concat());
129        if let Some(tagname) = tagname.as_ref() {
130            let mut bytes_start = BytesStart::new(tagname);
131            if !has_prefix && let Some(ns) = &ns {
132                bytes_start.push_attribute((b"xmlns".as_ref(), ns.as_ref()));
133            }
134            writer.write_event(Event::Start(bytes_start))?;
135        }
136        writer.write_event(Event::Text(BytesText::new(&self.serialize())))?;
137        if let Some(tagname) = tagname {
138            writer.write_event(Event::End(BytesEnd::new(tagname)))?;
139        }
140        Ok(())
141    }
142
143    fn attributes<'a>(&self) -> Option<Vec<quick_xml::events::attributes::Attribute<'a>>> {
144        None
145    }
146}