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