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
178/// Marker trait used to automatically implement [`SerializeBytes`] for any type
179/// that implements [`ToString`].
180pub trait SerializeBytesToString: ToString {}
181
182impl<X> SerializeBytes for X
183where
184    X: SerializeBytesToString,
185{
186    fn serialize_bytes(&self) -> Result<Option<Cow<'_, str>>, Error> {
187        Ok(Some(Cow::Owned(self.to_string())))
188    }
189}
190
191impl SerializeBytesToString for bool {}
192impl SerializeBytesToString for String {}
193
194impl SerializeBytesToString for u8 {}
195impl SerializeBytesToString for u16 {}
196impl SerializeBytesToString for u32 {}
197impl SerializeBytesToString for u64 {}
198impl SerializeBytesToString for usize {}
199
200impl SerializeBytesToString for i8 {}
201impl SerializeBytesToString for i16 {}
202impl SerializeBytesToString for i32 {}
203impl SerializeBytesToString for i64 {}
204impl SerializeBytesToString for isize {}
205
206impl SerializeBytesToString for f32 {}
207impl SerializeBytesToString for f64 {}
208
209#[cfg(feature = "num")]
210impl SerializeBytesToString for num::BigInt {}
211
212#[cfg(feature = "num")]
213impl SerializeBytesToString for num::BigUint {}
214
215/// Implements a [`Serializer`] for any type that implements [`SerializeBytes`].
216
217#[derive(Debug)]
218#[allow(missing_docs)]
219pub enum ContentSerializer<'ser, T> {
220    Begin {
221        name: Option<&'ser str>,
222        value: &'ser T,
223    },
224    Data {
225        name: Option<&'ser str>,
226        data: Cow<'ser, str>,
227    },
228    End {
229        name: &'ser str,
230    },
231    Done,
232}
233
234impl<'ser, T> ContentSerializer<'ser, T>
235where
236    T: SerializeBytes + Debug,
237{
238    /// Create a new [`ContentSerializer`] instance from the passed arguments.
239    ///
240    /// If a `name` was passed it will emit suitable [`Start`](Event::Start)
241    /// and [`End`](Event::End) events. If no `name` was passed only the content
242    /// is rendered.
243    ///
244    /// # Errors
245    ///
246    /// Will throw a [`ErrorKind::MissingName`] error, if `None` is passed as
247    /// `name`.
248    pub fn new(value: &'ser T, name: Option<&'ser str>, is_root: bool) -> Self {
249        let _is_root = is_root;
250
251        Self::Begin { name, value }
252    }
253}
254
255impl<'ser, T> Iterator for ContentSerializer<'ser, T>
256where
257    T: SerializeBytes + Debug,
258{
259    type Item = Result<Event<'ser>, Error>;
260
261    fn next(&mut self) -> Option<Self::Item> {
262        loop {
263            match replace(self, Self::Done) {
264                Self::Begin { name, value } => match value.serialize_bytes() {
265                    Ok(None) => return name.map(|name| Ok(Event::Empty(BytesStart::new(name)))),
266                    Ok(Some(data)) => {
267                        if data.contains("]]>") {
268                            return Some(Err(ErrorKind::InvalidData(RawByteStr::from_slice(
269                                data.as_bytes(),
270                            ))
271                            .into()));
272                        }
273
274                        *self = Self::Data { name, data };
275
276                        if let Some(name) = name {
277                            return Some(Ok(Event::Start(BytesStart::new(name))));
278                        }
279                    }
280                    Err(error) => return Some(Err(error)),
281                },
282                Self::Data { name, data } => {
283                    if let Some(name) = name {
284                        *self = Self::End { name };
285                    }
286
287                    return Some(Ok(Event::Text(BytesText::from_escaped(escape(data)))));
288                }
289                Self::End { name } => return Some(Ok(Event::End(BytesEnd::new(name)))),
290                Self::Done => return None,
291            }
292        }
293    }
294}
295
296/// Implements a [`Serializer`] for any type that implements an [`Iterator`]
297/// that emits references to a type that implements [`WithSerializer`].
298#[derive(Debug)]
299#[allow(missing_docs)]
300pub enum IterSerializer<'ser, T, TItem>
301where
302    T: IntoIterator<Item = &'ser TItem> + 'ser,
303    <T as IntoIterator>::IntoIter: Debug,
304    TItem: WithSerializer + 'ser,
305{
306    Pending {
307        name: Option<&'ser str>,
308        iter: <T as IntoIterator>::IntoIter,
309    },
310    Emitting {
311        name: Option<&'ser str>,
312        iter: <T as IntoIterator>::IntoIter,
313        serializer: TItem::Serializer<'ser>,
314    },
315    Done,
316}
317
318impl<'ser, T, TItem> Iterator for IterSerializer<'ser, T, TItem>
319where
320    T: IntoIterator<Item = &'ser TItem> + 'ser,
321    <T as IntoIterator>::IntoIter: Debug,
322    TItem: WithSerializer + 'ser,
323{
324    type Item = Result<Event<'ser>, Error>;
325
326    fn next(&mut self) -> Option<Self::Item> {
327        loop {
328            match replace(self, Self::Done) {
329                Self::Pending { name, mut iter } => {
330                    let item = iter.next()?;
331
332                    match item.serializer(name, false) {
333                        Ok(serializer) => {
334                            *self = Self::Emitting {
335                                name,
336                                iter,
337                                serializer,
338                            }
339                        }
340                        Err(error) => return Some(Err(error)),
341                    }
342                }
343                Self::Emitting {
344                    name,
345                    iter,
346                    mut serializer,
347                } => {
348                    if let Some(ret) = serializer.next() {
349                        *self = Self::Emitting {
350                            name,
351                            iter,
352                            serializer,
353                        };
354
355                        return Some(ret);
356                    }
357
358                    *self = Self::Pending { name, iter };
359                }
360                Self::Done => return None,
361            }
362        }
363    }
364}
365
366impl<'ser, T, TItem> IterSerializer<'ser, T, TItem>
367where
368    T: IntoIterator<Item = &'ser TItem> + 'ser,
369    <T as IntoIterator>::IntoIter: Debug,
370    TItem: WithSerializer + 'ser,
371{
372    /// Create a new [`IterSerializer`] instance from the passed arguments.
373    pub fn new(value: T, name: Option<&'ser str>, is_root: bool) -> Self {
374        let _is_root = is_root;
375
376        Self::Pending {
377            name,
378            iter: value.into_iter(),
379        }
380    }
381}
382
383/* SerializeHelper */
384
385struct SerializeHelper<'a, T, W>
386where
387    T: WithSerializer + 'a,
388{
389    writer: &'a mut Writer<W>,
390    serializer: T::Serializer<'a>,
391}
392
393impl<'a, T, W> SerializeHelper<'a, T, W>
394where
395    T: WithSerializer,
396{
397    fn new(value: &'a T, name: Option<&'a str>, writer: &'a mut Writer<W>) -> Result<Self, Error> {
398        let serializer = value.serializer(name, true)?;
399
400        Ok(Self { writer, serializer })
401    }
402}
403
404impl<T, W> SerializeHelper<'_, T, W>
405where
406    T: WithSerializer,
407    W: Write,
408{
409    fn serialize_sync(&mut self) -> Result<(), Error> {
410        for event in self.serializer.by_ref() {
411            self.writer
412                .write_event(event?)
413                .map_err(|error| ErrorKind::XmlError(error.into()))?;
414        }
415
416        Ok(())
417    }
418}
419
420#[cfg(feature = "async")]
421impl<T, W> SerializeHelper<'_, T, W>
422where
423    T: WithSerializer,
424    W: tokio::io::AsyncWrite + Unpin,
425{
426    async fn serialize_async(&mut self) -> Result<(), Error> {
427        for event in self.serializer.by_ref() {
428            self.writer
429                .write_event_async(event?)
430                .await
431                .map_err(ErrorKind::XmlError)?;
432        }
433
434        Ok(())
435    }
436}