xsd_parser/quick_xml/
serialize.rs

1use std::borrow::Cow;
2use std::fmt::Debug;
3use std::io::Write;
4use std::mem::replace;
5
6use quick_xml::{
7    escape::escape,
8    events::{BytesEnd, BytesStart, BytesText, Event},
9    Writer,
10};
11
12use super::{Error, ErrorKind, RawByteStr};
13
14/// Trait that defines the [`Serializer`] for a type.
15pub trait WithSerializer {
16    /// The serializer to use for this type.
17    type Serializer<'x>: Serializer<'x>
18    where
19        Self: 'x;
20
21    /// Initializes a new serializer from the passed `value`.
22    ///
23    /// # Errors
24    ///
25    /// Returns a suitable [`Error`] is the serializer could not be initialized.
26    fn serializer<'ser>(
27        &'ser self,
28        name: Option<&'ser str>,
29        is_root: bool,
30    ) -> Result<Self::Serializer<'ser>, Error>;
31}
32
33impl<X> WithSerializer for X
34where
35    X: SerializeBytes + Debug,
36{
37    type Serializer<'x>
38        = ContentSerializer<'x, X>
39    where
40        Self: 'x;
41
42    fn serializer<'ser>(
43        &'ser self,
44        name: Option<&'ser str>,
45        is_root: bool,
46    ) -> Result<Self::Serializer<'ser>, Error> {
47        Ok(ContentSerializer::new(self, name, is_root))
48    }
49}
50
51/// Trait that defines a serializer that can be used to destruct a type to
52/// suitable XML [`Event`]s.
53pub trait Serializer<'ser>: Iterator<Item = Result<Event<'ser>, Error>> + Debug {}
54
55impl<'ser, X> Serializer<'ser> for X where
56    X: Iterator<Item = Result<Event<'ser>, Error>> + Debug + Sized
57{
58}
59
60/// Trait that returns a boxed version of a [`Serializer`] for any type that
61/// implements [`WithSerializer`].
62pub trait WithBoxedSerializer {
63    /// Initializes a new serializer from the passed `value`.
64    ///
65    /// # Errors
66    ///
67    /// Returns a suitable [`Error`] is the serializer could not be initialized.
68    fn serializer<'ser>(
69        &'ser self,
70        name: Option<&'ser str>,
71        is_root: bool,
72    ) -> Result<BoxedSerializer<'ser>, Error>;
73}
74
75impl<X> WithBoxedSerializer for X
76where
77    X: WithSerializer,
78{
79    fn serializer<'ser>(
80        &'ser self,
81        name: Option<&'ser str>,
82        is_root: bool,
83    ) -> Result<BoxedSerializer<'ser>, Error> {
84        Ok(Box::new(WithSerializer::serializer(self, name, is_root)?))
85    }
86}
87
88/// Boxed version of a [`Serializer`].
89pub type BoxedSerializer<'ser> =
90    Box<dyn Serializer<'ser, Item = Result<Event<'ser>, Error>> + 'ser>;
91
92/// Trait that could be implemented by types to support serialization to XML
93/// using the [`quick_xml`] crate.
94pub trait SerializeSync: Sized {
95    /// Error returned by the `serialize` method.
96    type Error;
97
98    /// Serializes the type to XML using the provided `writer`.
99    ///
100    /// # Errors
101    ///
102    /// Returns a suitable error if the operation was not successful.
103    fn serialize<W: Write>(&self, root: &str, writer: &mut Writer<W>) -> Result<(), Self::Error>;
104}
105
106impl<X> SerializeSync for X
107where
108    X: WithSerializer,
109{
110    type Error = Error;
111
112    fn serialize<W: Write>(&self, root: &str, writer: &mut Writer<W>) -> Result<(), Self::Error> {
113        SerializeHelper::new(self, Some(root), writer)?.serialize_sync()
114    }
115}
116
117/// Trait that could be implemented by types to support asynchronous serialization
118/// to XML using the [`quick_xml`] crate.
119#[cfg(feature = "async")]
120pub trait SerializeAsync: Sized {
121    /// Future that is returned by the `serialize_async` method.
122    type Future<'x>: std::future::Future<Output = Result<(), Self::Error>> + 'x
123    where
124        Self: 'x;
125
126    /// Error returned by the `serialize_async` method.
127    type Error;
128
129    /// Asynchronously serializes the type to XML using the provided `writer`.
130    fn serialize_async<'a, W: tokio::io::AsyncWrite + Unpin>(
131        &'a self,
132        root: &'a str,
133        writer: &'a mut Writer<W>,
134    ) -> Self::Future<'a>;
135}
136
137#[cfg(feature = "async")]
138impl<X> SerializeAsync for X
139where
140    X: WithSerializer,
141{
142    type Future<'x>
143        = std::pin::Pin<Box<dyn std::future::Future<Output = Result<(), Self::Error>> + 'x>>
144    where
145        X: 'x;
146
147    type Error = Error;
148
149    fn serialize_async<'a, W: tokio::io::AsyncWrite + Unpin>(
150        &'a self,
151        root: &'a str,
152        writer: &'a mut Writer<W>,
153    ) -> Self::Future<'a> {
154        Box::pin(async move {
155            SerializeHelper::new(self, Some(root), writer)?
156                .serialize_async()
157                .await
158        })
159    }
160}
161
162/// Trait that could be implemented by types to support serialization to
163/// XML byte streams.
164///
165/// This is usually implemented for simple types like numbers, strings or enums.
166pub trait SerializeBytes: Sized {
167    /// Try to serialize the type to bytes.
168    ///
169    /// This is used to serialize the type to attributes or raw element
170    /// content.
171    ///
172    /// # Errors
173    ///
174    /// Returns a suitable [`Error`] if the serialization was not successful.
175    fn serialize_bytes(&self) -> Result<Option<Cow<'_, str>>, Error>;
176}
177
178impl<X> SerializeBytes for X
179where
180    X: ToString,
181{
182    fn serialize_bytes(&self) -> Result<Option<Cow<'_, str>>, Error> {
183        Ok(Some(Cow::Owned(self.to_string())))
184    }
185}
186
187/// Implements a [`Serializer`] for any type that implements [`SerializeBytes`].
188
189#[derive(Debug)]
190#[allow(missing_docs)]
191pub enum ContentSerializer<'ser, T> {
192    Begin {
193        name: Option<&'ser str>,
194        value: &'ser T,
195    },
196    Data {
197        name: Option<&'ser str>,
198        data: Cow<'ser, str>,
199    },
200    End {
201        name: &'ser str,
202    },
203    Done,
204}
205
206impl<'ser, T> ContentSerializer<'ser, T>
207where
208    T: SerializeBytes + Debug,
209{
210    /// Create a new [`ContentSerializer`] instance from the passed arguments.
211    ///
212    /// If a `name` was passed it will emit suitable [`Start`](Event::Start)
213    /// and [`End`](Event::End) events. If no `name` was passed only the content
214    /// is rendered.
215    ///
216    /// # Errors
217    ///
218    /// Will throw a [`ErrorKind::MissingName`] error, if `None` is passed as
219    /// `name`.
220    pub fn new(value: &'ser T, name: Option<&'ser str>, is_root: bool) -> Self {
221        let _is_root = is_root;
222
223        Self::Begin { name, value }
224    }
225}
226
227impl<'ser, T> Iterator for ContentSerializer<'ser, T>
228where
229    T: SerializeBytes + Debug,
230{
231    type Item = Result<Event<'ser>, Error>;
232
233    fn next(&mut self) -> Option<Self::Item> {
234        loop {
235            match replace(self, Self::Done) {
236                Self::Begin { name, value } => match value.serialize_bytes() {
237                    Ok(None) => return name.map(|name| Ok(Event::Empty(BytesStart::new(name)))),
238                    Ok(Some(data)) => {
239                        if data.contains("]]>") {
240                            return Some(Err(ErrorKind::InvalidData(RawByteStr::from_slice(
241                                data.as_bytes(),
242                            ))
243                            .into()));
244                        }
245
246                        *self = Self::Data { name, data };
247
248                        if let Some(name) = name {
249                            return Some(Ok(Event::Start(BytesStart::new(name))));
250                        }
251                    }
252                    Err(error) => return Some(Err(error)),
253                },
254                Self::Data { name, data } => {
255                    if let Some(name) = name {
256                        *self = Self::End { name };
257                    }
258
259                    return Some(Ok(Event::Text(BytesText::from_escaped(escape(data)))));
260                }
261                Self::End { name } => return Some(Ok(Event::End(BytesEnd::new(name)))),
262                Self::Done => return None,
263            }
264        }
265    }
266}
267
268/// Implements a [`Serializer`] for any type that implements an [`Iterator`]
269/// that emits references to a type that implements [`WithSerializer`].
270#[derive(Debug)]
271#[allow(missing_docs)]
272pub enum IterSerializer<'ser, T, TItem>
273where
274    T: IntoIterator<Item = &'ser TItem> + 'ser,
275    <T as IntoIterator>::IntoIter: Debug,
276    TItem: WithSerializer + 'ser,
277{
278    Pending {
279        name: Option<&'ser str>,
280        iter: <T as IntoIterator>::IntoIter,
281    },
282    Emitting {
283        name: Option<&'ser str>,
284        iter: <T as IntoIterator>::IntoIter,
285        serializer: TItem::Serializer<'ser>,
286    },
287    Done,
288}
289
290impl<'ser, T, TItem> Iterator for IterSerializer<'ser, T, TItem>
291where
292    T: IntoIterator<Item = &'ser TItem> + 'ser,
293    <T as IntoIterator>::IntoIter: Debug,
294    TItem: WithSerializer + 'ser,
295{
296    type Item = Result<Event<'ser>, Error>;
297
298    fn next(&mut self) -> Option<Self::Item> {
299        loop {
300            match replace(self, Self::Done) {
301                Self::Pending { name, mut iter } => {
302                    let item = iter.next()?;
303
304                    match item.serializer(name, false) {
305                        Ok(serializer) => {
306                            *self = Self::Emitting {
307                                name,
308                                iter,
309                                serializer,
310                            }
311                        }
312                        Err(error) => return Some(Err(error)),
313                    }
314                }
315                Self::Emitting {
316                    name,
317                    iter,
318                    mut serializer,
319                } => {
320                    if let Some(ret) = serializer.next() {
321                        *self = Self::Emitting {
322                            name,
323                            iter,
324                            serializer,
325                        };
326
327                        return Some(ret);
328                    }
329
330                    *self = Self::Pending { name, iter };
331                }
332                Self::Done => return None,
333            }
334        }
335    }
336}
337
338impl<'ser, T, TItem> IterSerializer<'ser, T, TItem>
339where
340    T: IntoIterator<Item = &'ser TItem> + 'ser,
341    <T as IntoIterator>::IntoIter: Debug,
342    TItem: WithSerializer + 'ser,
343{
344    /// Create a new [`IterSerializer`] instance from the passed arguments.
345    pub fn new(value: T, name: Option<&'ser str>, is_root: bool) -> Self {
346        let _is_root = is_root;
347
348        Self::Pending {
349            name,
350            iter: value.into_iter(),
351        }
352    }
353}
354
355/* SerializeHelper */
356
357struct SerializeHelper<'a, T, W>
358where
359    T: WithSerializer + 'a,
360{
361    writer: &'a mut Writer<W>,
362    serializer: T::Serializer<'a>,
363}
364
365impl<'a, T, W> SerializeHelper<'a, T, W>
366where
367    T: WithSerializer,
368{
369    fn new(value: &'a T, name: Option<&'a str>, writer: &'a mut Writer<W>) -> Result<Self, Error> {
370        let serializer = value.serializer(name, true)?;
371
372        Ok(Self { writer, serializer })
373    }
374}
375
376impl<T, W> SerializeHelper<'_, T, W>
377where
378    T: WithSerializer,
379    W: Write,
380{
381    fn serialize_sync(&mut self) -> Result<(), Error> {
382        for event in self.serializer.by_ref() {
383            self.writer
384                .write_event(event?)
385                .map_err(|error| ErrorKind::XmlError(error.into()))?;
386        }
387
388        Ok(())
389    }
390}
391
392#[cfg(feature = "async")]
393impl<T, W> SerializeHelper<'_, T, W>
394where
395    T: WithSerializer,
396    W: tokio::io::AsyncWrite + Unpin,
397{
398    async fn serialize_async(&mut self) -> Result<(), Error> {
399        for event in self.serializer.by_ref() {
400            self.writer
401                .write_event_async(event?)
402                .await
403                .map_err(ErrorKind::XmlError)?;
404        }
405
406        Ok(())
407    }
408}