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