quick_xml/se/
simple_type.rs

1//! Contains Serde `Serializer` for XML [simple types] [as defined] in the XML Schema.
2//!
3//! [simple types]: https://www.w3schools.com/xml/el_simpletype.asp
4//! [as defined]: https://www.w3.org/TR/xmlschema11-1/#Simple_Type_Definition
5
6use crate::errors::serialize::DeError;
7use crate::escapei::_escape;
8use crate::se::{Indent, QuoteLevel};
9use serde::ser::{
10    Impossible, Serialize, SerializeSeq, SerializeTuple, SerializeTupleStruct,
11    SerializeTupleVariant, Serializer,
12};
13use serde::serde_if_integer128;
14use std::borrow::Cow;
15use std::fmt::Write;
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum QuoteTarget {
19    /// Escape data for a text content. No additional escape symbols
20    Text,
21    /// Escape data for a double-quoted attribute. `"` always escaped
22    DoubleQAttr,
23    /// Escape data for a single-quoted attribute. `'` always escaped
24    SingleQAttr,
25}
26
27/// Escapes atomic value that could be part of a `xs:list`. All whitespace characters
28/// additionally escaped
29fn escape_item(value: &str, target: QuoteTarget, level: QuoteLevel) -> Cow<str> {
30    use QuoteLevel::*;
31    use QuoteTarget::*;
32
33    match (target, level) {
34        (_, Full) => _escape(value, |ch| match ch {
35            // Spaces used as delimiters of list items, cannot be used in the item
36            b' ' | b'\r' | b'\n' | b'\t' => true,
37            // Required characters to escape
38            b'&' | b'<' | b'>' | b'\'' | b'\"' => true,
39            _ => false,
40        }),
41        //----------------------------------------------------------------------
42        (Text, Partial) => _escape(value, |ch| match ch {
43            // Spaces used as delimiters of list items, cannot be used in the item
44            b' ' | b'\r' | b'\n' | b'\t' => true,
45            // Required characters to escape
46            b'&' | b'<' | b'>' => true,
47            _ => false,
48        }),
49        (Text, Minimal) => _escape(value, |ch| match ch {
50            // Spaces used as delimiters of list items, cannot be used in the item
51            b' ' | b'\r' | b'\n' | b'\t' => true,
52            // Required characters to escape
53            b'&' | b'<' => true,
54            _ => false,
55        }),
56        //----------------------------------------------------------------------
57        (DoubleQAttr, Partial) => _escape(value, |ch| match ch {
58            // Spaces used as delimiters of list items, cannot be used in the item
59            b' ' | b'\r' | b'\n' | b'\t' => true,
60            // Required characters to escape
61            b'&' | b'<' | b'>' => true,
62            // Double quoted attribute should escape quote
63            b'"' => true,
64            _ => false,
65        }),
66        (DoubleQAttr, Minimal) => _escape(value, |ch| match ch {
67            // Spaces used as delimiters of list items, cannot be used in the item
68            b' ' | b'\r' | b'\n' | b'\t' => true,
69            // Required characters to escape
70            b'&' | b'<' => true,
71            // Double quoted attribute should escape quote
72            b'"' => true,
73            _ => false,
74        }),
75        //----------------------------------------------------------------------
76        (SingleQAttr, Partial) => _escape(value, |ch| match ch {
77            // Spaces used as delimiters of list items
78            b' ' | b'\r' | b'\n' | b'\t' => true,
79            // Required characters to escape
80            b'&' | b'<' | b'>' => true,
81            // Single quoted attribute should escape quote
82            b'\'' => true,
83            _ => false,
84        }),
85        (SingleQAttr, Minimal) => _escape(value, |ch| match ch {
86            // Spaces used as delimiters of list items
87            b' ' | b'\r' | b'\n' | b'\t' => true,
88            // Required characters to escape
89            b'&' | b'<' => true,
90            // Single quoted attribute should escape quote
91            b'\'' => true,
92            _ => false,
93        }),
94    }
95}
96
97/// Escapes XSD simple type value
98fn escape_list(value: &str, target: QuoteTarget, level: QuoteLevel) -> Cow<str> {
99    use QuoteLevel::*;
100    use QuoteTarget::*;
101
102    match (target, level) {
103        (_, Full) => _escape(value, |ch| match ch {
104            // Required characters to escape
105            b'&' | b'<' | b'>' | b'\'' | b'\"' => true,
106            _ => false,
107        }),
108        //----------------------------------------------------------------------
109        (Text, Partial) => _escape(value, |ch| match ch {
110            // Required characters to escape
111            b'&' | b'<' | b'>' => true,
112            _ => false,
113        }),
114        (Text, Minimal) => _escape(value, |ch| match ch {
115            // Required characters to escape
116            b'&' | b'<' => true,
117            _ => false,
118        }),
119        //----------------------------------------------------------------------
120        (DoubleQAttr, Partial) => _escape(value, |ch| match ch {
121            // Required characters to escape
122            b'&' | b'<' | b'>' => true,
123            // Double quoted attribute should escape quote
124            b'"' => true,
125            _ => false,
126        }),
127        (DoubleQAttr, Minimal) => _escape(value, |ch| match ch {
128            // Required characters to escape
129            b'&' | b'<' => true,
130            // Double quoted attribute should escape quote
131            b'"' => true,
132            _ => false,
133        }),
134        //----------------------------------------------------------------------
135        (SingleQAttr, Partial) => _escape(value, |ch| match ch {
136            // Required characters to escape
137            b'&' | b'<' | b'>' => true,
138            // Single quoted attribute should escape quote
139            b'\'' => true,
140            _ => false,
141        }),
142        (SingleQAttr, Minimal) => _escape(value, |ch| match ch {
143            // Required characters to escape
144            b'&' | b'<' => true,
145            // Single quoted attribute should escape quote
146            b'\'' => true,
147            _ => false,
148        }),
149    }
150}
151
152////////////////////////////////////////////////////////////////////////////////////////////////////
153
154macro_rules! write_atomic {
155    ($method:ident ( $ty:ty )) => {
156        fn $method(mut self, value: $ty) -> Result<Self::Ok, Self::Error> {
157            self.write_str(&value.to_string())?;
158            Ok(true)
159        }
160    };
161}
162
163/// A serializer that handles ordinary [simple type definition][item] with
164/// `{variety} = atomic`, or an ordinary [simple type] definition with
165/// `{variety} = union` whose basic members are all atomic.
166///
167/// This serializer can serialize only primitive types:
168/// - numbers
169/// - booleans
170/// - strings
171/// - units
172/// - options
173/// - unit variants of enums
174///
175/// Identifiers represented as strings and serialized accordingly.
176///
177/// Serialization of all other types returns [`Unsupported`][DeError::Unsupported] error.
178///
179/// This serializer returns `true` if something was written and `false` otherwise.
180///
181/// [item]: https://www.w3.org/TR/xmlschema11-1/#std-item_type_definition
182/// [simple type]: https://www.w3.org/TR/xmlschema11-1/#Simple_Type_Definition
183pub struct AtomicSerializer<'i, W: Write> {
184    pub writer: W,
185    pub target: QuoteTarget,
186    /// Defines which XML characters need to be escaped
187    pub level: QuoteLevel,
188    /// When `Some`, the indent that should be written before the content
189    /// if content is not an empty string.
190    /// When `None` an `xs:list` delimiter (a space) should be written
191    pub(crate) indent: Option<Indent<'i>>,
192}
193
194impl<'i, W: Write> AtomicSerializer<'i, W> {
195    fn write_str(&mut self, value: &str) -> Result<(), DeError> {
196        if let Some(indent) = self.indent.as_mut() {
197            indent.write_indent(&mut self.writer)?;
198        } else {
199            // TODO: Customization point -- possible non-XML compatible extension to specify delimiter char
200            self.writer.write_char(' ')?;
201        }
202        Ok(self.writer.write_str(value)?)
203    }
204}
205
206impl<'i, W: Write> Serializer for AtomicSerializer<'i, W> {
207    type Ok = bool;
208    type Error = DeError;
209
210    type SerializeSeq = Impossible<Self::Ok, Self::Error>;
211    type SerializeTuple = Impossible<Self::Ok, Self::Error>;
212    type SerializeTupleStruct = Impossible<Self::Ok, Self::Error>;
213    type SerializeTupleVariant = Impossible<Self::Ok, Self::Error>;
214    type SerializeMap = Impossible<Self::Ok, Self::Error>;
215    type SerializeStruct = Impossible<Self::Ok, Self::Error>;
216    type SerializeStructVariant = Impossible<Self::Ok, Self::Error>;
217
218    fn serialize_bool(mut self, value: bool) -> Result<Self::Ok, Self::Error> {
219        self.write_str(if value { "true" } else { "false" })?;
220        Ok(true)
221    }
222
223    write_atomic!(serialize_i8(i8));
224    write_atomic!(serialize_i16(i16));
225    write_atomic!(serialize_i32(i32));
226    write_atomic!(serialize_i64(i64));
227
228    write_atomic!(serialize_u8(u8));
229    write_atomic!(serialize_u16(u16));
230    write_atomic!(serialize_u32(u32));
231    write_atomic!(serialize_u64(u64));
232
233    serde_if_integer128! {
234        write_atomic!(serialize_i128(i128));
235        write_atomic!(serialize_u128(u128));
236    }
237
238    write_atomic!(serialize_f32(f32));
239    write_atomic!(serialize_f64(f64));
240
241    fn serialize_char(self, value: char) -> Result<Self::Ok, Self::Error> {
242        self.serialize_str(&value.to_string())
243    }
244
245    fn serialize_str(mut self, value: &str) -> Result<Self::Ok, Self::Error> {
246        if !value.is_empty() {
247            self.write_str(&escape_item(value, self.target, self.level))?;
248        }
249        Ok(!value.is_empty())
250    }
251
252    fn serialize_bytes(self, _value: &[u8]) -> Result<Self::Ok, Self::Error> {
253        //TODO: Customization point - allow user to decide how to encode bytes
254        Err(DeError::Unsupported(
255            "`serialize_bytes` not supported yet".into(),
256        ))
257    }
258
259    fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
260        Ok(false)
261    }
262
263    fn serialize_some<T: ?Sized + Serialize>(self, value: &T) -> Result<Self::Ok, Self::Error> {
264        value.serialize(self)
265    }
266
267    /// We cannot store anything, so the absence of a unit and presence of it
268    /// does not differ, so serialization of unit returns `Err(Unsupported)`
269    fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
270        Err(DeError::Unsupported(
271            "cannot serialize unit type `()` as an `xs:list` item".into(),
272        ))
273    }
274
275    /// We cannot store anything, so the absence of a unit and presence of it
276    /// does not differ, so serialization of unit returns `Err(Unsupported)`
277    fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok, Self::Error> {
278        Err(DeError::Unsupported(
279            format!(
280                "cannot serialize unit struct `{}` as an `xs:list` item",
281                name
282            )
283            .into(),
284        ))
285    }
286
287    fn serialize_unit_variant(
288        self,
289        _name: &'static str,
290        _variant_index: u32,
291        variant: &'static str,
292    ) -> Result<Self::Ok, Self::Error> {
293        self.serialize_str(variant)
294    }
295
296    fn serialize_newtype_struct<T: ?Sized + Serialize>(
297        self,
298        _name: &'static str,
299        value: &T,
300    ) -> Result<Self::Ok, Self::Error> {
301        value.serialize(self)
302    }
303
304    /// We cannot store both a variant discriminant and a variant value,
305    /// so serialization of enum newtype variant returns `Err(Unsupported)`
306    fn serialize_newtype_variant<T: ?Sized + Serialize>(
307        self,
308        name: &'static str,
309        _variant_index: u32,
310        variant: &'static str,
311        _value: &T,
312    ) -> Result<Self::Ok, DeError> {
313        Err(DeError::Unsupported(
314            format!(
315                "cannot serialize enum newtype variant `{}::{}` as an `xs:list` item",
316                name, variant
317            )
318            .into(),
319        ))
320    }
321
322    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
323        Err(DeError::Unsupported(
324            "cannot serialize sequence as an `xs:list` item".into(),
325        ))
326    }
327
328    fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
329        Err(DeError::Unsupported(
330            "cannot serialize tuple as an `xs:list` item".into(),
331        ))
332    }
333
334    fn serialize_tuple_struct(
335        self,
336        name: &'static str,
337        _len: usize,
338    ) -> Result<Self::SerializeTupleStruct, Self::Error> {
339        Err(DeError::Unsupported(
340            format!(
341                "cannot serialize tuple struct `{}` as an `xs:list` item",
342                name
343            )
344            .into(),
345        ))
346    }
347
348    fn serialize_tuple_variant(
349        self,
350        name: &'static str,
351        _variant_index: u32,
352        variant: &'static str,
353        _len: usize,
354    ) -> Result<Self::SerializeTupleVariant, Self::Error> {
355        Err(DeError::Unsupported(
356            format!(
357                "cannot serialize enum tuple variant `{}::{}` as an `xs:list` item",
358                name, variant
359            )
360            .into(),
361        ))
362    }
363
364    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
365        Err(DeError::Unsupported(
366            "cannot serialize map as an `xs:list` item".into(),
367        ))
368    }
369
370    fn serialize_struct(
371        self,
372        name: &'static str,
373        _len: usize,
374    ) -> Result<Self::SerializeStruct, Self::Error> {
375        Err(DeError::Unsupported(
376            format!("cannot serialize struct `{}` as an `xs:list` item", name).into(),
377        ))
378    }
379
380    fn serialize_struct_variant(
381        self,
382        name: &'static str,
383        _variant_index: u32,
384        variant: &'static str,
385        _len: usize,
386    ) -> Result<Self::SerializeStructVariant, Self::Error> {
387        Err(DeError::Unsupported(
388            format!(
389                "cannot serialize enum struct variant `{}::{}` as an `xs:list` item",
390                name, variant
391            )
392            .into(),
393        ))
394    }
395}
396
397////////////////////////////////////////////////////////////////////////////////////////////////////
398
399/// A serializer for a values representing XSD [simple types], which used in:
400/// - attribute values (`<... ...="value" ...>`)
401/// - text content (`<...>text</...>`)
402/// - CDATA content (`<...><![CDATA[cdata]]></...>`)
403///
404/// [simple types]: https://www.w3.org/TR/xmlschema11-1/#Simple_Type_Definition
405pub struct SimpleTypeSerializer<'i, W: Write> {
406    /// Writer to which this serializer writes content
407    pub writer: W,
408    /// Target for which element is serializing. Affects additional characters to escape.
409    pub target: QuoteTarget,
410    /// Defines which XML characters need to be escaped
411    pub level: QuoteLevel,
412    /// Indent that should be written before the content if content is not an empty string
413    pub(crate) indent: Indent<'i>,
414}
415
416impl<'i, W: Write> SimpleTypeSerializer<'i, W> {
417    fn write_str(&mut self, value: &str) -> Result<(), DeError> {
418        self.indent.write_indent(&mut self.writer)?;
419        Ok(self.writer.write_str(value)?)
420    }
421}
422
423impl<'i, W: Write> Serializer for SimpleTypeSerializer<'i, W> {
424    type Ok = W;
425    type Error = DeError;
426
427    type SerializeSeq = SimpleSeq<'i, W>;
428    type SerializeTuple = SimpleSeq<'i, W>;
429    type SerializeTupleStruct = SimpleSeq<'i, W>;
430    type SerializeTupleVariant = Impossible<Self::Ok, Self::Error>;
431    type SerializeMap = Impossible<Self::Ok, Self::Error>;
432    type SerializeStruct = Impossible<Self::Ok, Self::Error>;
433    type SerializeStructVariant = Impossible<Self::Ok, Self::Error>;
434
435    write_primitive!();
436
437    fn serialize_str(mut self, value: &str) -> Result<Self::Ok, Self::Error> {
438        if !value.is_empty() {
439            self.write_str(&escape_list(value, self.target, self.level))?;
440        }
441        Ok(self.writer)
442    }
443
444    /// Does not write anything
445    fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
446        Ok(self.writer)
447    }
448
449    /// Does not write anything
450    fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
451        Ok(self.writer)
452    }
453
454    /// We cannot store both a variant discriminant and a variant value,
455    /// so serialization of enum newtype variant returns `Err(Unsupported)`
456    fn serialize_newtype_variant<T: ?Sized + Serialize>(
457        self,
458        name: &'static str,
459        _variant_index: u32,
460        variant: &'static str,
461        _value: &T,
462    ) -> Result<Self::Ok, DeError> {
463        Err(DeError::Unsupported(
464            format!("cannot serialize enum newtype variant `{}::{}` as an attribute or text content value", name, variant).into(),
465        ))
466    }
467
468    #[inline]
469    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
470        Ok(SimpleSeq {
471            writer: self.writer,
472            target: self.target,
473            level: self.level,
474            indent: self.indent,
475            is_empty: true,
476        })
477    }
478
479    #[inline]
480    fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
481        self.serialize_seq(None)
482    }
483
484    #[inline]
485    fn serialize_tuple_struct(
486        self,
487        _name: &'static str,
488        _len: usize,
489    ) -> Result<Self::SerializeTupleStruct, Self::Error> {
490        self.serialize_seq(None)
491    }
492
493    fn serialize_tuple_variant(
494        self,
495        name: &'static str,
496        _variant_index: u32,
497        variant: &'static str,
498        _len: usize,
499    ) -> Result<Self::SerializeTupleVariant, Self::Error> {
500        Err(DeError::Unsupported(
501            format!("cannot serialize enum tuple variant `{}::{}` as an attribute or text content value", name, variant).into(),
502        ))
503    }
504
505    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
506        Err(DeError::Unsupported(
507            "cannot serialize map as an attribute or text content value".into(),
508        ))
509    }
510
511    fn serialize_struct(
512        self,
513        name: &'static str,
514        _len: usize,
515    ) -> Result<Self::SerializeStruct, Self::Error> {
516        Err(DeError::Unsupported(
517            format!(
518                "cannot serialize struct `{}` as an attribute or text content value",
519                name
520            )
521            .into(),
522        ))
523    }
524
525    fn serialize_struct_variant(
526        self,
527        name: &'static str,
528        _variant_index: u32,
529        variant: &'static str,
530        _len: usize,
531    ) -> Result<Self::SerializeStructVariant, Self::Error> {
532        Err(DeError::Unsupported(
533            format!("cannot serialize enum struct variant `{}::{}` as an attribute or text content value", name, variant).into(),
534        ))
535    }
536}
537
538/// Serializer for a sequence of atomic values delimited by space
539pub struct SimpleSeq<'i, W: Write> {
540    writer: W,
541    target: QuoteTarget,
542    level: QuoteLevel,
543    /// Indent that should be written before the content if content is not an empty string
544    indent: Indent<'i>,
545    /// If `true`, nothing was written yet to the `writer`
546    is_empty: bool,
547}
548
549impl<'i, W: Write> SerializeSeq for SimpleSeq<'i, W> {
550    type Ok = W;
551    type Error = DeError;
552
553    fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
554    where
555        T: ?Sized + Serialize,
556    {
557        // Write indent for the first element and delimiter for others
558        let indent = if self.is_empty {
559            Some(self.indent.borrow())
560        } else {
561            None
562        };
563        if value.serialize(AtomicSerializer {
564            writer: &mut self.writer,
565            target: self.target,
566            level: self.level,
567            indent,
568        })? {
569            self.is_empty = false;
570        }
571        Ok(())
572    }
573
574    #[inline]
575    fn end(self) -> Result<Self::Ok, Self::Error> {
576        Ok(self.writer)
577    }
578}
579
580impl<'i, W: Write> SerializeTuple for SimpleSeq<'i, W> {
581    type Ok = W;
582    type Error = DeError;
583
584    #[inline]
585    fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
586    where
587        T: ?Sized + Serialize,
588    {
589        SerializeSeq::serialize_element(self, value)
590    }
591
592    #[inline]
593    fn end(self) -> Result<Self::Ok, Self::Error> {
594        SerializeSeq::end(self)
595    }
596}
597
598impl<'i, W: Write> SerializeTupleStruct for SimpleSeq<'i, W> {
599    type Ok = W;
600    type Error = DeError;
601
602    #[inline]
603    fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
604    where
605        T: ?Sized + Serialize,
606    {
607        SerializeSeq::serialize_element(self, value)
608    }
609
610    #[inline]
611    fn end(self) -> Result<Self::Ok, Self::Error> {
612        SerializeSeq::end(self)
613    }
614}
615
616impl<'i, W: Write> SerializeTupleVariant for SimpleSeq<'i, W> {
617    type Ok = W;
618    type Error = DeError;
619
620    #[inline]
621    fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
622    where
623        T: ?Sized + Serialize,
624    {
625        SerializeSeq::serialize_element(self, value)
626    }
627
628    #[inline]
629    fn end(self) -> Result<Self::Ok, Self::Error> {
630        SerializeSeq::end(self)
631    }
632}
633
634////////////////////////////////////////////////////////////////////////////////////////////////////
635
636#[cfg(test)]
637mod tests {
638    use super::*;
639    use crate::utils::Bytes;
640    use serde::Serialize;
641    use std::collections::BTreeMap;
642
643    #[derive(Debug, Serialize, PartialEq)]
644    struct Unit;
645
646    #[derive(Debug, Serialize, PartialEq)]
647    struct Newtype(usize);
648
649    #[derive(Debug, Serialize, PartialEq)]
650    struct Tuple(&'static str, usize);
651
652    #[derive(Debug, Serialize, PartialEq)]
653    struct Struct {
654        key: &'static str,
655        val: usize,
656    }
657
658    #[derive(Debug, Serialize, PartialEq)]
659    enum Enum {
660        Unit,
661        #[serde(rename = "<\"&'>")]
662        UnitEscaped,
663        Newtype(usize),
664        Tuple(&'static str, usize),
665        Struct {
666            key: &'static str,
667            val: usize,
668        },
669    }
670
671    mod escape_item {
672        use super::*;
673
674        mod full {
675            use super::*;
676            use pretty_assertions::assert_eq;
677
678            #[test]
679            fn text() {
680                assert_eq!(
681                    escape_item("text<\"'&> \t\n\rtext", QuoteTarget::Text, QuoteLevel::Full),
682                    "text&lt;&quot;&apos;&amp;&gt;&#32;&#9;&#10;&#13;text"
683                );
684            }
685
686            #[test]
687            fn double_quote_attr() {
688                assert_eq!(
689                    escape_item(
690                        "text<\"'&> \t\n\rtext",
691                        QuoteTarget::DoubleQAttr,
692                        QuoteLevel::Full
693                    ),
694                    "text&lt;&quot;&apos;&amp;&gt;&#32;&#9;&#10;&#13;text"
695                );
696            }
697
698            #[test]
699            fn single_quote_attr() {
700                assert_eq!(
701                    escape_item(
702                        "text<\"'&> \t\n\rtext",
703                        QuoteTarget::SingleQAttr,
704                        QuoteLevel::Full
705                    ),
706                    "text&lt;&quot;&apos;&amp;&gt;&#32;&#9;&#10;&#13;text"
707                );
708            }
709        }
710
711        mod partial {
712            use super::*;
713            use pretty_assertions::assert_eq;
714
715            #[test]
716            fn text() {
717                assert_eq!(
718                    escape_item(
719                        "text<\"'&> \t\n\rtext",
720                        QuoteTarget::Text,
721                        QuoteLevel::Partial
722                    ),
723                    "text&lt;\"'&amp;&gt;&#32;&#9;&#10;&#13;text"
724                );
725            }
726
727            #[test]
728            fn double_quote_attr() {
729                assert_eq!(
730                    escape_item(
731                        "text<\"'&> \t\n\rtext",
732                        QuoteTarget::DoubleQAttr,
733                        QuoteLevel::Partial
734                    ),
735                    "text&lt;&quot;'&amp;&gt;&#32;&#9;&#10;&#13;text"
736                );
737            }
738
739            #[test]
740            fn single_quote_attr() {
741                assert_eq!(
742                    escape_item(
743                        "text<\"'&> \t\n\rtext",
744                        QuoteTarget::SingleQAttr,
745                        QuoteLevel::Partial
746                    ),
747                    "text&lt;\"&apos;&amp;&gt;&#32;&#9;&#10;&#13;text"
748                );
749            }
750        }
751
752        mod minimal {
753            use super::*;
754            use pretty_assertions::assert_eq;
755
756            #[test]
757            fn text() {
758                assert_eq!(
759                    escape_item(
760                        "text<\"'&> \t\n\rtext",
761                        QuoteTarget::Text,
762                        QuoteLevel::Minimal
763                    ),
764                    "text&lt;\"'&amp;>&#32;&#9;&#10;&#13;text"
765                );
766            }
767
768            #[test]
769            fn double_quote_attr() {
770                assert_eq!(
771                    escape_item(
772                        "text<\"'&> \t\n\rtext",
773                        QuoteTarget::DoubleQAttr,
774                        QuoteLevel::Minimal
775                    ),
776                    "text&lt;&quot;'&amp;>&#32;&#9;&#10;&#13;text"
777                );
778            }
779
780            #[test]
781            fn single_quote_attr() {
782                assert_eq!(
783                    escape_item(
784                        "text<\"'&> \t\n\rtext",
785                        QuoteTarget::SingleQAttr,
786                        QuoteLevel::Minimal
787                    ),
788                    "text&lt;\"&apos;&amp;>&#32;&#9;&#10;&#13;text"
789                );
790            }
791        }
792    }
793
794    mod escape_list {
795        use super::*;
796
797        mod full {
798            use super::*;
799            use pretty_assertions::assert_eq;
800
801            #[test]
802            fn text() {
803                assert_eq!(
804                    escape_list("text<\"'&> \t\n\rtext", QuoteTarget::Text, QuoteLevel::Full),
805                    "text&lt;&quot;&apos;&amp;&gt; \t\n\rtext"
806                );
807            }
808
809            #[test]
810            fn double_quote_attr() {
811                assert_eq!(
812                    escape_list(
813                        "text<\"'&> \t\n\rtext",
814                        QuoteTarget::DoubleQAttr,
815                        QuoteLevel::Full
816                    ),
817                    "text&lt;&quot;&apos;&amp;&gt; \t\n\rtext"
818                );
819            }
820
821            #[test]
822            fn single_quote_attr() {
823                assert_eq!(
824                    escape_list(
825                        "text<\"'&> \t\n\rtext",
826                        QuoteTarget::SingleQAttr,
827                        QuoteLevel::Full
828                    ),
829                    "text&lt;&quot;&apos;&amp;&gt; \t\n\rtext"
830                );
831            }
832        }
833
834        mod partial {
835            use super::*;
836            use pretty_assertions::assert_eq;
837
838            #[test]
839            fn text() {
840                assert_eq!(
841                    escape_list(
842                        "text<\"'&> \t\n\rtext",
843                        QuoteTarget::Text,
844                        QuoteLevel::Partial
845                    ),
846                    "text&lt;\"'&amp;&gt; \t\n\rtext"
847                );
848            }
849
850            #[test]
851            fn double_quote_attr() {
852                assert_eq!(
853                    escape_list(
854                        "text<\"'&> \t\n\rtext",
855                        QuoteTarget::DoubleQAttr,
856                        QuoteLevel::Partial
857                    ),
858                    "text&lt;&quot;'&amp;&gt; \t\n\rtext"
859                );
860            }
861
862            #[test]
863            fn single_quote_attr() {
864                assert_eq!(
865                    escape_list(
866                        "text<\"'&> \t\n\rtext",
867                        QuoteTarget::SingleQAttr,
868                        QuoteLevel::Partial
869                    ),
870                    "text&lt;\"&apos;&amp;&gt; \t\n\rtext"
871                );
872            }
873        }
874
875        mod minimal {
876            use super::*;
877            use pretty_assertions::assert_eq;
878
879            #[test]
880            fn text() {
881                assert_eq!(
882                    escape_list(
883                        "text<\"'&> \t\n\rtext",
884                        QuoteTarget::Text,
885                        QuoteLevel::Minimal
886                    ),
887                    "text&lt;\"'&amp;> \t\n\rtext"
888                );
889            }
890
891            #[test]
892            fn double_quote_attr() {
893                assert_eq!(
894                    escape_list(
895                        "text<\"'&> \t\n\rtext",
896                        QuoteTarget::DoubleQAttr,
897                        QuoteLevel::Minimal
898                    ),
899                    "text&lt;&quot;'&amp;> \t\n\rtext"
900                );
901            }
902
903            #[test]
904            fn single_quote_attr() {
905                assert_eq!(
906                    escape_list(
907                        "text<\"'&> \t\n\rtext",
908                        QuoteTarget::SingleQAttr,
909                        QuoteLevel::Minimal
910                    ),
911                    "text&lt;\"&apos;&amp;> \t\n\rtext"
912                );
913            }
914        }
915    }
916
917    /// Tests for serialize atomic and union values, as defined in XSD specification
918    mod atomic {
919        use super::*;
920        use pretty_assertions::assert_eq;
921
922        /// Checks that given `$data` successfully serialized as `$expected`
923        macro_rules! serialize_as {
924            ($name:ident: $data:expr => $expected:literal) => {
925                #[test]
926                fn $name() {
927                    let mut buffer = String::new();
928                    let ser = AtomicSerializer {
929                        writer: &mut buffer,
930                        target: QuoteTarget::Text,
931                        level: QuoteLevel::Full,
932                        indent: Some(Indent::None),
933                    };
934
935                    let has_written = $data.serialize(ser).unwrap();
936                    assert_eq!(buffer, $expected);
937                    assert_eq!(has_written, !buffer.is_empty());
938                }
939            };
940        }
941
942        /// Checks that attempt to serialize given `$data` results to a
943        /// serialization error `$kind` with `$reason`
944        macro_rules! err {
945            ($name:ident: $data:expr => $kind:ident($reason:literal)) => {
946                #[test]
947                fn $name() {
948                    let mut buffer = String::new();
949                    let ser = AtomicSerializer {
950                        writer: &mut buffer,
951                        target: QuoteTarget::Text,
952                        level: QuoteLevel::Full,
953                        indent: Some(Indent::None),
954                    };
955
956                    match $data.serialize(ser).unwrap_err() {
957                        DeError::$kind(e) => assert_eq!(e, $reason),
958                        e => panic!(
959                            "Expected `{}({})`, found `{:?}`",
960                            stringify!($kind),
961                            $reason,
962                            e
963                        ),
964                    }
965                    assert_eq!(buffer, "");
966                }
967            };
968        }
969
970        serialize_as!(false_: false => "false");
971        serialize_as!(true_:  true  => "true");
972
973        serialize_as!(i8_:    -42i8                => "-42");
974        serialize_as!(i16_:   -4200i16             => "-4200");
975        serialize_as!(i32_:   -42000000i32         => "-42000000");
976        serialize_as!(i64_:   -42000000000000i64   => "-42000000000000");
977        serialize_as!(isize_: -42000000000000isize => "-42000000000000");
978
979        serialize_as!(u8_:    42u8                => "42");
980        serialize_as!(u16_:   4200u16             => "4200");
981        serialize_as!(u32_:   42000000u32         => "42000000");
982        serialize_as!(u64_:   42000000000000u64   => "42000000000000");
983        serialize_as!(usize_: 42000000000000usize => "42000000000000");
984
985        serde_if_integer128! {
986            serialize_as!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000");
987            serialize_as!(u128_:  420000000000000000000000000000u128 => "420000000000000000000000000000");
988        }
989
990        serialize_as!(f32_: 4.2f32 => "4.2");
991        serialize_as!(f64_: 4.2f64 => "4.2");
992
993        serialize_as!(char_non_escaped: 'h' => "h");
994        serialize_as!(char_lt:   '<' => "&lt;");
995        serialize_as!(char_gt:   '>' => "&gt;");
996        serialize_as!(char_amp:  '&' => "&amp;");
997        serialize_as!(char_apos: '\'' => "&apos;");
998        serialize_as!(char_quot: '"' => "&quot;");
999
1000        serialize_as!(str_non_escaped: "non-escaped-string" => "non-escaped-string");
1001        serialize_as!(str_escaped: "<\"escaped & string'>" => "&lt;&quot;escaped&#32;&amp;&#32;string&apos;&gt;");
1002
1003        err!(bytes: Bytes(b"<\"escaped & bytes'>")
1004            => Unsupported("`serialize_bytes` not supported yet"));
1005
1006        serialize_as!(option_none: Option::<&str>::None => "");
1007        serialize_as!(option_some: Some("non-escaped-string") => "non-escaped-string");
1008
1009        err!(unit: ()
1010            => Unsupported("cannot serialize unit type `()` as an `xs:list` item"));
1011        err!(unit_struct: Unit
1012            => Unsupported("cannot serialize unit struct `Unit` as an `xs:list` item"));
1013
1014        serialize_as!(enum_unit: Enum::Unit => "Unit");
1015        serialize_as!(enum_unit_escaped: Enum::UnitEscaped => "&lt;&quot;&amp;&apos;&gt;");
1016
1017        serialize_as!(newtype: Newtype(42) => "42");
1018        err!(enum_newtype: Enum::Newtype(42)
1019            => Unsupported("cannot serialize enum newtype variant `Enum::Newtype` as an `xs:list` item"));
1020
1021        err!(seq: vec![1, 2, 3]
1022            => Unsupported("cannot serialize sequence as an `xs:list` item"));
1023        err!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
1024            => Unsupported("cannot serialize tuple as an `xs:list` item"));
1025        err!(tuple_struct: Tuple("first", 42)
1026            => Unsupported("cannot serialize tuple struct `Tuple` as an `xs:list` item"));
1027        err!(enum_tuple: Enum::Tuple("first", 42)
1028            => Unsupported("cannot serialize enum tuple variant `Enum::Tuple` as an `xs:list` item"));
1029
1030        err!(map: BTreeMap::from([(1, 2), (3, 4)])
1031            => Unsupported("cannot serialize map as an `xs:list` item"));
1032        err!(struct_: Struct { key: "answer", val: 42 }
1033            => Unsupported("cannot serialize struct `Struct` as an `xs:list` item"));
1034        err!(enum_struct: Enum::Struct { key: "answer", val: 42 }
1035            => Unsupported("cannot serialize enum struct variant `Enum::Struct` as an `xs:list` item"));
1036    }
1037
1038    mod simple_type {
1039        use super::*;
1040        use pretty_assertions::assert_eq;
1041
1042        /// Checks that given `$data` successfully serialized as `$expected`
1043        macro_rules! serialize_as {
1044            ($name:ident: $data:expr => $expected:literal) => {
1045                #[test]
1046                fn $name() {
1047                    let ser = SimpleTypeSerializer {
1048                        writer: String::new(),
1049                        target: QuoteTarget::Text,
1050                        level: QuoteLevel::Full,
1051                        indent: Indent::None,
1052                    };
1053
1054                    let buffer = $data.serialize(ser).unwrap();
1055                    assert_eq!(buffer, $expected);
1056                }
1057            };
1058        }
1059
1060        /// Checks that attempt to serialize given `$data` results to a
1061        /// serialization error `$kind` with `$reason`
1062        macro_rules! err {
1063            ($name:ident: $data:expr => $kind:ident($reason:literal)) => {
1064                #[test]
1065                fn $name() {
1066                    let mut buffer = String::new();
1067                    let ser = SimpleTypeSerializer {
1068                        writer: &mut buffer,
1069                        target: QuoteTarget::Text,
1070                        level: QuoteLevel::Full,
1071                        indent: Indent::None,
1072                    };
1073
1074                    match $data.serialize(ser).unwrap_err() {
1075                        DeError::$kind(e) => assert_eq!(e, $reason),
1076                        e => panic!(
1077                            "Expected `{}({})`, found `{:?}`",
1078                            stringify!($kind),
1079                            $reason,
1080                            e
1081                        ),
1082                    }
1083                    assert_eq!(buffer, "");
1084                }
1085            };
1086        }
1087
1088        serialize_as!(false_: false => "false");
1089        serialize_as!(true_:  true  => "true");
1090
1091        serialize_as!(i8_:    -42i8                => "-42");
1092        serialize_as!(i16_:   -4200i16             => "-4200");
1093        serialize_as!(i32_:   -42000000i32         => "-42000000");
1094        serialize_as!(i64_:   -42000000000000i64   => "-42000000000000");
1095        serialize_as!(isize_: -42000000000000isize => "-42000000000000");
1096
1097        serialize_as!(u8_:    42u8                => "42");
1098        serialize_as!(u16_:   4200u16             => "4200");
1099        serialize_as!(u32_:   42000000u32         => "42000000");
1100        serialize_as!(u64_:   42000000000000u64   => "42000000000000");
1101        serialize_as!(usize_: 42000000000000usize => "42000000000000");
1102
1103        serde_if_integer128! {
1104            serialize_as!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000");
1105            serialize_as!(u128_:  420000000000000000000000000000u128 => "420000000000000000000000000000");
1106        }
1107
1108        serialize_as!(f32_: 4.2f32 => "4.2");
1109        serialize_as!(f64_: 4.2f64 => "4.2");
1110
1111        serialize_as!(char_non_escaped: 'h' => "h");
1112        serialize_as!(char_lt:   '<' => "&lt;");
1113        serialize_as!(char_gt:   '>' => "&gt;");
1114        serialize_as!(char_amp:  '&' => "&amp;");
1115        serialize_as!(char_apos: '\'' => "&apos;");
1116        serialize_as!(char_quot: '"' => "&quot;");
1117
1118        serialize_as!(str_non_escaped: "non-escaped string" => "non-escaped string");
1119        serialize_as!(str_escaped: "<\"escaped & string'>" => "&lt;&quot;escaped &amp; string&apos;&gt;");
1120
1121        err!(bytes: Bytes(b"<\"escaped & bytes'>")
1122            => Unsupported("`serialize_bytes` not supported yet"));
1123
1124        serialize_as!(option_none: Option::<&str>::None => "");
1125        serialize_as!(option_some: Some("non-escaped string") => "non-escaped string");
1126
1127        serialize_as!(unit: () => "");
1128        serialize_as!(unit_struct: Unit => "");
1129
1130        serialize_as!(enum_unit: Enum::Unit => "Unit");
1131        serialize_as!(enum_unit_escaped: Enum::UnitEscaped => "&lt;&quot;&amp;&apos;&gt;");
1132
1133        serialize_as!(newtype: Newtype(42) => "42");
1134        err!(enum_newtype: Enum::Newtype(42)
1135            => Unsupported("cannot serialize enum newtype variant `Enum::Newtype` as an attribute or text content value"));
1136
1137        serialize_as!(seq: vec![1, 2, 3] => "1 2 3");
1138        serialize_as!(seq_empty: Vec::<usize>::new() => "");
1139        serialize_as!(seq_with_1_empty_str: vec![""] => "");
1140        serialize_as!(seq_with_2_empty_strs: vec!["", ""] => "");
1141        serialize_as!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
1142            => "&lt;&quot;&amp;&apos;&gt; with&#9;&#10;&#13;&#32;spaces 3");
1143        serialize_as!(tuple_struct: Tuple("first", 42) => "first 42");
1144        err!(enum_tuple: Enum::Tuple("first", 42)
1145            => Unsupported("cannot serialize enum tuple variant `Enum::Tuple` as an attribute or text content value"));
1146
1147        err!(map: BTreeMap::from([(1, 2), (3, 4)])
1148            => Unsupported("cannot serialize map as an attribute or text content value"));
1149        err!(struct_: Struct { key: "answer", val: 42 }
1150            => Unsupported("cannot serialize struct `Struct` as an attribute or text content value"));
1151        err!(enum_struct: Enum::Struct { key: "answer", val: 42 }
1152            => Unsupported("cannot serialize enum struct variant `Enum::Struct` as an attribute or text content value"));
1153    }
1154
1155    mod simple_seq {
1156        use super::*;
1157        use crate::writer::Indentation;
1158        use pretty_assertions::assert_eq;
1159
1160        #[test]
1161        fn empty_seq() {
1162            let mut buffer = String::new();
1163            let mut indent = Indentation::new(b'*', 2);
1164            indent.grow();
1165            let ser = SimpleSeq {
1166                writer: &mut buffer,
1167                target: QuoteTarget::Text,
1168                level: QuoteLevel::Full,
1169                indent: Indent::Owned(indent),
1170                is_empty: true,
1171            };
1172
1173            SerializeSeq::end(ser).unwrap();
1174            assert_eq!(buffer, "");
1175        }
1176
1177        #[test]
1178        fn all_items_empty() {
1179            let mut buffer = String::new();
1180            let mut indent = Indentation::new(b'*', 2);
1181            indent.grow();
1182            let mut ser = SimpleSeq {
1183                writer: &mut buffer,
1184                target: QuoteTarget::Text,
1185                level: QuoteLevel::Full,
1186                indent: Indent::Owned(indent),
1187                is_empty: true,
1188            };
1189
1190            SerializeSeq::serialize_element(&mut ser, "").unwrap();
1191            SerializeSeq::serialize_element(&mut ser, "").unwrap();
1192            SerializeSeq::serialize_element(&mut ser, "").unwrap();
1193            SerializeSeq::end(ser).unwrap();
1194            assert_eq!(buffer, "");
1195        }
1196
1197        #[test]
1198        fn some_items_empty1() {
1199            let mut buffer = String::new();
1200            let mut indent = Indentation::new(b'*', 2);
1201            indent.grow();
1202            let mut ser = SimpleSeq {
1203                writer: &mut buffer,
1204                target: QuoteTarget::Text,
1205                level: QuoteLevel::Full,
1206                indent: Indent::Owned(indent),
1207                is_empty: true,
1208            };
1209
1210            SerializeSeq::serialize_element(&mut ser, "").unwrap();
1211            SerializeSeq::serialize_element(&mut ser, &1).unwrap();
1212            SerializeSeq::serialize_element(&mut ser, "").unwrap();
1213            SerializeSeq::end(ser).unwrap();
1214            assert_eq!(buffer, "\n**1");
1215        }
1216
1217        #[test]
1218        fn some_items_empty2() {
1219            let mut buffer = String::new();
1220            let mut indent = Indentation::new(b'*', 2);
1221            indent.grow();
1222            let mut ser = SimpleSeq {
1223                writer: &mut buffer,
1224                target: QuoteTarget::Text,
1225                level: QuoteLevel::Full,
1226                indent: Indent::Owned(indent),
1227                is_empty: true,
1228            };
1229
1230            SerializeSeq::serialize_element(&mut ser, &1).unwrap();
1231            SerializeSeq::serialize_element(&mut ser, "").unwrap();
1232            SerializeSeq::serialize_element(&mut ser, &2).unwrap();
1233            SerializeSeq::end(ser).unwrap();
1234            assert_eq!(buffer, "\n**1 2");
1235        }
1236
1237        #[test]
1238        fn items() {
1239            let mut buffer = String::new();
1240            let mut indent = Indentation::new(b'*', 2);
1241            indent.grow();
1242            let mut ser = SimpleSeq {
1243                writer: &mut buffer,
1244                target: QuoteTarget::Text,
1245                level: QuoteLevel::Full,
1246                indent: Indent::Owned(indent),
1247                is_empty: true,
1248            };
1249
1250            SerializeSeq::serialize_element(&mut ser, &1).unwrap();
1251            SerializeSeq::serialize_element(&mut ser, &2).unwrap();
1252            SerializeSeq::serialize_element(&mut ser, &3).unwrap();
1253            SerializeSeq::end(ser).unwrap();
1254            assert_eq!(buffer, "\n**1 2 3");
1255        }
1256    }
1257}