rustical_xml/
value.rs

1use crate::{XmlDeserialize, XmlError, XmlSerialize};
2use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event};
3use quick_xml::name::{Namespace, QName};
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.unescape()?;
81                        if !string.is_empty() {
82                            // Content already written
83                            return Err(XmlError::UnsupportedEvent("content already written"));
84                        }
85                        string = text.to_string();
86                    }
87                    Event::CData(cdata) => {
88                        let text = String::from_utf8(cdata.to_vec())?;
89                        if !string.is_empty() {
90                            // Content already written
91                            return Err(XmlError::UnsupportedEvent("content already written"));
92                        }
93                        string = text;
94                    }
95                    Event::End(_) => break,
96                    Event::Eof => return Err(XmlError::Eof),
97                    _ => return Err(XmlError::UnsupportedEvent("todo")),
98                };
99            }
100        }
101
102        ValueDeserialize::deserialize(&string)
103    }
104}
105
106impl<T: ValueSerialize> XmlSerialize for T {
107    fn serialize<W: std::io::Write>(
108        &self,
109        ns: Option<Namespace>,
110        tag: Option<&[u8]>,
111        namespaces: &HashMap<Namespace, &[u8]>,
112        writer: &mut quick_xml::Writer<W>,
113    ) -> std::io::Result<()> {
114        let prefix = ns
115            .map(|ns| namespaces.get(&ns))
116            .unwrap_or(None)
117            .map(|prefix| {
118                if !prefix.is_empty() {
119                    [*prefix, b":"].concat()
120                } else {
121                    Vec::new()
122                }
123            });
124        let has_prefix = prefix.is_some();
125        let tagname = tag.map(|tag| [&prefix.unwrap_or_default(), tag].concat());
126        let qname = tagname.as_ref().map(|tagname| QName(tagname));
127        if let Some(qname) = &qname {
128            let mut bytes_start = BytesStart::from(qname.to_owned());
129            if !has_prefix {
130                if let Some(ns) = &ns {
131                    bytes_start.push_attribute((b"xmlns".as_ref(), ns.as_ref()));
132                }
133            }
134            writer.write_event(Event::Start(bytes_start))?;
135        }
136        writer.write_event(Event::Text(BytesText::new(&self.serialize())))?;
137        if let Some(qname) = &qname {
138            writer.write_event(Event::End(BytesEnd::from(qname.to_owned())))?;
139        }
140        Ok(())
141    }
142
143    #[allow(refining_impl_trait)]
144    fn attributes<'a>(&self) -> Option<Vec<quick_xml::events::attributes::Attribute<'a>>> {
145        None
146    }
147}