instant_xml/
ser.rs

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    /// Map namespace keys to prefixes.
12    ///
13    /// The prefix map is updated using `Context` types that are held on the
14    /// stack in the relevant `ToXml` implementation. If a prefix is already
15    /// defined for a given namespace, we don't update the set the new prefix.
16    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}