3
3
use crate :: errors:: serialize:: DeError ;
4
4
use crate :: se:: element:: { ElementSerializer , Struct } ;
5
5
use crate :: se:: simple_type:: { QuoteTarget , SimpleTypeSerializer } ;
6
- use crate :: se:: { QuoteLevel , XmlName } ;
6
+ use crate :: se:: { Indent , QuoteLevel , XmlName } ;
7
7
use serde:: ser:: {
8
8
Impossible , Serialize , SerializeSeq , SerializeTuple , SerializeTupleStruct , Serializer ,
9
9
} ;
@@ -39,23 +39,36 @@ macro_rules! write_primitive {
39
39
/// and maps serialized. Unlike `SimpleTypeSerializer` it supports any types in
40
40
/// sequences and serializes them as list of elements, but that has drawbacks.
41
41
/// Sequence of primitives would be serialized without delimiters and it will be
42
- /// impossible to distinguish between them.
43
- pub struct ContentSerializer < W : Write > {
42
+ /// impossible to distinguish between them. Even worse, when serializing with
43
+ /// indent, sequence of strings become one big string with additional content
44
+ /// and it would be impossible to distinguish between content of the original
45
+ /// strings and inserted indent characters.
46
+ pub struct ContentSerializer < ' i , W : Write > {
44
47
pub writer : W ,
45
48
/// Defines which XML characters need to be escaped in text content
46
49
pub level : QuoteLevel ,
50
+ /// Current indentation level
51
+ pub ( super ) indent : Indent < ' i > ,
52
+ /// If `true`, then current indent will be written before write the content,
53
+ /// but only if content is not empty
54
+ pub write_indent : bool ,
47
55
//TODO: add settings to disallow consequent serialization of primitives
48
56
}
49
57
50
- impl < W : Write > ContentSerializer < W > {
58
+ impl < ' i , W : Write > ContentSerializer < ' i , W > {
51
59
/// Turns this serializer into serializer of a text content
52
60
#[ inline]
53
- pub fn into_simple_type_serializer ( self ) -> SimpleTypeSerializer < W > {
61
+ pub fn into_simple_type_serializer ( self ) -> SimpleTypeSerializer < ' i , W > {
54
62
//TODO: Customization point: choose between CDATA and Text representation
55
63
SimpleTypeSerializer {
56
64
writer : self . writer ,
57
65
target : QuoteTarget :: Text ,
58
66
level : self . level ,
67
+ indent : if self . write_indent {
68
+ self . indent
69
+ } else {
70
+ Indent :: None
71
+ } ,
59
72
}
60
73
}
61
74
@@ -66,12 +79,15 @@ impl<W: Write> ContentSerializer<W> {
66
79
ContentSerializer {
67
80
writer : & mut self . writer ,
68
81
level : self . level ,
82
+ indent : self . indent . borrow ( ) ,
83
+ write_indent : self . write_indent ,
69
84
}
70
85
}
71
86
72
87
/// Writes `name` as self-closed tag
73
88
#[ inline]
74
89
pub ( super ) fn write_empty ( mut self , name : XmlName ) -> Result < W , DeError > {
90
+ self . write_indent ( ) ?;
75
91
self . writer . write_char ( '<' ) ?;
76
92
self . writer . write_str ( name. 0 ) ?;
77
93
self . writer . write_str ( "/>" ) ?;
@@ -81,8 +97,9 @@ impl<W: Write> ContentSerializer<W> {
81
97
/// Writes simple type content between `name` tags
82
98
pub ( super ) fn write_wrapped < S > ( mut self , name : XmlName , serialize : S ) -> Result < W , DeError >
83
99
where
84
- S : FnOnce ( SimpleTypeSerializer < W > ) -> Result < W , DeError > ,
100
+ S : FnOnce ( SimpleTypeSerializer < ' i , W > ) -> Result < W , DeError > ,
85
101
{
102
+ self . write_indent ( ) ?;
86
103
self . writer . write_char ( '<' ) ?;
87
104
self . writer . write_str ( name. 0 ) ?;
88
105
self . writer . write_char ( '>' ) ?;
@@ -94,19 +111,27 @@ impl<W: Write> ContentSerializer<W> {
94
111
writer. write_char ( '>' ) ?;
95
112
Ok ( writer)
96
113
}
114
+
115
+ pub ( super ) fn write_indent ( & mut self ) -> Result < ( ) , DeError > {
116
+ if self . write_indent {
117
+ self . indent . write_indent ( & mut self . writer ) ?;
118
+ self . write_indent = false ;
119
+ }
120
+ Ok ( ( ) )
121
+ }
97
122
}
98
123
99
- impl < W : Write > Serializer for ContentSerializer < W > {
124
+ impl < ' i , W : Write > Serializer for ContentSerializer < ' i , W > {
100
125
type Ok = W ;
101
126
type Error = DeError ;
102
127
103
128
type SerializeSeq = Self ;
104
129
type SerializeTuple = Self ;
105
130
type SerializeTupleStruct = Self ;
106
- type SerializeTupleVariant = ElementSerializer < ' static , W > ;
131
+ type SerializeTupleVariant = ElementSerializer < ' i , W > ;
107
132
type SerializeMap = Impossible < Self :: Ok , Self :: Error > ;
108
133
type SerializeStruct = Impossible < Self :: Ok , Self :: Error > ;
109
- type SerializeStructVariant = Struct < ' static , W > ;
134
+ type SerializeStructVariant = Struct < ' i , W > ;
110
135
111
136
write_primitive ! ( serialize_bool( bool ) ) ;
112
137
@@ -129,9 +154,17 @@ impl<W: Write> Serializer for ContentSerializer<W> {
129
154
write_primitive ! ( serialize_f64( f64 ) ) ;
130
155
131
156
write_primitive ! ( serialize_char( char ) ) ;
132
- write_primitive ! ( serialize_str( & str ) ) ;
133
157
write_primitive ! ( serialize_bytes( & [ u8 ] ) ) ;
134
158
159
+ #[ inline]
160
+ fn serialize_str ( self , value : & str ) -> Result < Self :: Ok , Self :: Error > {
161
+ if value. is_empty ( ) {
162
+ Ok ( self . writer )
163
+ } else {
164
+ self . into_simple_type_serializer ( ) . serialize_str ( value)
165
+ }
166
+ }
167
+
135
168
/// Does not write anything
136
169
#[ inline]
137
170
fn serialize_none ( self ) -> Result < Self :: Ok , Self :: Error > {
@@ -261,7 +294,7 @@ impl<W: Write> Serializer for ContentSerializer<W> {
261
294
}
262
295
}
263
296
264
- impl < W : Write > SerializeSeq for ContentSerializer < W > {
297
+ impl < ' i , W : Write > SerializeSeq for ContentSerializer < ' i , W > {
265
298
type Ok = W ;
266
299
type Error = DeError ;
267
300
@@ -270,6 +303,8 @@ impl<W: Write> SerializeSeq for ContentSerializer<W> {
270
303
T : ?Sized + Serialize ,
271
304
{
272
305
value. serialize ( self . new_seq_element_serializer ( ) ) ?;
306
+ // Write indent for next element
307
+ self . write_indent = true ;
273
308
Ok ( ( ) )
274
309
}
275
310
@@ -279,7 +314,7 @@ impl<W: Write> SerializeSeq for ContentSerializer<W> {
279
314
}
280
315
}
281
316
282
- impl < W : Write > SerializeTuple for ContentSerializer < W > {
317
+ impl < ' i , W : Write > SerializeTuple for ContentSerializer < ' i , W > {
283
318
type Ok = W ;
284
319
type Error = DeError ;
285
320
@@ -297,7 +332,7 @@ impl<W: Write> SerializeTuple for ContentSerializer<W> {
297
332
}
298
333
}
299
334
300
- impl < W : Write > SerializeTupleStruct for ContentSerializer < W > {
335
+ impl < ' i , W : Write > SerializeTupleStruct for ContentSerializer < ' i , W > {
301
336
type Ok = W ;
302
337
type Error = DeError ;
303
338
@@ -442,6 +477,8 @@ pub(super) mod tests {
442
477
let ser = ContentSerializer {
443
478
writer: String :: new( ) ,
444
479
level: QuoteLevel :: Full ,
480
+ indent: Indent :: None ,
481
+ write_indent: false ,
445
482
} ;
446
483
447
484
let buffer = $data. serialize( ser) . unwrap( ) ;
@@ -460,6 +497,8 @@ pub(super) mod tests {
460
497
let ser = ContentSerializer {
461
498
writer: & mut buffer,
462
499
level: QuoteLevel :: Full ,
500
+ indent: Indent :: None ,
501
+ write_indent: false ,
463
502
} ;
464
503
465
504
match $data. serialize( ser) . unwrap_err( ) {
@@ -611,4 +650,197 @@ pub(super) mod tests {
611
650
=> r#"<AttributesAfter val="42"><key>answer</key></AttributesAfter>"# ) ;
612
651
}
613
652
}
653
+
654
+ mod with_indent {
655
+ use super :: Struct ;
656
+ use super :: * ;
657
+ use crate :: writer:: Indentation ;
658
+ use pretty_assertions:: assert_eq;
659
+
660
+ /// Checks that given `$data` successfully serialized as `$expected`
661
+ macro_rules! serialize_as {
662
+ ( $name: ident: $data: expr => $expected: literal) => {
663
+ #[ test]
664
+ fn $name( ) {
665
+ let ser = ContentSerializer {
666
+ writer: String :: new( ) ,
667
+ level: QuoteLevel :: Full ,
668
+ indent: Indent :: Owned ( Indentation :: new( b' ' , 2 ) ) ,
669
+ write_indent: false ,
670
+ } ;
671
+
672
+ let buffer = $data. serialize( ser) . unwrap( ) ;
673
+ assert_eq!( buffer, $expected) ;
674
+ }
675
+ } ;
676
+ }
677
+
678
+ /// Checks that attempt to serialize given `$data` results to a
679
+ /// serialization error `$kind` with `$reason`
680
+ macro_rules! err {
681
+ ( $name: ident: $data: expr => $kind: ident( $reason: literal) ) => {
682
+ #[ test]
683
+ fn $name( ) {
684
+ let mut buffer = String :: new( ) ;
685
+ let ser = ContentSerializer {
686
+ writer: & mut buffer,
687
+ level: QuoteLevel :: Full ,
688
+ indent: Indent :: Owned ( Indentation :: new( b' ' , 2 ) ) ,
689
+ write_indent: false ,
690
+ } ;
691
+
692
+ match $data. serialize( ser) . unwrap_err( ) {
693
+ DeError :: $kind( e) => assert_eq!( e, $reason) ,
694
+ e => panic!(
695
+ "Expected `{}({})`, found `{:?}`" ,
696
+ stringify!( $kind) ,
697
+ $reason,
698
+ e
699
+ ) ,
700
+ }
701
+ // We can write something before fail
702
+ // assert_eq!(buffer, "");
703
+ }
704
+ } ;
705
+ }
706
+
707
+ serialize_as ! ( false_: false => "false" ) ;
708
+ serialize_as ! ( true_: true => "true" ) ;
709
+
710
+ serialize_as ! ( i8_: -42i8 => "-42" ) ;
711
+ serialize_as ! ( i16_: -4200i16 => "-4200" ) ;
712
+ serialize_as ! ( i32_: -42000000i32 => "-42000000" ) ;
713
+ serialize_as ! ( i64_: -42000000000000i64 => "-42000000000000" ) ;
714
+ serialize_as ! ( isize_: -42000000000000isize => "-42000000000000" ) ;
715
+
716
+ serialize_as ! ( u8_: 42u8 => "42" ) ;
717
+ serialize_as ! ( u16_: 4200u16 => "4200" ) ;
718
+ serialize_as ! ( u32_: 42000000u32 => "42000000" ) ;
719
+ serialize_as ! ( u64_: 42000000000000u64 => "42000000000000" ) ;
720
+ serialize_as ! ( usize_: 42000000000000usize => "42000000000000" ) ;
721
+
722
+ serde_if_integer128 ! {
723
+ serialize_as!( i128_: -420000000000000000000000000000i128 => "-420000000000000000000000000000" ) ;
724
+ serialize_as!( u128_: 420000000000000000000000000000u128 => "420000000000000000000000000000" ) ;
725
+ }
726
+
727
+ serialize_as ! ( f32_: 4.2f32 => "4.2" ) ;
728
+ serialize_as ! ( f64_: 4.2f64 => "4.2" ) ;
729
+
730
+ serialize_as ! ( char_non_escaped: 'h' => "h" ) ;
731
+ serialize_as ! ( char_lt: '<' => "<" ) ;
732
+ serialize_as ! ( char_gt: '>' => ">" ) ;
733
+ serialize_as ! ( char_amp: '&' => "&" ) ;
734
+ serialize_as ! ( char_apos: '\'' => "'" ) ;
735
+ serialize_as ! ( char_quot: '"' => """ ) ;
736
+ //TODO: add a setting to escape leading/trailing spaces, in order to
737
+ // pretty-print does not change the content
738
+ serialize_as ! ( char_space: ' ' => " " ) ;
739
+
740
+ serialize_as ! ( str_non_escaped: "non-escaped string" => "non-escaped string" ) ;
741
+ serialize_as ! ( str_escaped: "<\" escaped & string'>" => "<"escaped & string'>" ) ;
742
+
743
+ err ! ( bytes: Bytes ( b"<\" escaped & bytes'>" ) => Unsupported ( "`serialize_bytes` not supported yet" ) ) ;
744
+
745
+ serialize_as ! ( option_none: Option :: <Enum >:: None => "" ) ;
746
+ serialize_as ! ( option_some: Some ( Enum :: Unit ) => "<Unit/>" ) ;
747
+
748
+ serialize_as ! ( unit: ( ) => "" ) ;
749
+ serialize_as ! ( unit_struct: Unit => "" ) ;
750
+ serialize_as ! ( unit_struct_escaped: UnitEscaped => "" ) ;
751
+
752
+ // Unlike SimpleTypeSerializer, enumeration values serialized as tags
753
+ serialize_as ! ( enum_unit: Enum :: Unit => "<Unit/>" ) ;
754
+ err ! ( enum_unit_escaped: Enum :: UnitEscaped
755
+ => Unsupported ( "character `<` is not allowed at the start of an XML name `<\" &'>`" ) ) ;
756
+
757
+ // Newtypes recursively applies ContentSerializer
758
+ serialize_as ! ( newtype: Newtype ( 42 ) => "42" ) ;
759
+ serialize_as ! ( enum_newtype: Enum :: Newtype ( 42 ) => "<Newtype>42</Newtype>" ) ;
760
+
761
+ // Note that sequences of primitives serialized without delimiters other that indent!
762
+ serialize_as ! ( seq: vec![ 1 , 2 , 3 ]
763
+ => "1\n \
764
+ 2\n \
765
+ 3") ;
766
+ serialize_as ! ( seq_empty: Vec :: <usize >:: new( ) => "" ) ;
767
+ serialize_as ! ( tuple: ( "<\" &'>" , "with\t \r \n spaces" , 3usize )
768
+ => "<"&'>\n \
769
+ with\t \r \n spaces\n \
770
+ 3") ;
771
+ serialize_as ! ( tuple_struct: Tuple ( "first" , 42 )
772
+ => "first\n \
773
+ 42") ;
774
+ serialize_as ! ( enum_tuple: Enum :: Tuple ( "first" , 42 )
775
+ => "<Tuple>first</Tuple>\n \
776
+ <Tuple>42</Tuple>") ;
777
+
778
+ // Structured types cannot be serialized without surrounding tag, which
779
+ // only `enum` can provide
780
+ err ! ( map: BTreeMap :: from( [ ( "_1" , 2 ) , ( "_3" , 4 ) ] )
781
+ => Unsupported ( "serialization of map is not supported in `#any` field" ) ) ;
782
+ err ! ( struct_: Struct { key: "answer" , val: ( 42 , 42 ) }
783
+ => Unsupported ( "serialization of struct `Struct` is not supported in `#any` field" ) ) ;
784
+ serialize_as ! ( enum_struct: Enum :: Struct { key: "answer" , val: ( 42 , 42 ) }
785
+ => "<Struct>\n \
786
+ <key>answer</key>\n \
787
+ <val>42</val>\n \
788
+ <val>42</val>\n \
789
+ </Struct>") ;
790
+
791
+ /// Special field name `#text` should be serialized as text content
792
+ mod text {
793
+ use super :: * ;
794
+ use pretty_assertions:: assert_eq;
795
+
796
+ err ! ( map: BTreeMap :: from( [ ( "#text" , 2 ) , ( "_3" , 4 ) ] )
797
+ => Unsupported ( "serialization of map is not supported in `#any` field" ) ) ;
798
+ err ! ( struct_:
799
+ Text {
800
+ before: "answer" ,
801
+ content: ( 42 , 42 ) ,
802
+ after: "answer" ,
803
+ }
804
+ => Unsupported ( "serialization of struct `Text` is not supported in `#any` field" ) ) ;
805
+ serialize_as ! ( enum_struct:
806
+ SpecialEnum :: Text {
807
+ before: "answer" ,
808
+ content: ( 42 , 42 ) ,
809
+ after: "answer" ,
810
+ }
811
+ => "<Text>\n \
812
+ <before>answer</before>\n \
813
+ 42 42\n \
814
+ <after>answer</after>\n \
815
+ </Text>") ;
816
+ }
817
+
818
+ mod attributes {
819
+ use super :: * ;
820
+ use pretty_assertions:: assert_eq;
821
+
822
+ err ! ( map_attr: BTreeMap :: from( [ ( "@key1" , 1 ) , ( "@key2" , 2 ) ] )
823
+ => Unsupported ( "serialization of map is not supported in `#any` field" ) ) ;
824
+ err ! ( map_mixed: BTreeMap :: from( [ ( "@key1" , 1 ) , ( "key2" , 2 ) ] )
825
+ => Unsupported ( "serialization of map is not supported in `#any` field" ) ) ;
826
+
827
+ err ! ( struct_: Attributes { key: "answer" , val: ( 42 , 42 ) }
828
+ => Unsupported ( "serialization of struct `Attributes` is not supported in `#any` field" ) ) ;
829
+ err ! ( struct_before: AttributesBefore { key: "answer" , val: 42 }
830
+ => Unsupported ( "serialization of struct `AttributesBefore` is not supported in `#any` field" ) ) ;
831
+ err ! ( struct_after: AttributesAfter { key: "answer" , val: 42 }
832
+ => Unsupported ( "serialization of struct `AttributesAfter` is not supported in `#any` field" ) ) ;
833
+
834
+ serialize_as ! ( enum_: Enum :: Attributes { key: "answer" , val: ( 42 , 42 ) }
835
+ => r#"<Attributes key="answer" val="42 42"/>"# ) ;
836
+ serialize_as ! ( enum_before: Enum :: AttributesBefore { key: "answer" , val: 42 }
837
+ => "<AttributesBefore key=\" answer\" >\n \
838
+ <val>42</val>\n \
839
+ </AttributesBefore>") ;
840
+ serialize_as ! ( enum_after: Enum :: AttributesAfter { key: "answer" , val: 42 }
841
+ => "<AttributesAfter val=\" 42\" >\n \
842
+ <key>answer</key>\n \
843
+ </AttributesAfter>") ;
844
+ }
845
+ }
614
846
}
0 commit comments