1use std::collections::hash_map::Entry;
2use std::collections::HashMap;
3use std::fmt::{self};
4use std::mem;
5
6use super::Error;
7use crate::ToXml;
8
9pub struct Serializer<'xml, W: fmt::Write + ?Sized> {
11 output: &'xml mut W,
12 prefixes: HashMap<&'static str, &'static str>,
18 default_ns: &'static str,
19 state: State,
20}
21
22impl<'xml, W: fmt::Write + ?Sized> Serializer<'xml, W> {
23 pub fn new(output: &'xml mut W) -> Self {
25 Self {
26 output,
27 prefixes: HashMap::new(),
28 default_ns: "",
29 state: State::Element,
30 }
31 }
32
33 pub fn write_start(&mut self, name: &str, ns: &str) -> Result<Option<&'static str>, Error> {
37 if self.state != State::Element {
38 return Err(Error::UnexpectedState("invalid state for element start"));
39 }
40
41 let prefix = match (ns == self.default_ns, self.prefixes.get(ns)) {
42 (true, _) => {
43 self.output.write_fmt(format_args!("<{name}"))?;
44 None
45 }
46 (false, Some(prefix)) => {
47 self.output.write_fmt(format_args!("<{prefix}:{name}"))?;
48 Some(*prefix)
49 }
50 _ => {
51 self.output
52 .write_fmt(format_args!("<{name} xmlns=\"{ns}\""))?;
53 None
54 }
55 };
56
57 self.state = State::Attribute;
58 Ok(prefix)
59 }
60
61 pub fn write_attr<V: ToXml + ?Sized>(
63 &mut self,
64 name: &str,
65 ns: &str,
66 value: &V,
67 ) -> Result<(), Error> {
68 if self.state != State::Attribute {
69 return Err(Error::UnexpectedState("invalid state for attribute"));
70 }
71
72 match ns == self.default_ns {
73 true => self.output.write_fmt(format_args!(" {name}=\""))?,
74 false => {
75 let prefix = self
76 .prefixes
77 .get(ns)
78 .ok_or(Error::UnexpectedState("unknown prefix"))?;
79 self.output.write_fmt(format_args!(" {prefix}:{name}=\""))?;
80 }
81 }
82
83 self.state = State::Scalar;
84 value.serialize(None, self)?;
85 self.state = State::Attribute;
86 self.output.write_char('"')?;
87 Ok(())
88 }
89
90 pub fn write_str<V: fmt::Display + ?Sized>(&mut self, value: &V) -> Result<(), Error> {
92 if !matches!(self.state, State::Element | State::Scalar) {
93 return Err(Error::UnexpectedState("invalid state for scalar"));
94 }
95
96 self.output.write_fmt(format_args!("{value}"))?;
97 self.state = State::Element;
98 Ok(())
99 }
100
101 pub fn end_start(&mut self) -> Result<(), Error> {
103 if self.state != State::Attribute {
104 return Err(Error::UnexpectedState("invalid state for element end"));
105 }
106
107 self.output.write_char('>')?;
108 self.state = State::Element;
109 Ok(())
110 }
111
112 pub fn end_empty(&mut self) -> Result<(), Error> {
114 if self.state != State::Attribute {
115 return Err(Error::UnexpectedState("invalid state for element end"));
116 }
117
118 self.output.write_str(" />")?;
119 self.state = State::Element;
120 Ok(())
121 }
122
123 pub fn write_close(&mut self, prefix: Option<&str>, name: &str) -> Result<(), Error> {
125 if self.state != State::Element {
126 return Err(Error::UnexpectedState("invalid state for close element"));
127 }
128
129 match prefix {
130 Some(prefix) => self.output.write_fmt(format_args!("</{prefix}:{name}>"))?,
131 None => self.output.write_fmt(format_args!("</{name}>"))?,
132 }
133
134 Ok(())
135 }
136
137 pub fn push<const N: usize>(&mut self, new: Context<N>) -> Result<Context<N>, Error> {
141 if self.state != State::Attribute {
142 return Err(Error::UnexpectedState("invalid state for attribute"));
143 }
144
145 let mut old = Context::default();
146 let prev = mem::replace(&mut self.default_ns, new.default_ns);
147 let _ = mem::replace(&mut old.default_ns, prev);
148
149 let mut used = 0;
150 for prefix in new.prefixes.into_iter() {
151 if prefix.prefix.is_empty() {
152 continue;
153 }
154
155 if self.prefixes.contains_key(prefix.ns) {
156 continue;
157 }
158
159 self.output
160 .write_fmt(format_args!(" xmlns:{}=\"{}\"", prefix.prefix, prefix.ns))?;
161
162 let prev = match self.prefixes.entry(prefix.ns) {
163 Entry::Occupied(mut entry) => mem::replace(entry.get_mut(), prefix.prefix),
164 Entry::Vacant(entry) => {
165 entry.insert(prefix.prefix);
166 ""
167 }
168 };
169
170 old.prefixes[used] = Prefix {
171 ns: prefix.ns,
172 prefix: prev,
173 };
174 used += 1;
175 }
176
177 Ok(old)
178 }
179
180 pub fn pop<const N: usize>(&mut self, old: Context<N>) {
182 let _ = mem::replace(&mut self.default_ns, old.default_ns);
183 for prefix in old.prefixes.into_iter() {
184 if prefix.ns.is_empty() && prefix.prefix.is_empty() {
185 continue;
186 }
187
188 let mut entry = match self.prefixes.entry(prefix.ns) {
189 Entry::Occupied(entry) => entry,
190 Entry::Vacant(_) => unreachable!(),
191 };
192
193 match prefix.prefix {
194 "" => {
195 entry.remove();
196 }
197 prev => {
198 let _ = mem::replace(entry.get_mut(), prev);
199 }
200 }
201 }
202 }
203
204 pub fn prefix(&self, ns: &str) -> Option<&'static str> {
206 self.prefixes.get(ns).copied()
207 }
208
209 pub fn default_ns(&self) -> &'static str {
211 self.default_ns
212 }
213}
214
215#[derive(Debug)]
217pub struct Context<const N: usize> {
218 pub default_ns: &'static str,
220 pub prefixes: [Prefix; N],
222}
223
224impl<const N: usize> Default for Context<N> {
225 fn default() -> Self {
226 Self {
227 default_ns: Default::default(),
228 prefixes: [Prefix { prefix: "", ns: "" }; N],
229 }
230 }
231}
232
233#[derive(Clone, Copy, Debug, Default)]
235pub struct Prefix {
236 pub prefix: &'static str,
238 pub ns: &'static str,
240}
241
242#[derive(Debug, Eq, PartialEq)]
243enum State {
244 Attribute,
245 Element,
246 Scalar,
247}