@@ -19,105 +19,120 @@ use serde_json::ser::{to_writer, PrettyFormatter, Serializer};
19
19
/// or in apostrophes with the (optional) safe filter `'{{data|json|safe}}'`.
20
20
/// In HTML texts the output of e.g. `<pre>{{data|json|safe}}</pre>` is safe, too.
21
21
#[ inline]
22
- pub fn json ( value : impl Serialize , indent : impl AsIndent ) -> Result < impl fmt:: Display , Infallible > {
23
- Ok ( ToJson { value, indent } )
22
+ pub fn json ( value : impl Serialize ) -> Result < impl fmt:: Display , Infallible > {
23
+ Ok ( ToJson { value } )
24
+ }
25
+
26
+ /// Serialize to formatted/prettified JSON (requires `json` feature)
27
+ ///
28
+ /// This filter works the same as [`json()`], but it formats the data for human readability.
29
+ /// It has an additional "indent" argument, which can either be an integer how many spaces to use
30
+ /// for indentation (capped to 16 characters), or a string (e.g. `"\u{A0}\u{A0}"` for two
31
+ /// non-breaking spaces).
32
+ ///
33
+ /// ### Note
34
+ ///
35
+ /// In rinja's template language, this filter is called `|json`, too. The right function is
36
+ /// automatically selected depending on whether an `indent` argument was provided or not.
37
+ #[ inline]
38
+ pub fn json_pretty (
39
+ value : impl Serialize ,
40
+ indent : impl AsIndent ,
41
+ ) -> Result < impl fmt:: Display , Infallible > {
42
+ Ok ( ToJsonPretty { value, indent } )
43
+ }
44
+
45
+ #[ derive( Debug , Clone ) ]
46
+ struct ToJson < S > {
47
+ value : S ,
48
+ }
49
+
50
+ #[ derive( Debug , Clone ) ]
51
+ struct ToJsonPretty < S , I > {
52
+ value : S ,
53
+ indent : I ,
24
54
}
25
55
26
56
pub trait AsIndent {
27
- fn as_indent ( & self ) -> Option < & str > ;
57
+ fn as_indent ( & self ) -> & str ;
28
58
}
29
59
30
60
impl AsIndent for str {
31
61
#[ inline]
32
- fn as_indent ( & self ) -> Option < & str > {
33
- Some ( self )
62
+ fn as_indent ( & self ) -> & str {
63
+ self
34
64
}
35
65
}
36
66
37
67
impl AsIndent for String {
38
68
#[ inline]
39
- fn as_indent ( & self ) -> Option < & str > {
40
- Some ( self )
69
+ fn as_indent ( & self ) -> & str {
70
+ self
41
71
}
42
72
}
43
73
44
- impl AsIndent for isize {
45
- fn as_indent ( & self ) -> Option < & str > {
46
- const SPACES : & str = " " ;
47
- match * self < 0 {
48
- true => None ,
49
- false => Some ( & SPACES [ ..( * self as usize ) . min ( SPACES . len ( ) ) ] ) ,
50
- }
51
- }
52
- }
53
-
54
- impl AsIndent for ( ) {
74
+ impl AsIndent for usize {
55
75
#[ inline]
56
- fn as_indent ( & self ) -> Option < & str > {
57
- None
76
+ fn as_indent ( & self ) -> & str {
77
+ const MAX_SPACES : usize = 16 ;
78
+ const SPACES : & str = match str:: from_utf8 ( & [ b' ' ; MAX_SPACES ] ) {
79
+ Ok ( spaces) => spaces,
80
+ Err ( _) => panic ! ( ) ,
81
+ } ;
82
+
83
+ & SPACES [ ..( * self ) . min ( SPACES . len ( ) ) ]
58
84
}
59
85
}
60
86
61
87
impl < T : AsIndent + ?Sized > AsIndent for & T {
62
88
#[ inline]
63
- fn as_indent ( & self ) -> Option < & str > {
89
+ fn as_indent ( & self ) -> & str {
64
90
T :: as_indent ( self )
65
91
}
66
92
}
67
93
68
- impl < T : AsIndent > AsIndent for Option < T > {
69
- #[ inline]
70
- fn as_indent ( & self ) -> Option < & str > {
71
- self . as_ref ( ) . and_then ( T :: as_indent)
72
- }
73
- }
74
-
75
94
impl < T : AsIndent + ?Sized > AsIndent for Box < T > {
76
95
#[ inline]
77
- fn as_indent ( & self ) -> Option < & str > {
96
+ fn as_indent ( & self ) -> & str {
78
97
T :: as_indent ( self . as_ref ( ) )
79
98
}
80
99
}
81
100
82
101
impl < T : AsIndent + ToOwned + ?Sized > AsIndent for std:: borrow:: Cow < ' _ , T > {
83
102
#[ inline]
84
- fn as_indent ( & self ) -> Option < & str > {
103
+ fn as_indent ( & self ) -> & str {
85
104
T :: as_indent ( self . as_ref ( ) )
86
105
}
87
106
}
88
107
89
108
impl < T : AsIndent + ?Sized > AsIndent for std:: rc:: Rc < T > {
90
109
#[ inline]
91
- fn as_indent ( & self ) -> Option < & str > {
110
+ fn as_indent ( & self ) -> & str {
92
111
T :: as_indent ( self . as_ref ( ) )
93
112
}
94
113
}
95
114
96
115
impl < T : AsIndent + ?Sized > AsIndent for std:: sync:: Arc < T > {
97
116
#[ inline]
98
- fn as_indent ( & self ) -> Option < & str > {
117
+ fn as_indent ( & self ) -> & str {
99
118
T :: as_indent ( self . as_ref ( ) )
100
119
}
101
120
}
102
121
103
- # [ derive ( Debug , Clone ) ]
104
- struct ToJson < S , I > {
105
- value : S ,
106
- indent : I ,
122
+ impl < S : Serialize > fmt :: Display for ToJson < S > {
123
+ fn fmt ( & self , f : & mut fmt :: Formatter < ' _ > ) -> fmt :: Result {
124
+ to_writer ( JsonWriter ( f ) , & self . value ) . map_err ( |_| fmt :: Error )
125
+ }
107
126
}
108
127
109
- impl < S : Serialize , I : AsIndent > fmt:: Display for ToJson < S , I > {
128
+ impl < S : Serialize , I : AsIndent > fmt:: Display for ToJsonPretty < S , I > {
110
129
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
111
- let f = JsonWriter ( f) ;
112
- if let Some ( indent) = self . indent . as_indent ( ) {
113
- let formatter = PrettyFormatter :: with_indent ( indent. as_bytes ( ) ) ;
114
- let mut serializer = Serializer :: with_formatter ( f, formatter) ;
115
- self . value
116
- . serialize ( & mut serializer)
117
- . map_err ( |_| fmt:: Error )
118
- } else {
119
- to_writer ( f, & self . value ) . map_err ( |_| fmt:: Error )
120
- }
130
+ let indent = self . indent . as_indent ( ) ;
131
+ let formatter = PrettyFormatter :: with_indent ( indent. as_bytes ( ) ) ;
132
+ let mut serializer = Serializer :: with_formatter ( JsonWriter ( f) , formatter) ;
133
+ self . value
134
+ . serialize ( & mut serializer)
135
+ . map_err ( |_| fmt:: Error )
121
136
}
122
137
}
123
138
@@ -166,51 +181,43 @@ mod tests {
166
181
167
182
#[ test]
168
183
fn test_ugly ( ) {
169
- assert_eq ! ( json( true , ( ) ) . unwrap( ) . to_string( ) , "true" ) ;
170
- assert_eq ! ( json( "foo" , ( ) ) . unwrap( ) . to_string( ) , r#""foo""# ) ;
171
- assert_eq ! ( json( true , ( ) ) . unwrap( ) . to_string( ) , "true" ) ;
172
- assert_eq ! ( json( "foo" , ( ) ) . unwrap( ) . to_string( ) , r#""foo""# ) ;
184
+ assert_eq ! ( json( true ) . unwrap( ) . to_string( ) , "true" ) ;
185
+ assert_eq ! ( json( "foo" ) . unwrap( ) . to_string( ) , r#""foo""# ) ;
186
+ assert_eq ! ( json( true ) . unwrap( ) . to_string( ) , "true" ) ;
187
+ assert_eq ! ( json( "foo" ) . unwrap( ) . to_string( ) , r#""foo""# ) ;
173
188
assert_eq ! (
174
- json( "<script>" , ( ) ) . unwrap( ) . to_string( ) ,
189
+ json( "<script>" ) . unwrap( ) . to_string( ) ,
175
190
r#""\u003cscript\u003e""#
176
191
) ;
177
192
assert_eq ! (
178
- json( vec![ "foo" , "bar" ] , ( ) ) . unwrap( ) . to_string( ) ,
193
+ json( vec![ "foo" , "bar" ] ) . unwrap( ) . to_string( ) ,
179
194
r#"["foo","bar"]"#
180
195
) ;
181
- assert_eq ! ( json( true , -1 ) . unwrap( ) . to_string( ) , "true" ) ;
182
- assert_eq ! ( json( true , Some ( ( ) ) ) . unwrap( ) . to_string( ) , "true" ) ;
183
- assert_eq ! (
184
- json( true , & Some ( None :: <isize >) ) . unwrap( ) . to_string( ) ,
185
- "true"
186
- ) ;
187
196
}
188
197
189
198
#[ test]
190
199
fn test_pretty ( ) {
191
- assert_eq ! ( json ( true , "" ) . unwrap( ) . to_string( ) , "true" ) ;
200
+ assert_eq ! ( json_pretty ( true , "" ) . unwrap( ) . to_string( ) , "true" ) ;
192
201
assert_eq ! (
193
- json ( "<script>" , Some ( "" ) ) . unwrap( ) . to_string( ) ,
202
+ json_pretty ( "<script>" , "" ) . unwrap( ) . to_string( ) ,
194
203
r#""\u003cscript\u003e""#
195
204
) ;
196
205
assert_eq ! (
197
- json ( vec![ "foo" , "bar" ] , Some ( "" ) ) . unwrap( ) . to_string( ) ,
206
+ json_pretty ( vec![ "foo" , "bar" ] , "" ) . unwrap( ) . to_string( ) ,
198
207
r#"[
199
208
"foo",
200
209
"bar"
201
210
]"#
202
211
) ;
203
212
assert_eq ! (
204
- json ( vec![ "foo" , "bar" ] , 2 ) . unwrap( ) . to_string( ) ,
213
+ json_pretty ( vec![ "foo" , "bar" ] , 2 ) . unwrap( ) . to_string( ) ,
205
214
r#"[
206
215
"foo",
207
216
"bar"
208
217
]"#
209
218
) ;
210
219
assert_eq ! (
211
- json( vec![ "foo" , "bar" ] , & Some ( & "————" ) )
212
- . unwrap( )
213
- . to_string( ) ,
220
+ json_pretty( vec![ "foo" , "bar" ] , "————" ) . unwrap( ) . to_string( ) ,
214
221
r#"[
215
222
————"foo",
216
223
————"bar"
0 commit comments