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}