1use std::borrow::Cow;
2use std::fmt;
3use std::io::Write;
4use std::marker::PhantomData;
5
6use quick_xml::events::{BytesDecl, BytesText, Event};
7use quick_xml::Writer as QuickWriter;
8
9use super::common::XmlVersion;
10
11pub type Result<T> = std::result::Result<T, Error>;
12
13#[derive(Debug)]
14pub enum Error {
15 Io(std::io::Error),
16 Xml(quick_xml::Error),
17 UnbalancedEndTag,
18}
19
20impl fmt::Display for Error {
21 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22 match self {
23 Error::Io(err) => write!(f, "io error: {}", err),
24 Error::Xml(err) => write!(f, "xml error: {}", err),
25 Error::UnbalancedEndTag => write!(f, "attempted to close more elements than opened"),
26 }
27 }
28}
29
30impl std::error::Error for Error {
31 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
32 match self {
33 Error::Io(err) => Some(err),
34 Error::Xml(err) => Some(err),
35 Error::UnbalancedEndTag => None,
36 }
37 }
38}
39
40impl From<std::io::Error> for Error {
41 fn from(value: std::io::Error) -> Self {
42 Error::Io(value)
43 }
44}
45
46impl From<quick_xml::Error> for Error {
47 fn from(value: quick_xml::Error) -> Self {
48 Error::Xml(value)
49 }
50}
51
52#[derive(Clone, Debug)]
53pub struct EmitterConfig {
54 pub write_document_declaration: bool,
55 pub perform_escaping: bool,
56 pub perform_indent: bool,
57 pub line_separator: Cow<'static, str>,
58}
59
60impl Default for EmitterConfig {
61 fn default() -> Self {
62 Self {
63 write_document_declaration: true,
64 perform_escaping: true,
65 perform_indent: false,
66 line_separator: Cow::Borrowed("\n"),
67 }
68 }
69}
70
71impl EmitterConfig {
72 pub fn create_writer<W: Write>(&self, writer: W) -> EventWriter<W> {
73 EventWriter {
74 writer: QuickWriter::new(writer),
75 perform_escaping: self.perform_escaping,
76 element_stack: Vec::new(),
77 }
78 }
79}
80
81#[derive(Debug)]
82struct ElementState {
83 name: String,
84 attributes: Vec<Attribute>,
85 pending: bool,
86}
87
88pub struct EventWriter<W: Write> {
89 writer: QuickWriter<W>,
90 perform_escaping: bool,
91 element_stack: Vec<ElementState>,
92}
93
94impl<W: Write> EventWriter<W> {
95 pub fn write<'a, E>(&mut self, event: E) -> Result<()>
96 where
97 E: Into<XmlEvent<'a>>,
98 {
99 match event.into() {
100 XmlEvent::StartDocument {
101 version,
102 encoding,
103 standalone,
104 } => {
105 let standalone_text = standalone.map(|flag| if flag { "yes" } else { "no" });
106 let decl = BytesDecl::new(version.as_str(), encoding, standalone_text);
107 self.writer.write_event(Event::Decl(decl))?;
108 }
109 XmlEvent::StartElement(element) => {
110 self.flush_pending()?;
111 let StartElement {
112 name, attributes, ..
113 } = element;
114 self.element_stack.push(ElementState {
115 name,
116 attributes,
117 pending: true,
118 });
119 }
120 XmlEvent::EndElement => {
121 let state = self.element_stack.pop().ok_or(Error::UnbalancedEndTag)?;
122 if state.pending {
123 self.write_empty(state)?;
124 } else {
125 self.write_closing(&state.name)?;
126 }
127 }
128 XmlEvent::Characters(text) => {
129 self.flush_pending()?;
130 let text_event = if self.perform_escaping {
131 BytesText::new(text.as_ref())
132 } else {
133 BytesText::from_escaped(text.as_ref())
134 };
135 self.writer.write_event(Event::Text(text_event))?;
136 }
137 }
138 Ok(())
139 }
140
141 pub fn into_inner(self) -> Result<W> {
142 Ok(self.writer.into_inner())
143 }
144
145 pub fn inner_mut(&mut self) -> Result<&mut W> {
146 Ok(self.writer.get_mut())
147 }
148
149 fn flush_pending(&mut self) -> Result<()> {
150 if let Some(state) = self.element_stack.last_mut() {
151 if state.pending {
152 state.pending = false;
153 let writer = self.writer.get_mut();
154 writer.write_all(b"<").map_err(Error::from)?;
155 writer
156 .write_all(state.name.as_bytes())
157 .map_err(Error::from)?;
158 for attr in &state.attributes {
159 writer.write_all(b" ").map_err(Error::from)?;
160 writer
161 .write_all(attr.name.as_bytes())
162 .map_err(Error::from)?;
163 writer.write_all(b"=\"").map_err(Error::from)?;
164 writer
165 .write_all(attr.value.as_bytes())
166 .map_err(Error::from)?;
167 writer.write_all(b"\"").map_err(Error::from)?;
168 }
169 writer.write_all(b">").map_err(Error::from)?;
170 }
171 }
172 Ok(())
173 }
174
175 fn write_empty(&mut self, state: ElementState) -> Result<()> {
176 self.write_tag(state.name.as_str(), &state.attributes, b" />")
177 }
178
179 fn write_closing(&mut self, name: &str) -> Result<()> {
180 let writer = self.writer.get_mut();
181 writer.write_all(b"</").map_err(Error::from)?;
182 writer.write_all(name.as_bytes()).map_err(Error::from)?;
183 writer.write_all(b">").map_err(Error::from)
184 }
185
186 fn write_tag(&mut self, name: &str, attributes: &[Attribute], suffix: &[u8]) -> Result<()> {
187 let writer = self.writer.get_mut();
188 writer.write_all(b"<").map_err(Error::from)?;
189 writer.write_all(name.as_bytes()).map_err(Error::from)?;
190 for attr in attributes {
191 writer.write_all(b" ").map_err(Error::from)?;
192 writer
193 .write_all(attr.name.as_bytes())
194 .map_err(Error::from)?;
195 writer.write_all(b"=\"").map_err(Error::from)?;
196 writer
197 .write_all(attr.value.as_bytes())
198 .map_err(Error::from)?;
199 writer.write_all(b"\"").map_err(Error::from)?;
200 }
201 writer.write_all(suffix).map_err(Error::from)
202 }
203}
204
205#[derive(Clone, Debug)]
206pub struct StartElement<'a> {
207 name: String,
208 attributes: Vec<Attribute>,
209 _marker: PhantomData<&'a ()>,
210}
211
212#[derive(Clone, Debug)]
213struct Attribute {
214 name: String,
215 value: String,
216}
217
218#[derive(Clone, Debug)]
219pub enum XmlEvent<'a> {
220 StartDocument {
221 version: XmlVersion,
222 encoding: Option<&'a str>,
223 standalone: Option<bool>,
224 },
225 StartElement(StartElement<'a>),
226 EndElement,
227 Characters(Cow<'a, str>),
228}
229
230impl<'a> XmlEvent<'a> {
231 pub fn start_element(name: &'a str) -> StartElement<'a> {
232 StartElement {
233 name: name.to_string(),
234 attributes: Vec::new(),
235 _marker: std::marker::PhantomData,
236 }
237 }
238
239 pub fn end_element() -> XmlEvent<'static> {
240 XmlEvent::EndElement
241 }
242}
243
244impl<'a> From<StartElement<'a>> for XmlEvent<'a> {
245 fn from(value: StartElement<'a>) -> Self {
246 XmlEvent::StartElement(value)
247 }
248}
249
250impl<'a> From<&'a str> for XmlEvent<'a> {
251 fn from(value: &'a str) -> Self {
252 XmlEvent::Characters(Cow::Borrowed(value))
253 }
254}
255
256impl From<String> for XmlEvent<'static> {
257 fn from(value: String) -> Self {
258 XmlEvent::Characters(Cow::Owned(value))
259 }
260}
261
262impl<'a> StartElement<'a> {
263 pub fn attr(mut self, name: &str, value: &str) -> Self {
264 self.attributes.push(Attribute {
265 name: name.to_string(),
266 value: value.to_string(),
267 });
268 self
269 }
270}