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