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    &'ser T: IntoIterator<Item = &'ser TItem>,
275    <&'ser T as IntoIterator>::IntoIter: Debug,
276    TItem: WithSerializer + 'ser,
277{
278    Pending {
279        name: Option<&'ser str>,
280        iter: <&'ser T as IntoIterator>::IntoIter,
281    },
282    Emitting {
283        name: Option<&'ser str>,
284        iter: <&'ser 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: 'ser,
293    &'ser T: IntoIterator<Item = &'ser TItem>,
294    <&'ser T as IntoIterator>::IntoIter: Debug,
295    TItem: WithSerializer + 'ser,
296{
297    type Item = Result<Event<'ser>, Error>;
298
299    fn next(&mut self) -> Option<Self::Item> {
300        loop {
301            match replace(self, Self::Done) {
302                Self::Pending { name, mut iter } => {
303                    let item = iter.next()?;
304
305                    match item.serializer(name, false) {
306                        Ok(serializer) => {
307                            *self = Self::Emitting {
308                                name,
309                                iter,
310                                serializer,
311                            }
312                        }
313                        Err(error) => return Some(Err(error)),
314                    }
315                }
316                Self::Emitting {
317                    name,
318                    iter,
319                    mut serializer,
320                } => {
321                    if let Some(ret) = serializer.next() {
322                        *self = Self::Emitting {
323                            name,
324                            iter,
325                            serializer,
326                        };
327
328                        return Some(ret);
329                    }
330
331                    *self = Self::Pending { name, iter };
332                }
333                Self::Done => return None,
334            }
335        }
336    }
337}
338
339impl<'ser, T, TItem> IterSerializer<'ser, T, TItem>
340where
341    T: Debug + 'ser,
342    &'ser T: IntoIterator<Item = &'ser TItem>,
343    <&'ser T as IntoIterator>::IntoIter: Debug,
344    TItem: WithSerializer + Debug + 'ser,
345{
346    /// Create a new [`IterSerializer`] instance from the passed arguments.
347    pub fn new(value: &'ser T, name: Option<&'ser str>, is_root: bool) -> Self {
348        let _is_root = is_root;
349
350        Self::Pending {
351            name,
352            iter: value.into_iter(),
353        }
354    }
355}
356
357/* SerializeHelper */
358
359struct SerializeHelper<'a, T, W>
360where
361    T: WithSerializer + 'a,
362{
363    writer: &'a mut Writer<W>,
364    serializer: T::Serializer<'a>,
365}
366
367impl<'a, T, W> SerializeHelper<'a, T, W>
368where
369    T: WithSerializer,
370{
371    fn new(value: &'a T, name: Option<&'a str>, writer: &'a mut Writer<W>) -> Result<Self, Error> {
372        let serializer = value.serializer(name, true)?;
373
374        Ok(Self { writer, serializer })
375    }
376}
377
378impl<T, W> SerializeHelper<'_, T, W>
379where
380    T: WithSerializer,
381    W: Write,
382{
383    fn serialize_sync(&mut self) -> Result<(), Error> {
384        for event in self.serializer.by_ref() {
385            self.writer
386                .write_event(event?)
387                .map_err(|error| ErrorKind::XmlError(error.into()))?;
388        }
389
390        Ok(())
391    }
392}
393
394#[cfg(feature = "async")]
395impl<T, W> SerializeHelper<'_, T, W>
396where
397    T: WithSerializer,
398    W: tokio::io::AsyncWrite + Unpin,
399{
400    async fn serialize_async(&mut self) -> Result<(), Error> {
401        for event in self.serializer.by_ref() {
402            self.writer
403                .write_event_async(event?)
404                .await
405                .map_err(ErrorKind::XmlError)?;
406        }
407
408        Ok(())
409    }
410}