1use crate::escape::escape_char;
7use crate::se::{QuoteLevel, SeError};
8use crate::utils::CDataIterator;
9use serde::ser::{
10 Impossible, Serialize, SerializeSeq, SerializeTuple, SerializeTupleStruct,
11 SerializeTupleVariant, Serializer,
12};
13use serde::serde_if_integer128;
14use std::fmt::{self, Write};
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum QuoteTarget {
18 Text,
20 DoubleQAttr,
22 SingleQAttr,
24 CData,
27}
28
29fn escape_into<W, F>(mut writer: W, value: &str, escape_chars: F) -> fmt::Result
30where
31 W: Write,
32 F: Fn(u8) -> bool,
33{
34 let bytes = value.as_bytes();
35 let mut iter = bytes.iter();
36 let mut pos = 0;
37 while let Some(i) = iter.position(|&b| escape_chars(b)) {
38 let new_pos = pos + i;
39 escape_char(&mut writer, value, pos, new_pos)?;
40 pos = new_pos + 1;
41 }
42
43 if let Some(raw) = value.get(pos..) {
44 writer.write_str(raw)?;
45 }
46 Ok(())
47}
48
49fn escape_item<W>(mut writer: W, value: &str, target: QuoteTarget, level: QuoteLevel) -> fmt::Result
52where
53 W: Write,
54{
55 use QuoteLevel::*;
56 use QuoteTarget::*;
57
58 match (target, level) {
59 (CData, _) => {
60 let mut it = CDataIterator::new(value);
61 if let Some(part) = it.next() {
62 writer.write_str(part)?;
63 }
64 for part in it {
65 writer.write_str("]]><![CDATA[")?;
66 writer.write_str(part)?;
67 }
68 Ok(())
69 }
70 (_, Full) => escape_into(writer, value, |ch| match ch {
71 b' ' | b'\r' | b'\n' | b'\t' => true,
73 b'&' | b'<' | b'>' | b'\'' | b'\"' => true,
75 _ => false,
76 }),
77 (Text, Partial) => escape_into(writer, value, |ch| match ch {
79 b' ' | b'\r' | b'\n' | b'\t' => true,
81 b'&' | b'<' | b'>' => true,
83 _ => false,
84 }),
85 (Text, Minimal) => escape_into(writer, value, |ch| match ch {
86 b' ' | b'\r' | b'\n' | b'\t' => true,
88 b'&' | b'<' => true,
90 _ => false,
91 }),
92 (DoubleQAttr, Partial) => escape_into(writer, value, |ch| match ch {
94 b' ' | b'\r' | b'\n' | b'\t' => true,
96 b'&' | b'<' | b'>' => true,
98 b'"' => true,
100 _ => false,
101 }),
102 (DoubleQAttr, Minimal) => escape_into(writer, value, |ch| match ch {
103 b' ' | b'\r' | b'\n' | b'\t' => true,
105 b'&' | b'<' => true,
107 b'"' => true,
109 _ => false,
110 }),
111 (SingleQAttr, Partial) => escape_into(writer, value, |ch| match ch {
113 b' ' | b'\r' | b'\n' | b'\t' => true,
115 b'&' | b'<' | b'>' => true,
117 b'\'' => true,
119 _ => false,
120 }),
121 (SingleQAttr, Minimal) => escape_into(writer, value, |ch| match ch {
122 b' ' | b'\r' | b'\n' | b'\t' => true,
124 b'&' | b'<' => true,
126 b'\'' => true,
128 _ => false,
129 }),
130 }
131}
132
133fn escape_list<W>(mut writer: W, value: &str, target: QuoteTarget, level: QuoteLevel) -> fmt::Result
135where
136 W: Write,
137{
138 use QuoteLevel::*;
139 use QuoteTarget::*;
140
141 match (target, level) {
142 (CData, _) => {
143 for part in CDataIterator::new(value) {
144 writer.write_str("<![CDATA[")?;
145 writer.write_str(part)?;
146 writer.write_str("]]>")?;
147 }
148 Ok(())
149 }
150 (_, Full) => escape_into(writer, value, |ch| match ch {
151 b'&' | b'<' | b'>' | b'\'' | b'\"' => true,
153 _ => false,
154 }),
155 (Text, Partial) => escape_into(writer, value, |ch| match ch {
157 b'&' | b'<' | b'>' => true,
159 _ => false,
160 }),
161 (Text, Minimal) => escape_into(writer, value, |ch| match ch {
162 b'&' | b'<' => true,
164 _ => false,
165 }),
166 (DoubleQAttr, Partial) => escape_into(writer, value, |ch| match ch {
168 b'&' | b'<' | b'>' => true,
170 b'"' => true,
172 _ => false,
173 }),
174 (DoubleQAttr, Minimal) => escape_into(writer, value, |ch| match ch {
175 b'&' | b'<' => true,
177 b'"' => true,
179 _ => false,
180 }),
181 (SingleQAttr, Partial) => escape_into(writer, value, |ch| match ch {
183 b'&' | b'<' | b'>' => true,
185 b'\'' => true,
187 _ => false,
188 }),
189 (SingleQAttr, Minimal) => escape_into(writer, value, |ch| match ch {
190 b'&' | b'<' => true,
192 b'\'' => true,
194 _ => false,
195 }),
196 }
197}
198
199macro_rules! write_atomic {
202 ($method:ident ( $ty:ty )) => {
203 fn $method(mut self, value: $ty) -> Result<Self::Ok, Self::Error> {
204 self.write_fmt(format_args!("{}", value))?;
205 Ok(true)
206 }
207 };
208}
209
210pub struct AtomicSerializer<W: Write> {
231 pub writer: W,
232 pub target: QuoteTarget,
233 pub level: QuoteLevel,
235 pub(crate) write_delimiter: bool,
237}
238
239impl<W: Write> AtomicSerializer<W> {
240 fn write_delimiter(&mut self) -> fmt::Result {
241 if self.write_delimiter {
242 return self.writer.write_char(' ');
244 }
245 Ok(())
246 }
247 fn write_str(&mut self, value: &str) -> Result<(), SeError> {
248 self.write_delimiter()?;
249 Ok(self.writer.write_str(value)?)
250 }
251 fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<(), SeError> {
252 self.write_delimiter()?;
253 Ok(self.writer.write_fmt(args)?)
254 }
255}
256
257impl<W: Write> Serializer for AtomicSerializer<W> {
258 type Ok = bool;
259 type Error = SeError;
260
261 type SerializeSeq = Impossible<Self::Ok, Self::Error>;
262 type SerializeTuple = Impossible<Self::Ok, Self::Error>;
263 type SerializeTupleStruct = Impossible<Self::Ok, Self::Error>;
264 type SerializeTupleVariant = Impossible<Self::Ok, Self::Error>;
265 type SerializeMap = Impossible<Self::Ok, Self::Error>;
266 type SerializeStruct = Impossible<Self::Ok, Self::Error>;
267 type SerializeStructVariant = Impossible<Self::Ok, Self::Error>;
268
269 fn serialize_bool(mut self, value: bool) -> Result<Self::Ok, Self::Error> {
270 self.write_str(if value { "true" } else { "false" })?;
271 Ok(true)
272 }
273
274 write_atomic!(serialize_i8(i8));
275 write_atomic!(serialize_i16(i16));
276 write_atomic!(serialize_i32(i32));
277 write_atomic!(serialize_i64(i64));
278
279 write_atomic!(serialize_u8(u8));
280 write_atomic!(serialize_u16(u16));
281 write_atomic!(serialize_u32(u32));
282 write_atomic!(serialize_u64(u64));
283
284 serde_if_integer128! {
285 write_atomic!(serialize_i128(i128));
286 write_atomic!(serialize_u128(u128));
287 }
288
289 write_atomic!(serialize_f32(f32));
290 write_atomic!(serialize_f64(f64));
291
292 fn serialize_char(self, value: char) -> Result<Self::Ok, Self::Error> {
293 self.serialize_str(value.encode_utf8(&mut [0u8; 4]))
294 }
295
296 fn serialize_str(mut self, value: &str) -> Result<Self::Ok, Self::Error> {
297 if !value.is_empty() {
298 self.write_delimiter()?;
299 escape_item(self.writer, value, self.target, self.level)?;
300 }
301 Ok(!value.is_empty())
302 }
303
304 fn serialize_bytes(self, _value: &[u8]) -> Result<Self::Ok, Self::Error> {
305 Err(SeError::Unsupported(
307 "`serialize_bytes` not supported yet".into(),
308 ))
309 }
310
311 fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
312 Ok(false)
313 }
314
315 fn serialize_some<T: ?Sized + Serialize>(self, value: &T) -> Result<Self::Ok, Self::Error> {
316 value.serialize(self)
317 }
318
319 fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
322 Err(SeError::Unsupported(
323 "cannot serialize unit type `()` as an `xs:list` item".into(),
324 ))
325 }
326
327 fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok, Self::Error> {
330 Err(SeError::Unsupported(
331 format!(
332 "cannot serialize unit struct `{}` as an `xs:list` item",
333 name
334 )
335 .into(),
336 ))
337 }
338
339 fn serialize_unit_variant(
340 self,
341 _name: &'static str,
342 _variant_index: u32,
343 variant: &'static str,
344 ) -> Result<Self::Ok, Self::Error> {
345 self.serialize_str(variant)
346 }
347
348 fn serialize_newtype_struct<T: ?Sized + Serialize>(
349 self,
350 _name: &'static str,
351 value: &T,
352 ) -> Result<Self::Ok, Self::Error> {
353 value.serialize(self)
354 }
355
356 fn serialize_newtype_variant<T: ?Sized + Serialize>(
359 self,
360 name: &'static str,
361 _variant_index: u32,
362 variant: &'static str,
363 _value: &T,
364 ) -> Result<Self::Ok, SeError> {
365 Err(SeError::Unsupported(
366 format!(
367 "cannot serialize enum newtype variant `{}::{}` as an `xs:list` item",
368 name, variant
369 )
370 .into(),
371 ))
372 }
373
374 fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
375 Err(SeError::Unsupported(
376 "cannot serialize sequence as an `xs:list` item".into(),
377 ))
378 }
379
380 fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
381 Err(SeError::Unsupported(
382 "cannot serialize tuple as an `xs:list` item".into(),
383 ))
384 }
385
386 fn serialize_tuple_struct(
387 self,
388 name: &'static str,
389 _len: usize,
390 ) -> Result<Self::SerializeTupleStruct, Self::Error> {
391 Err(SeError::Unsupported(
392 format!(
393 "cannot serialize tuple struct `{}` as an `xs:list` item",
394 name
395 )
396 .into(),
397 ))
398 }
399
400 fn serialize_tuple_variant(
401 self,
402 name: &'static str,
403 _variant_index: u32,
404 variant: &'static str,
405 _len: usize,
406 ) -> Result<Self::SerializeTupleVariant, Self::Error> {
407 Err(SeError::Unsupported(
408 format!(
409 "cannot serialize enum tuple variant `{}::{}` as an `xs:list` item",
410 name, variant
411 )
412 .into(),
413 ))
414 }
415
416 fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
417 Err(SeError::Unsupported(
418 "cannot serialize map as an `xs:list` item".into(),
419 ))
420 }
421
422 fn serialize_struct(
423 self,
424 name: &'static str,
425 _len: usize,
426 ) -> Result<Self::SerializeStruct, Self::Error> {
427 Err(SeError::Unsupported(
428 format!("cannot serialize struct `{}` as an `xs:list` item", name).into(),
429 ))
430 }
431
432 fn serialize_struct_variant(
433 self,
434 name: &'static str,
435 _variant_index: u32,
436 variant: &'static str,
437 _len: usize,
438 ) -> Result<Self::SerializeStructVariant, Self::Error> {
439 Err(SeError::Unsupported(
440 format!(
441 "cannot serialize enum struct variant `{}::{}` as an `xs:list` item",
442 name, variant
443 )
444 .into(),
445 ))
446 }
447}
448
449pub struct SimpleTypeSerializer<W: Write> {
458 pub writer: W,
460 pub target: QuoteTarget,
462 pub level: QuoteLevel,
464}
465
466impl<W: Write> SimpleTypeSerializer<W> {
467 #[inline]
468 fn write_str(&mut self, value: &str) -> Result<(), SeError> {
469 Ok(self.writer.write_str(value)?)
470 }
471 #[inline]
472 fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<(), SeError> {
473 Ok(self.writer.write_fmt(args)?)
474 }
475}
476
477impl<W: Write> Serializer for SimpleTypeSerializer<W> {
478 type Ok = W;
479 type Error = SeError;
480
481 type SerializeSeq = SimpleSeq<W>;
482 type SerializeTuple = SimpleSeq<W>;
483 type SerializeTupleStruct = SimpleSeq<W>;
484 type SerializeTupleVariant = Impossible<Self::Ok, Self::Error>;
485 type SerializeMap = Impossible<Self::Ok, Self::Error>;
486 type SerializeStruct = Impossible<Self::Ok, Self::Error>;
487 type SerializeStructVariant = Impossible<Self::Ok, Self::Error>;
488
489 write_primitive!();
490
491 fn serialize_str(mut self, value: &str) -> Result<Self::Ok, Self::Error> {
492 if !value.is_empty() {
493 escape_list(&mut self.writer, value, self.target, self.level)?;
494 }
495 Ok(self.writer)
496 }
497
498 fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
500 Ok(self.writer)
501 }
502
503 fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
505 Ok(self.writer)
506 }
507
508 fn serialize_newtype_variant<T: ?Sized + Serialize>(
511 self,
512 name: &'static str,
513 _variant_index: u32,
514 variant: &'static str,
515 _value: &T,
516 ) -> Result<Self::Ok, SeError> {
517 Err(SeError::Unsupported(
518 format!("cannot serialize enum newtype variant `{}::{}` as an attribute or text content value", name, variant).into(),
519 ))
520 }
521
522 #[inline]
523 fn serialize_seq(mut self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
524 if let QuoteTarget::CData = self.target {
525 self.writer.write_str("<![CDATA[")?;
526 }
527 Ok(SimpleSeq {
528 writer: self.writer,
529 target: self.target,
530 level: self.level,
531 is_empty: true,
532 })
533 }
534
535 #[inline]
536 fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
537 self.serialize_seq(None)
538 }
539
540 #[inline]
541 fn serialize_tuple_struct(
542 self,
543 _name: &'static str,
544 _len: usize,
545 ) -> Result<Self::SerializeTupleStruct, Self::Error> {
546 self.serialize_seq(None)
547 }
548
549 fn serialize_tuple_variant(
550 self,
551 name: &'static str,
552 _variant_index: u32,
553 variant: &'static str,
554 _len: usize,
555 ) -> Result<Self::SerializeTupleVariant, Self::Error> {
556 Err(SeError::Unsupported(
557 format!("cannot serialize enum tuple variant `{}::{}` as an attribute or text content value", name, variant).into(),
558 ))
559 }
560
561 fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
562 Err(SeError::Unsupported(
563 "cannot serialize map as an attribute or text content value".into(),
564 ))
565 }
566
567 fn serialize_struct(
568 self,
569 name: &'static str,
570 _len: usize,
571 ) -> Result<Self::SerializeStruct, Self::Error> {
572 Err(SeError::Unsupported(
573 format!(
574 "cannot serialize struct `{}` as an attribute or text content value",
575 name
576 )
577 .into(),
578 ))
579 }
580
581 fn serialize_struct_variant(
582 self,
583 name: &'static str,
584 _variant_index: u32,
585 variant: &'static str,
586 _len: usize,
587 ) -> Result<Self::SerializeStructVariant, Self::Error> {
588 Err(SeError::Unsupported(
589 format!("cannot serialize enum struct variant `{}::{}` as an attribute or text content value", name, variant).into(),
590 ))
591 }
592}
593
594pub struct SimpleSeq<W: Write> {
596 writer: W,
597 target: QuoteTarget,
598 level: QuoteLevel,
599 is_empty: bool,
601}
602
603impl<W: Write> SerializeSeq for SimpleSeq<W> {
604 type Ok = W;
605 type Error = SeError;
606
607 fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
608 where
609 T: ?Sized + Serialize,
610 {
611 if value.serialize(AtomicSerializer {
612 writer: &mut self.writer,
613 target: self.target,
614 level: self.level,
615 write_delimiter: !self.is_empty,
616 })? {
617 self.is_empty = false;
618 }
619 Ok(())
620 }
621
622 #[inline]
623 fn end(mut self) -> Result<Self::Ok, Self::Error> {
624 if let QuoteTarget::CData = self.target {
625 self.writer.write_str("]]>")?;
626 }
627 Ok(self.writer)
628 }
629}
630
631impl<W: Write> SerializeTuple for SimpleSeq<W> {
632 type Ok = W;
633 type Error = SeError;
634
635 #[inline]
636 fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error>
637 where
638 T: ?Sized + Serialize,
639 {
640 SerializeSeq::serialize_element(self, value)
641 }
642
643 #[inline]
644 fn end(self) -> Result<Self::Ok, Self::Error> {
645 SerializeSeq::end(self)
646 }
647}
648
649impl<W: Write> SerializeTupleStruct for SimpleSeq<W> {
650 type Ok = W;
651 type Error = SeError;
652
653 #[inline]
654 fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
655 where
656 T: ?Sized + Serialize,
657 {
658 SerializeSeq::serialize_element(self, value)
659 }
660
661 #[inline]
662 fn end(self) -> Result<Self::Ok, Self::Error> {
663 SerializeSeq::end(self)
664 }
665}
666
667impl<W: Write> SerializeTupleVariant for SimpleSeq<W> {
668 type Ok = W;
669 type Error = SeError;
670
671 #[inline]
672 fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error>
673 where
674 T: ?Sized + Serialize,
675 {
676 SerializeSeq::serialize_element(self, value)
677 }
678
679 #[inline]
680 fn end(self) -> Result<Self::Ok, Self::Error> {
681 SerializeSeq::end(self)
682 }
683}
684
685#[cfg(test)]
688mod tests {
689 use super::*;
690 use crate::utils::Bytes;
691 use serde::Serialize;
692 use std::collections::BTreeMap;
693
694 #[derive(Debug, Serialize, PartialEq)]
695 struct Unit;
696
697 #[derive(Debug, Serialize, PartialEq)]
698 struct Newtype(usize);
699
700 #[derive(Debug, Serialize, PartialEq)]
701 struct Tuple(&'static str, usize);
702
703 #[derive(Debug, Serialize, PartialEq)]
704 struct Struct {
705 key: &'static str,
706 val: usize,
707 }
708
709 #[derive(Debug, Serialize, PartialEq)]
710 enum Enum {
711 Unit,
712 #[serde(rename = "<\"&'>")]
713 UnitEscaped,
714 Newtype(usize),
715 Tuple(&'static str, usize),
716 Struct {
717 key: &'static str,
718 val: usize,
719 },
720 }
721
722 mod escape_item {
723 use super::*;
724 use pretty_assertions::assert_eq;
725
726 fn escape_item(value: &str, target: QuoteTarget, level: QuoteLevel) -> String {
727 let mut result = String::new();
728 super::escape_item(&mut result, value, target, level).unwrap();
729 result
730 }
731
732 mod full {
733 use super::*;
734 use pretty_assertions::assert_eq;
735
736 #[test]
737 fn text() {
738 assert_eq!(
739 escape_item("text<\"'&> \t\n\rtext", QuoteTarget::Text, QuoteLevel::Full),
740 "text<"'&> 	 text"
741 );
742 }
743
744 #[test]
745 fn double_quote_attr() {
746 assert_eq!(
747 escape_item(
748 "text<\"'&> \t\n\rtext",
749 QuoteTarget::DoubleQAttr,
750 QuoteLevel::Full
751 ),
752 "text<"'&> 	 text"
753 );
754 }
755
756 #[test]
757 fn single_quote_attr() {
758 assert_eq!(
759 escape_item(
760 "text<\"'&> \t\n\rtext",
761 QuoteTarget::SingleQAttr,
762 QuoteLevel::Full
763 ),
764 "text<"'&> 	 text"
765 );
766 }
767 }
768
769 mod partial {
770 use super::*;
771 use pretty_assertions::assert_eq;
772
773 #[test]
774 fn text() {
775 assert_eq!(
776 escape_item(
777 "text<\"'&> \t\n\rtext",
778 QuoteTarget::Text,
779 QuoteLevel::Partial
780 ),
781 "text<\"'&> 	 text"
782 );
783 }
784
785 #[test]
786 fn double_quote_attr() {
787 assert_eq!(
788 escape_item(
789 "text<\"'&> \t\n\rtext",
790 QuoteTarget::DoubleQAttr,
791 QuoteLevel::Partial
792 ),
793 "text<"'&> 	 text"
794 );
795 }
796
797 #[test]
798 fn single_quote_attr() {
799 assert_eq!(
800 escape_item(
801 "text<\"'&> \t\n\rtext",
802 QuoteTarget::SingleQAttr,
803 QuoteLevel::Partial
804 ),
805 "text<\"'&> 	 text"
806 );
807 }
808 }
809
810 mod minimal {
811 use super::*;
812 use pretty_assertions::assert_eq;
813
814 #[test]
815 fn text() {
816 assert_eq!(
817 escape_item(
818 "text<\"'&> \t\n\rtext",
819 QuoteTarget::Text,
820 QuoteLevel::Minimal
821 ),
822 "text<\"'&> 	 text"
823 );
824 }
825
826 #[test]
827 fn double_quote_attr() {
828 assert_eq!(
829 escape_item(
830 "text<\"'&> \t\n\rtext",
831 QuoteTarget::DoubleQAttr,
832 QuoteLevel::Minimal
833 ),
834 "text<"'&> 	 text"
835 );
836 }
837
838 #[test]
839 fn single_quote_attr() {
840 assert_eq!(
841 escape_item(
842 "text<\"'&> \t\n\rtext",
843 QuoteTarget::SingleQAttr,
844 QuoteLevel::Minimal
845 ),
846 "text<\"'&> 	 text"
847 );
848 }
849 }
850
851 #[test]
853 fn cdata() {
854 assert_eq!(
855 escape_item(
856 "text<\"'&>]]> \t\n\rtext",
857 QuoteTarget::CData,
858 QuoteLevel::Full
859 ),
860 "text<\"'&>]]]]><![CDATA[> \t\n\rtext"
861 );
862 assert_eq!(
863 escape_item(
864 "text<\"'&>]]> \t\n\rtext",
865 QuoteTarget::CData,
866 QuoteLevel::Partial
867 ),
868 "text<\"'&>]]]]><![CDATA[> \t\n\rtext"
869 );
870 assert_eq!(
871 escape_item(
872 "text<\"'&>]]> \t\n\rtext",
873 QuoteTarget::CData,
874 QuoteLevel::Minimal
875 ),
876 "text<\"'&>]]]]><![CDATA[> \t\n\rtext"
877 );
878 }
879 }
880
881 mod escape_list {
882 use super::*;
883 use pretty_assertions::assert_eq;
884
885 fn escape_list(value: &str, target: QuoteTarget, level: QuoteLevel) -> String {
886 let mut result = String::new();
887 super::escape_list(&mut result, value, target, level).unwrap();
888 result
889 }
890
891 mod full {
892 use super::*;
893 use pretty_assertions::assert_eq;
894
895 #[test]
896 fn text() {
897 assert_eq!(
898 escape_list("text<\"'&> \t\n\rtext", QuoteTarget::Text, QuoteLevel::Full),
899 "text<"'&> \t\n\rtext"
900 );
901 }
902
903 #[test]
904 fn double_quote_attr() {
905 assert_eq!(
906 escape_list(
907 "text<\"'&> \t\n\rtext",
908 QuoteTarget::DoubleQAttr,
909 QuoteLevel::Full
910 ),
911 "text<"'&> \t\n\rtext"
912 );
913 }
914
915 #[test]
916 fn single_quote_attr() {
917 assert_eq!(
918 escape_list(
919 "text<\"'&> \t\n\rtext",
920 QuoteTarget::SingleQAttr,
921 QuoteLevel::Full
922 ),
923 "text<"'&> \t\n\rtext"
924 );
925 }
926 }
927
928 mod partial {
929 use super::*;
930 use pretty_assertions::assert_eq;
931
932 #[test]
933 fn text() {
934 assert_eq!(
935 escape_list(
936 "text<\"'&> \t\n\rtext",
937 QuoteTarget::Text,
938 QuoteLevel::Partial
939 ),
940 "text<\"'&> \t\n\rtext"
941 );
942 }
943
944 #[test]
945 fn double_quote_attr() {
946 assert_eq!(
947 escape_list(
948 "text<\"'&> \t\n\rtext",
949 QuoteTarget::DoubleQAttr,
950 QuoteLevel::Partial
951 ),
952 "text<"'&> \t\n\rtext"
953 );
954 }
955
956 #[test]
957 fn single_quote_attr() {
958 assert_eq!(
959 escape_list(
960 "text<\"'&> \t\n\rtext",
961 QuoteTarget::SingleQAttr,
962 QuoteLevel::Partial
963 ),
964 "text<\"'&> \t\n\rtext"
965 );
966 }
967 }
968
969 mod minimal {
970 use super::*;
971 use pretty_assertions::assert_eq;
972
973 #[test]
974 fn text() {
975 assert_eq!(
976 escape_list(
977 "text<\"'&> \t\n\rtext",
978 QuoteTarget::Text,
979 QuoteLevel::Minimal
980 ),
981 "text<\"'&> \t\n\rtext"
982 );
983 }
984
985 #[test]
986 fn double_quote_attr() {
987 assert_eq!(
988 escape_list(
989 "text<\"'&> \t\n\rtext",
990 QuoteTarget::DoubleQAttr,
991 QuoteLevel::Minimal
992 ),
993 "text<"'&> \t\n\rtext"
994 );
995 }
996
997 #[test]
998 fn single_quote_attr() {
999 assert_eq!(
1000 escape_list(
1001 "text<\"'&> \t\n\rtext",
1002 QuoteTarget::SingleQAttr,
1003 QuoteLevel::Minimal
1004 ),
1005 "text<\"'&> \t\n\rtext"
1006 );
1007 }
1008 }
1009
1010 #[test]
1011 fn cdata() {
1012 assert_eq!(
1013 escape_list(
1014 "text<\"'&>]]> \t\n\rtext",
1015 QuoteTarget::CData,
1016 QuoteLevel::Full
1017 ),
1018 "<![CDATA[text<\"'&>]]]]><![CDATA[> \t\n\rtext]]>"
1019 );
1020 assert_eq!(
1021 escape_list(
1022 "text<\"'&>]]> \t\n\rtext",
1023 QuoteTarget::CData,
1024 QuoteLevel::Partial
1025 ),
1026 "<![CDATA[text<\"'&>]]]]><![CDATA[> \t\n\rtext]]>"
1027 );
1028 assert_eq!(
1029 escape_list(
1030 "text<\"'&>]]> \t\n\rtext",
1031 QuoteTarget::CData,
1032 QuoteLevel::Minimal
1033 ),
1034 "<![CDATA[text<\"'&>]]]]><![CDATA[> \t\n\rtext]]>"
1035 );
1036 }
1037 }
1038
1039 mod atomic {
1041 use super::*;
1042 use pretty_assertions::assert_eq;
1043
1044 macro_rules! serialize_as {
1046 ($name:ident: $data:expr => $expected:literal) => {
1047 #[test]
1048 fn $name() {
1049 let mut buffer = String::new();
1050 let ser = AtomicSerializer {
1051 writer: &mut buffer,
1052 target: QuoteTarget::Text,
1053 level: QuoteLevel::Full,
1054 write_delimiter: false,
1055 };
1056
1057 let has_written = $data.serialize(ser).unwrap();
1058 assert_eq!(buffer, $expected);
1059 assert_eq!(has_written, !buffer.is_empty());
1060 }
1061 };
1062 }
1063
1064 macro_rules! err {
1067 ($name:ident: $data:expr => $kind:ident($reason:literal)) => {
1068 #[test]
1069 fn $name() {
1070 let mut buffer = String::new();
1071 let ser = AtomicSerializer {
1072 writer: &mut buffer,
1073 target: QuoteTarget::Text,
1074 level: QuoteLevel::Full,
1075 write_delimiter: false,
1076 };
1077
1078 match $data.serialize(ser).unwrap_err() {
1079 SeError::$kind(e) => assert_eq!(e, $reason),
1080 e => panic!(
1081 "Expected `Err({}({}))`, but got `{:?}`",
1082 stringify!($kind),
1083 $reason,
1084 e
1085 ),
1086 }
1087 assert_eq!(buffer, "");
1088 }
1089 };
1090 }
1091
1092 serialize_as!(false_: false => "false");
1093 serialize_as!(true_: true => "true");
1094
1095 serialize_as!(i8_: -42i8 => "-42");
1096 serialize_as!(i16_: -4200i16 => "-4200");
1097 serialize_as!(i32_: -42000000i32 => "-42000000");
1098 serialize_as!(i64_: -42000000000000i64 => "-42000000000000");
1099 serialize_as!(isize_: -42000000isize => "-42000000");
1100
1101 serialize_as!(u8_: 42u8 => "42");
1102 serialize_as!(u16_: 4200u16 => "4200");
1103 serialize_as!(u32_: 42000000u32 => "42000000");
1104 serialize_as!(u64_: 42000000000000u64 => "42000000000000");
1105 serialize_as!(usize_: 42000000usize => "42000000");
1106
1107 serde_if_integer128! {
1108 serialize_as!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000");
1109 serialize_as!(u128_: 420000000000000000000000000000u128 => "420000000000000000000000000000");
1110 }
1111
1112 serialize_as!(f32_: 4.2f32 => "4.2");
1113 serialize_as!(f64_: 4.2f64 => "4.2");
1114
1115 serialize_as!(char_non_escaped: 'h' => "h");
1116 serialize_as!(char_lt: '<' => "<");
1117 serialize_as!(char_gt: '>' => ">");
1118 serialize_as!(char_amp: '&' => "&");
1119 serialize_as!(char_apos: '\'' => "'");
1120 serialize_as!(char_quot: '"' => """);
1121
1122 serialize_as!(str_non_escaped: "non-escaped-string" => "non-escaped-string");
1123 serialize_as!(str_escaped: "<\"escaped & string'>" => "<"escaped & string'>");
1124
1125 err!(bytes: Bytes(b"<\"escaped & bytes'>")
1126 => Unsupported("`serialize_bytes` not supported yet"));
1127
1128 serialize_as!(option_none: Option::<&str>::None => "");
1129 serialize_as!(option_some: Some("non-escaped-string") => "non-escaped-string");
1130
1131 err!(unit: ()
1132 => Unsupported("cannot serialize unit type `()` as an `xs:list` item"));
1133 err!(unit_struct: Unit
1134 => Unsupported("cannot serialize unit struct `Unit` as an `xs:list` item"));
1135
1136 serialize_as!(enum_unit: Enum::Unit => "Unit");
1137 serialize_as!(enum_unit_escaped: Enum::UnitEscaped => "<"&'>");
1138
1139 serialize_as!(newtype: Newtype(42) => "42");
1140 err!(enum_newtype: Enum::Newtype(42)
1141 => Unsupported("cannot serialize enum newtype variant `Enum::Newtype` as an `xs:list` item"));
1142
1143 err!(seq: vec![1, 2, 3]
1144 => Unsupported("cannot serialize sequence as an `xs:list` item"));
1145 err!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
1146 => Unsupported("cannot serialize tuple as an `xs:list` item"));
1147 err!(tuple_struct: Tuple("first", 42)
1148 => Unsupported("cannot serialize tuple struct `Tuple` as an `xs:list` item"));
1149 err!(enum_tuple: Enum::Tuple("first", 42)
1150 => Unsupported("cannot serialize enum tuple variant `Enum::Tuple` as an `xs:list` item"));
1151
1152 err!(map: BTreeMap::from([(1, 2), (3, 4)])
1153 => Unsupported("cannot serialize map as an `xs:list` item"));
1154 err!(struct_: Struct { key: "answer", val: 42 }
1155 => Unsupported("cannot serialize struct `Struct` as an `xs:list` item"));
1156 err!(enum_struct: Enum::Struct { key: "answer", val: 42 }
1157 => Unsupported("cannot serialize enum struct variant `Enum::Struct` as an `xs:list` item"));
1158 }
1159
1160 mod simple_type {
1161 use super::*;
1162 use pretty_assertions::assert_eq;
1163
1164 macro_rules! serialize_as {
1166 ($name:ident: $data:expr => $expected:literal) => {
1167 #[test]
1168 fn $name() {
1169 let ser = SimpleTypeSerializer {
1170 writer: String::new(),
1171 target: QuoteTarget::Text,
1172 level: QuoteLevel::Full,
1173 };
1174
1175 let buffer = $data.serialize(ser).unwrap();
1176 assert_eq!(buffer, $expected);
1177 }
1178 };
1179 }
1180
1181 macro_rules! err {
1184 ($name:ident: $data:expr => $kind:ident($reason:literal)) => {
1185 #[test]
1186 fn $name() {
1187 let mut buffer = String::new();
1188 let ser = SimpleTypeSerializer {
1189 writer: &mut buffer,
1190 target: QuoteTarget::Text,
1191 level: QuoteLevel::Full,
1192 };
1193
1194 match $data.serialize(ser).unwrap_err() {
1195 SeError::$kind(e) => assert_eq!(e, $reason),
1196 e => panic!(
1197 "Expected `Err({}({}))`, but got `{:?}`",
1198 stringify!($kind),
1199 $reason,
1200 e
1201 ),
1202 }
1203 assert_eq!(buffer, "");
1204 }
1205 };
1206 }
1207
1208 serialize_as!(false_: false => "false");
1209 serialize_as!(true_: true => "true");
1210
1211 serialize_as!(i8_: -42i8 => "-42");
1212 serialize_as!(i16_: -4200i16 => "-4200");
1213 serialize_as!(i32_: -42000000i32 => "-42000000");
1214 serialize_as!(i64_: -42000000000000i64 => "-42000000000000");
1215 serialize_as!(isize_: -42000000isize => "-42000000");
1216
1217 serialize_as!(u8_: 42u8 => "42");
1218 serialize_as!(u16_: 4200u16 => "4200");
1219 serialize_as!(u32_: 42000000u32 => "42000000");
1220 serialize_as!(u64_: 42000000000000u64 => "42000000000000");
1221 serialize_as!(usize_: 42000000usize => "42000000");
1222
1223 serde_if_integer128! {
1224 serialize_as!(i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000");
1225 serialize_as!(u128_: 420000000000000000000000000000u128 => "420000000000000000000000000000");
1226 }
1227
1228 serialize_as!(f32_: 4.2f32 => "4.2");
1229 serialize_as!(f64_: 4.2f64 => "4.2");
1230
1231 serialize_as!(char_non_escaped: 'h' => "h");
1232 serialize_as!(char_lt: '<' => "<");
1233 serialize_as!(char_gt: '>' => ">");
1234 serialize_as!(char_amp: '&' => "&");
1235 serialize_as!(char_apos: '\'' => "'");
1236 serialize_as!(char_quot: '"' => """);
1237
1238 serialize_as!(str_non_escaped: "non-escaped string" => "non-escaped string");
1239 serialize_as!(str_escaped: "<\"escaped & string'>" => "<"escaped & string'>");
1240
1241 err!(bytes: Bytes(b"<\"escaped & bytes'>")
1242 => Unsupported("`serialize_bytes` not supported yet"));
1243
1244 serialize_as!(option_none: Option::<&str>::None => "");
1245 serialize_as!(option_some: Some("non-escaped string") => "non-escaped string");
1246
1247 serialize_as!(unit: () => "");
1248 serialize_as!(unit_struct: Unit => "");
1249
1250 serialize_as!(enum_unit: Enum::Unit => "Unit");
1251 serialize_as!(enum_unit_escaped: Enum::UnitEscaped => "<"&'>");
1252
1253 serialize_as!(newtype: Newtype(42) => "42");
1254 err!(enum_newtype: Enum::Newtype(42)
1255 => Unsupported("cannot serialize enum newtype variant `Enum::Newtype` as an attribute or text content value"));
1256
1257 serialize_as!(seq: vec![1, 2, 3] => "1 2 3");
1258 serialize_as!(seq_empty: Vec::<usize>::new() => "");
1259 serialize_as!(seq_with_1_empty_str: vec![""] => "");
1260 serialize_as!(seq_with_2_empty_strs: vec!["", ""] => "");
1261 serialize_as!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
1262 => "<"&'> with	  spaces 3");
1263 serialize_as!(tuple_struct: Tuple("first", 42) => "first 42");
1264 err!(enum_tuple: Enum::Tuple("first", 42)
1265 => Unsupported("cannot serialize enum tuple variant `Enum::Tuple` as an attribute or text content value"));
1266
1267 err!(map: BTreeMap::from([(1, 2), (3, 4)])
1268 => Unsupported("cannot serialize map as an attribute or text content value"));
1269 err!(struct_: Struct { key: "answer", val: 42 }
1270 => Unsupported("cannot serialize struct `Struct` as an attribute or text content value"));
1271 err!(enum_struct: Enum::Struct { key: "answer", val: 42 }
1272 => Unsupported("cannot serialize enum struct variant `Enum::Struct` as an attribute or text content value"));
1273 }
1274
1275 mod simple_seq {
1276 use super::*;
1277 use pretty_assertions::assert_eq;
1278
1279 #[test]
1280 fn empty_seq() {
1281 let mut buffer = String::new();
1282 let ser = SimpleSeq {
1283 writer: &mut buffer,
1284 target: QuoteTarget::Text,
1285 level: QuoteLevel::Full,
1286 is_empty: true,
1287 };
1288
1289 SerializeSeq::end(ser).unwrap();
1290 assert_eq!(buffer, "");
1291 }
1292
1293 #[test]
1294 fn all_items_empty() {
1295 let mut buffer = String::new();
1296 let mut ser = SimpleSeq {
1297 writer: &mut buffer,
1298 target: QuoteTarget::Text,
1299 level: QuoteLevel::Full,
1300 is_empty: true,
1301 };
1302
1303 SerializeSeq::serialize_element(&mut ser, "").unwrap();
1304 SerializeSeq::serialize_element(&mut ser, "").unwrap();
1305 SerializeSeq::serialize_element(&mut ser, "").unwrap();
1306 SerializeSeq::end(ser).unwrap();
1307 assert_eq!(buffer, "");
1308 }
1309
1310 #[test]
1311 fn some_items_empty1() {
1312 let mut buffer = String::new();
1313 let mut ser = SimpleSeq {
1314 writer: &mut buffer,
1315 target: QuoteTarget::Text,
1316 level: QuoteLevel::Full,
1317 is_empty: true,
1318 };
1319
1320 SerializeSeq::serialize_element(&mut ser, "").unwrap();
1321 SerializeSeq::serialize_element(&mut ser, &1).unwrap();
1322 SerializeSeq::serialize_element(&mut ser, "").unwrap();
1323 SerializeSeq::end(ser).unwrap();
1324 assert_eq!(buffer, "1");
1325 }
1326
1327 #[test]
1328 fn some_items_empty2() {
1329 let mut buffer = String::new();
1330 let mut ser = SimpleSeq {
1331 writer: &mut buffer,
1332 target: QuoteTarget::Text,
1333 level: QuoteLevel::Full,
1334 is_empty: true,
1335 };
1336
1337 SerializeSeq::serialize_element(&mut ser, &1).unwrap();
1338 SerializeSeq::serialize_element(&mut ser, "").unwrap();
1339 SerializeSeq::serialize_element(&mut ser, &2).unwrap();
1340 SerializeSeq::end(ser).unwrap();
1341 assert_eq!(buffer, "1 2");
1342 }
1343
1344 #[test]
1345 fn items() {
1346 let mut buffer = String::new();
1347 let mut ser = SimpleSeq {
1348 writer: &mut buffer,
1349 target: QuoteTarget::Text,
1350 level: QuoteLevel::Full,
1351 is_empty: true,
1352 };
1353
1354 SerializeSeq::serialize_element(&mut ser, &1).unwrap();
1355 SerializeSeq::serialize_element(&mut ser, &2).unwrap();
1356 SerializeSeq::serialize_element(&mut ser, &3).unwrap();
1357 SerializeSeq::end(ser).unwrap();
1358 assert_eq!(buffer, "1 2 3");
1359 }
1360 }
1361
1362 mod cdata {
1363 use super::*;
1364 use pretty_assertions::assert_eq;
1365
1366 macro_rules! serialize_as_cdata {
1367 ($name:ident: $data:expr => $expected:literal) => {
1368 #[test]
1369 fn $name() {
1370 let ser = SimpleTypeSerializer {
1371 writer: String::new(),
1372 target: QuoteTarget::CData,
1373 level: QuoteLevel::Full,
1374 };
1375
1376 let buffer = $data.serialize(ser).unwrap();
1377 assert_eq!(buffer, $expected);
1378 }
1379 };
1380 }
1381
1382 serialize_as_cdata!(empty_string: "" => "");
1383 serialize_as_cdata!(simple_text: "Hello World" => "<![CDATA[Hello World]]>");
1384 serialize_as_cdata!(with_markup: "<tag>content</tag>" => "<![CDATA[<tag>content</tag>]]>");
1385 serialize_as_cdata!(with_ampersand: "Tom & Jerry" => "<![CDATA[Tom & Jerry]]>");
1386 serialize_as_cdata!(with_quotes: r#"He said "Hello""# => r#"<![CDATA[He said "Hello"]]>"#);
1387 serialize_as_cdata!(all_xml_chars: "<>&\"'" => "<![CDATA[<>&\"']]>");
1388
1389 serialize_as_cdata!(with_cdata_end: "foo]]>bar" => "<![CDATA[foo]]]]><![CDATA[>bar]]>");
1390 serialize_as_cdata!(multiple_cdata_ends: "a]]>b]]>c" => "<![CDATA[a]]]]><![CDATA[>b]]]]><![CDATA[>c]]>");
1391 serialize_as_cdata!(starts_with_cdata_end: "]]>hello" => "<![CDATA[]]]]><![CDATA[>hello]]>");
1392 serialize_as_cdata!(ends_with_cdata_end: "hello]]>" => "<![CDATA[hello]]]]><![CDATA[>]]>");
1393 serialize_as_cdata!(only_cdata_end: "]]>" => "<![CDATA[]]]]><![CDATA[>]]>");
1394
1395 serialize_as_cdata!(seq_basic: vec!["foo", "bar", "baz"] => "<![CDATA[foo bar baz]]>");
1396 serialize_as_cdata!(seq_with_space: vec!["hello world", "hello\tworld", "world"] => "<![CDATA[hello world hello\tworld world]]>");
1397 serialize_as_cdata!(seq_with_markup_chars: vec!["<tag>", "&entity", "\"quoted\""] => "<![CDATA[<tag> &entity \"quoted\"]]>");
1398 serialize_as_cdata!(seq_with_cdata_end_split: vec!["foo]]>bar", "test"] => "<![CDATA[foo]]]]><![CDATA[>bar test]]>");
1399 serialize_as_cdata!(tuple_cdata: ("first", 42, "third") => "<![CDATA[first 42 third]]>");
1400 }
1401}