1use std::collections::hash_map::Entry;
4use std::collections::HashMap;
5use std::fmt::{self};
6use std::mem;
7
8use super::Error;
9use crate::ToXml;
10
11pub struct Serializer<'xml, W: fmt::Write + ?Sized> {
13 output: &'xml mut W,
14 prefixes: HashMap<&'static str, &'static str>,
20 default_ns: &'static str,
21 attribute_ns: Option<&'static str>,
26 state: State,
27}
28
29impl<'xml, W: fmt::Write + ?Sized> Serializer<'xml, W> {
30 pub fn new(output: &'xml mut W) -> Self {
32 Self {
33 output,
34 prefixes: HashMap::new(),
35 default_ns: "",
36 attribute_ns: None,
37 state: State::Element,
38 }
39 }
40
41 pub fn write_start<'a, const N: usize>(
48 &mut self,
49 name: &'a str,
50 ns: &str,
51 cx: Option<Context<N>>,
52 ) -> Result<Element<'a, N>, Error> {
53 if self.state != State::Element {
54 return Err(Error::UnexpectedState("invalid state for element start"));
55 }
56
57 let force_prefix = cx.as_ref().is_some_and(|cx| cx.force_prefix);
58
59 let (prefix, update_default_ns) =
60 match (ns == self.default_ns, self.prefixes.get(ns), force_prefix) {
61 (false, Some(prefix), true) => {
63 self.output.write_fmt(format_args!("<{prefix}:{name}"))?;
64 (Some(*prefix), false)
65 }
66 (false, Some(prefix), false) => {
68 self.output.write_fmt(format_args!("<{prefix}:{name}"))?;
69 if let Some(cx) = &cx {
70 self.output
71 .write_fmt(format_args!(" xmlns=\"{}\"", cx.default_ns))?;
72 }
73 (Some(*prefix), true)
74 }
75 (true, None, _) => {
77 self.output.write_fmt(format_args!("<{name}"))?;
78 (None, false)
79 }
80 (true, Some(_), false) => {
82 self.output.write_fmt(format_args!("<{name}"))?;
83 if let Some(cx) = &cx {
85 self.output
86 .write_fmt(format_args!(" xmlns=\"{}\"", cx.default_ns))?;
87 }
88 (None, true)
89 }
90 (true, Some(prefix), true) => {
92 self.output.write_fmt(format_args!("<{prefix}:{name}"))?;
93 (Some(*prefix), false)
94 }
95 _ => {
96 self.output
97 .write_fmt(format_args!("<{name} xmlns=\"{ns}\""))?;
98 (None, true)
99 }
100 };
101
102 self.state = State::Attribute;
103 self.attribute_ns = cx.as_ref().map(|cx| cx.default_ns);
104 let Some(cx) = cx else {
105 return Ok(Element {
106 prefix,
107 name,
108 parent: None,
109 });
110 };
111
112 let mut old = Context::default();
113 let prev = match update_default_ns {
114 true => mem::replace(&mut self.default_ns, cx.default_ns),
115 false => self.default_ns,
116 };
117 let _ = mem::replace(&mut old.default_ns, prev);
118
119 let mut used = 0;
120 for prefix in cx.prefixes.into_iter() {
121 if prefix.prefix.is_empty() {
122 continue;
123 }
124
125 if self.prefixes.contains_key(prefix.ns) {
126 continue;
127 }
128
129 self.output
130 .write_fmt(format_args!(" xmlns:{}=\"{}\"", prefix.prefix, prefix.ns))?;
131
132 let prev = match self.prefixes.entry(prefix.ns) {
133 Entry::Occupied(mut entry) => mem::replace(entry.get_mut(), prefix.prefix),
134 Entry::Vacant(entry) => {
135 entry.insert(prefix.prefix);
136 ""
137 }
138 };
139
140 old.prefixes[used] = Prefix {
141 ns: prefix.ns,
142 prefix: prev,
143 };
144 used += 1;
145 }
146
147 Ok(Element {
148 prefix,
149 name,
150 parent: Some(old),
151 })
152 }
153
154 pub fn write_attr<V: ToXml + ?Sized>(
156 &mut self,
157 name: &str,
158 ns: &str,
159 value: &V,
160 ) -> Result<(), Error> {
161 if self.state != State::Attribute {
162 return Err(Error::UnexpectedState("invalid state for attribute"));
163 }
164
165 let attr_ns = self.attribute_ns.unwrap_or(self.default_ns);
166 match ns.is_empty() || ns == attr_ns {
167 true => self.output.write_fmt(format_args!(" {name}=\""))?,
168 false => {
169 let prefix = self
170 .prefixes
171 .get(ns)
172 .ok_or(Error::UnexpectedState("unknown prefix"))?;
173 self.output.write_fmt(format_args!(" {prefix}:{name}=\""))?;
174 }
175 }
176
177 self.state = State::Scalar;
178 value.serialize(None, self)?;
179 self.state = State::Attribute;
180 self.output.write_char('"')?;
181 Ok(())
182 }
183
184 pub fn write_str<V: fmt::Display + ?Sized>(&mut self, value: &V) -> Result<(), Error> {
186 if !matches!(self.state, State::Element | State::Scalar) {
187 return Err(Error::UnexpectedState("invalid state for scalar"));
188 }
189
190 self.output.write_fmt(format_args!("{value}"))?;
191 self.state = State::Element;
192 Ok(())
193 }
194
195 pub fn end_start(&mut self) -> Result<(), Error> {
197 if self.state != State::Attribute {
198 return Err(Error::UnexpectedState("invalid state for element end"));
199 }
200
201 self.output.write_char('>')?;
202 self.attribute_ns = None;
203 self.state = State::Element;
204 Ok(())
205 }
206
207 pub fn end_empty(&mut self) -> Result<(), Error> {
209 if self.state != State::Attribute {
210 return Err(Error::UnexpectedState("invalid state for element end"));
211 }
212
213 self.output.write_str(" />")?;
214 self.attribute_ns = None;
215 self.state = State::Element;
216 Ok(())
217 }
218
219 pub fn write_close<const N: usize>(&mut self, element: Element<'_, N>) -> Result<(), Error> {
221 if self.state != State::Element {
222 return Err(Error::UnexpectedState("invalid state for close element"));
223 }
224
225 match element.prefix {
226 Some(prefix) => self
227 .output
228 .write_fmt(format_args!("</{prefix}:{}>", element.name))?,
229 None => self.output.write_fmt(format_args!("</{}>", element.name))?,
230 }
231
232 let Some(old) = element.parent else {
233 return Ok(());
234 };
235
236 let _ = mem::replace(&mut self.default_ns, old.default_ns);
237 for prefix in old.prefixes.into_iter() {
238 if prefix.ns.is_empty() && prefix.prefix.is_empty() {
239 continue;
240 }
241
242 let mut entry = match self.prefixes.entry(prefix.ns) {
243 Entry::Occupied(entry) => entry,
244 Entry::Vacant(_) => unreachable!(),
245 };
246
247 match prefix.prefix {
248 "" => {
249 entry.remove();
250 }
251 prev => {
252 let _ = mem::replace(entry.get_mut(), prev);
253 }
254 }
255 }
256
257 Ok(())
258 }
259
260 pub fn prefix(&self, ns: &str) -> Option<&'static str> {
262 self.prefixes.get(ns).copied()
263 }
264
265 pub fn default_ns(&self) -> &'static str {
267 self.default_ns
268 }
269}
270
271#[non_exhaustive]
273pub struct Element<'a, const N: usize> {
274 pub prefix: Option<&'static str>,
276 pub name: &'a str,
278 pub parent: Option<Context<N>>,
280}
281
282#[derive(Debug)]
284#[non_exhaustive]
285pub struct Context<const N: usize> {
286 pub default_ns: &'static str,
288 pub prefixes: [Prefix; N],
290 pub force_prefix: bool,
292}
293
294impl<const N: usize> Default for Context<N> {
295 fn default() -> Self {
296 Self {
297 default_ns: Default::default(),
298 prefixes: [Prefix { prefix: "", ns: "" }; N],
299 force_prefix: false,
300 }
301 }
302}
303
304#[derive(Clone, Copy, Debug, Default)]
306pub struct Prefix {
307 pub prefix: &'static str,
309 pub ns: &'static str,
311}
312
313#[derive(Debug, Eq, PartialEq)]
314enum State {
315 Attribute,
316 Element,
317 Scalar,
318}