1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 use crate::{consts::*, Array, Error, JsonValue, Number, Object};
15 #[cfg(feature = "c_adapter")]
16 use std::ffi::CString;
17 use std::io::Write;
18 
19 // todo: Considers extracting Encoder traits.
20 
21 /// JSON encoder with additional formats, used to output JsonValue instances in JSON format to the specified location.
22 ///
23 /// This encoder will add additional formatting control whitespace characters during encoding.
24 pub(crate) struct FormattedEncoder<'a, W: Write> {
25     output: &'a mut W,
26     /// The current number of nested layers
27     tab: usize,
28 }
29 
30 impl<'a, W: Write> FormattedEncoder<'a, W> {
31     /// Creates
new(output: &'a mut W) -> Self32     pub(crate) fn new(output: &'a mut W) -> Self {
33         Self { output, tab: 0 }
34     }
35 
36     /// Encodes
encode(&mut self, value: &JsonValue) -> Result<(), Error>37     pub(crate) fn encode(&mut self, value: &JsonValue) -> Result<(), Error> {
38         self.encode_value(value)?;
39         self.output.write_all(LINE_FEED_STR)?;
40         Ok(())
41     }
42 
43     /// Encodes JsonValue
encode_value(&mut self, value: &JsonValue) -> Result<(), Error>44     fn encode_value(&mut self, value: &JsonValue) -> Result<(), Error> {
45         match value {
46             JsonValue::Null => self.encode_null(),
47             JsonValue::Boolean(boolean) => self.encode_boolean(boolean),
48             JsonValue::Number(number) => self.encode_number(number),
49             JsonValue::String(string) => self.encode_string(string),
50             JsonValue::Array(array) => self.encode_array(array),
51             JsonValue::Object(object) => self.encode_object(object),
52         }
53     }
54 
55     /// Add tabs to improve readability.
add_tab(&mut self) -> Result<(), Error>56     fn add_tab(&mut self) -> Result<(), Error> {
57         for _ in 0..self.tab {
58             self.output.write_all(FOUR_SPACES_STR)?;
59         }
60         Ok(())
61     }
62 
63     /// Encodes Null
encode_null(&mut self) -> Result<(), Error>64     fn encode_null(&mut self) -> Result<(), Error> {
65         encode_null(self.output)
66     }
67 
68     /// Encodes Boolean
encode_boolean(&mut self, boolean: &bool) -> Result<(), Error>69     fn encode_boolean(&mut self, boolean: &bool) -> Result<(), Error> {
70         encode_boolean(self.output, *boolean)
71     }
72 
73     /// Encodes Number
encode_number(&mut self, number: &Number) -> Result<(), Error>74     fn encode_number(&mut self, number: &Number) -> Result<(), Error> {
75         encode_number(self.output, number)
76     }
77 
78     /// Encodes Key
encode_key(&mut self, key: &str) -> Result<(), Error>79     fn encode_key(&mut self, key: &str) -> Result<(), Error> {
80         encode_string(self.output, key)
81     }
82 
83     /// Encodes String
84     #[cfg(feature = "c_adapter")]
encode_string(&mut self, string: &CString) -> Result<(), Error>85     fn encode_string(&mut self, string: &CString) -> Result<(), Error> {
86         encode_string(self.output, unsafe {
87             core::str::from_utf8_unchecked(string.as_bytes())
88         })
89     }
90 
91     /// Encodes String
92     #[cfg(not(feature = "c_adapter"))]
encode_string(&mut self, string: &str) -> Result<(), Error>93     fn encode_string(&mut self, string: &str) -> Result<(), Error> {
94         encode_string(self.output, string)
95     }
96 
97     /// Encodes Array
encode_array(&mut self, array: &Array) -> Result<(), Error>98     fn encode_array(&mut self, array: &Array) -> Result<(), Error> {
99         // Check whether multiple lines are required. If array or object
100         // exists in the array value, multiple lines are required.
101         let mut multiple_line = false;
102         for v in array.iter() {
103             if v.is_array() | v.is_object() {
104                 multiple_line = true;
105                 break;
106             }
107         }
108 
109         self.output.write_all(LEFT_SQUARE_BRACKET_STR)?;
110         if multiple_line {
111             self.output.write_all(LINE_FEED_STR)?;
112             self.tab += 1;
113             self.add_tab()?;
114             for (n, v) in array.iter().enumerate() {
115                 if n != 0 {
116                     self.output.write_all(COMMA_STR)?;
117                     self.output.write_all(LINE_FEED_STR)?;
118                     self.add_tab()?;
119                 }
120                 self.encode_value(v)?;
121             }
122             self.output.write_all(LINE_FEED_STR)?;
123             self.tab -= 1;
124             self.add_tab()?;
125         } else {
126             for (n, v) in array.iter().enumerate() {
127                 if n != 0 {
128                     self.output.write_all(COMMA_STR)?;
129                     self.output.write_all(SPACE_STR)?;
130                 }
131                 self.encode_value(v)?;
132             }
133         }
134         self.output.write_all(RIGHT_SQUARE_BRACKET_STR)?;
135         Ok(())
136     }
137 
138     /// Encodes Object
encode_object(&mut self, object: &Object) -> Result<(), Error>139     fn encode_object(&mut self, object: &Object) -> Result<(), Error> {
140         self.output.write_all(LEFT_CURLY_BRACKET_STR)?;
141         self.tab += 1;
142         for (u, (k, v)) in object.iter().enumerate() {
143             if u != 0 {
144                 self.output.write_all(COMMA_STR)?;
145             }
146             self.output.write_all(LINE_FEED_STR)?;
147             self.add_tab()?;
148             self.encode_key(k)?;
149             self.output.write_all(COLON_STR)?;
150             self.output.write_all(SPACE_STR)?;
151             self.encode_value(v)?;
152         }
153         self.tab -= 1;
154         // Non-empty objects require additional newlines and tabs.
155         if !object.is_empty() {
156             self.output.write_all(LINE_FEED_STR)?;
157             self.add_tab()?;
158         }
159         self.output.write_all(RIGHT_CURLY_BRACKET_STR)?;
160         Ok(())
161     }
162 }
163 
164 /// JSON encoder that outputs no extra whitespace characters ,
165 /// used to output a JsonValue instance in JSON format to a specified location.
166 pub(crate) struct CompactEncoder<'a, W: Write> {
167     output: &'a mut W,
168 }
169 
170 impl<'a, W: Write> CompactEncoder<'a, W> {
171     /// Creates
new(output: &'a mut W) -> Self172     pub(crate) fn new(output: &'a mut W) -> Self {
173         Self { output }
174     }
175 
176     /// Encodes
encode(&mut self, value: &JsonValue) -> Result<(), Error>177     pub(crate) fn encode(&mut self, value: &JsonValue) -> Result<(), Error> {
178         self.encode_value(value)
179     }
180 
181     /// Encodes JsonValue
encode_value(&mut self, value: &JsonValue) -> Result<(), Error>182     fn encode_value(&mut self, value: &JsonValue) -> Result<(), Error> {
183         match value {
184             JsonValue::Null => self.encode_null(),
185             JsonValue::Boolean(boolean) => self.encode_boolean(boolean),
186             JsonValue::Number(number) => self.encode_number(number),
187             JsonValue::String(string) => self.encode_string(string),
188             JsonValue::Array(array) => self.encode_array(array),
189             JsonValue::Object(object) => self.encode_object(object),
190         }
191     }
192 
193     /// Encodes Null
encode_null(&mut self) -> Result<(), Error>194     fn encode_null(&mut self) -> Result<(), Error> {
195         encode_null(self.output)
196     }
197 
198     /// Encodes Boolean
encode_boolean(&mut self, boolean: &bool) -> Result<(), Error>199     fn encode_boolean(&mut self, boolean: &bool) -> Result<(), Error> {
200         encode_boolean(self.output, *boolean)
201     }
202 
203     /// Encodes Number
encode_number(&mut self, number: &Number) -> Result<(), Error>204     fn encode_number(&mut self, number: &Number) -> Result<(), Error> {
205         encode_number(self.output, number)
206     }
207 
208     /// Encodes Key
encode_key(&mut self, key: &str) -> Result<(), Error>209     fn encode_key(&mut self, key: &str) -> Result<(), Error> {
210         encode_string(self.output, key)
211     }
212 
213     /// Encodes String
214     #[cfg(feature = "c_adapter")]
encode_string(&mut self, string: &CString) -> Result<(), Error>215     fn encode_string(&mut self, string: &CString) -> Result<(), Error> {
216         encode_string(self.output, unsafe {
217             std::str::from_utf8_unchecked(string.as_bytes())
218         })
219     }
220 
221     /// Encodes String
222     #[cfg(not(feature = "c_adapter"))]
encode_string(&mut self, string: &str) -> Result<(), Error>223     fn encode_string(&mut self, string: &str) -> Result<(), Error> {
224         encode_string(self.output, string)
225     }
226 
227     /// Encodes Array
encode_array(&mut self, array: &Array) -> Result<(), Error>228     fn encode_array(&mut self, array: &Array) -> Result<(), Error> {
229         self.output.write_all(LEFT_SQUARE_BRACKET_STR)?;
230         for (n, v) in array.iter().enumerate() {
231             if n != 0 {
232                 self.output.write_all(COMMA_STR)?;
233             }
234             self.encode_value(v)?;
235         }
236         self.output.write_all(RIGHT_SQUARE_BRACKET_STR)?;
237         Ok(())
238     }
239 
240     /// Encodes Object
encode_object(&mut self, object: &Object) -> Result<(), Error>241     fn encode_object(&mut self, object: &Object) -> Result<(), Error> {
242         self.output.write_all(LEFT_CURLY_BRACKET_STR)?;
243         for (u, (k, v)) in object.iter().enumerate() {
244             if u != 0 {
245                 self.output.write_all(COMMA_STR)?;
246             }
247             self.encode_key(k)?;
248             self.output.write_all(COLON_STR)?;
249             self.encode_value(v)?;
250         }
251         self.output.write_all(RIGHT_CURLY_BRACKET_STR)?;
252         Ok(())
253     }
254 }
255 
256 #[inline]
encode_null(writer: &mut dyn Write) -> Result<(), Error>257 fn encode_null(writer: &mut dyn Write) -> Result<(), Error> {
258     writer.write_all(NULL_STR)?;
259     Ok(())
260 }
261 
262 #[inline]
encode_boolean(writer: &mut dyn Write, boolean: bool) -> Result<(), Error>263 fn encode_boolean(writer: &mut dyn Write, boolean: bool) -> Result<(), Error> {
264     if boolean {
265         writer.write_all(TRUE_STR)?;
266     } else {
267         writer.write_all(FALSE_STR)?;
268     }
269     Ok(())
270 }
271 
272 #[inline]
encode_number(writer: &mut dyn Write, number: &Number) -> Result<(), Error>273 pub(crate) fn encode_number(writer: &mut dyn Write, number: &Number) -> Result<(), Error> {
274     write!(writer, "{number}")?;
275     Ok(())
276 }
277 
278 #[inline]
encode_string(writer: &mut dyn Write, string: &str) -> Result<(), Error>279 fn encode_string(writer: &mut dyn Write, string: &str) -> Result<(), Error> {
280     writer.write_all(QUOTATION_MARK_STR)?;
281     encode_string_inner(writer, string)?;
282     writer.write_all(QUOTATION_MARK_STR)?;
283     Ok(())
284 }
285 
286 #[cfg(feature = "ascii_only")]
encode_string_inner(writer: &mut dyn Write, string: &str) -> Result<(), Error>287 pub(crate) fn encode_string_inner(writer: &mut dyn Write, string: &str) -> Result<(), Error> {
288     let bytes = string.as_bytes();
289     let len = bytes.len();
290     let mut start = 0usize;
291 
292     for i in 0..len {
293         let ch = &bytes[i];
294         if ESCAPE[(*ch) as usize] {
295             writer.write_all(&bytes[start..i])?;
296             start = i + 1;
297 
298             match *ch {
299                 REVERSE_SOLIDUS => writer.write_all(JSON_REVERSE_SOLIDUS)?,
300                 QUOTATION_MARK => writer.write_all(JSON_QUOTATION_MARK)?,
301                 BS_UNICODE_U8 => writer.write_all(JSON_BS)?,
302                 FF_UNICODE_U8 => writer.write_all(JSON_FF)?,
303                 LF_UNICODE_U8 => writer.write_all(JSON_LF)?,
304                 CR_UNICODE_U8 => writer.write_all(JSON_CR)?,
305                 HT_UNICODE_U8 => writer.write_all(JSON_HT)?,
306                 x => write!(writer, "\\u{number:0>width$x}", number = x, width = 4)?,
307             }
308         }
309     }
310     if start != len {
311         writer.write_all(&bytes[start..len])?;
312     }
313 
314     Ok(())
315 }
316 
317 #[cfg(not(feature = "ascii_only"))]
encode_string_inner(writer: &mut dyn Write, string: &str) -> Result<(), Error>318 pub(crate) fn encode_string_inner(writer: &mut dyn Write, string: &str) -> Result<(), Error> {
319     fn split_pattern(
320         writer: &mut dyn Write,
321         pattern: &mut &str,
322         split_pos: &mut usize,
323         ch: char,
324     ) -> Result<(), Error> {
325         let (l, r) = (*pattern).split_at(*split_pos);
326         writer.write_all(l.as_bytes())?;
327         *pattern = r;
328 
329         let (_, r) = (*pattern).split_at(ch.len_utf8());
330         *pattern = r;
331         *split_pos = 0;
332         Ok(())
333     }
334 
335     let mut pattern = string;
336     let mut split_pos = 0usize;
337     for ch in string.chars() {
338         if ch.is_ascii() {
339             match PRINT_MAP[ch as usize] {
340                 PrintMapItem::Other => {
341                     split_pos += 1;
342                     continue;
343                 }
344                 PrintMapItem::Special(x) => {
345                     split_pattern(writer, &mut pattern, &mut split_pos, ch)?;
346                     writer.write_all(x)?;
347                 }
348                 PrintMapItem::Control => {
349                     split_pattern(writer, &mut pattern, &mut split_pos, ch)?;
350                     let bytes = ch as u32;
351                     write!(writer, "\\u{number:0>width$x}", number = bytes, width = 4)?;
352                 }
353             }
354             continue;
355         }
356         split_pattern(writer, &mut pattern, &mut split_pos, ch)?;
357         let bytes = ch as u32;
358         write!(writer, "\\u{number:0>width$x}", number = bytes, width = 4)?;
359     }
360     if split_pos != 0 {
361         writer.write_all(pattern.as_bytes())?;
362     }
363     Ok(())
364 }
365 
366 #[cfg(test)]
367 mod ut_encoder {
368     use crate::{CompactEncoder, FormattedEncoder, JsonValue};
369     use std::io::Write;
370 
371     struct StringWriter {
372         string: String,
373     }
374 
375     impl StringWriter {
new() -> Self376         fn new() -> Self {
377             Self {
378                 string: String::new(),
379             }
380         }
381     }
382 
383     impl Write for StringWriter {
write(&mut self, buf: &[u8]) -> std::io::Result<usize>384         fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
385             self.string
386                 .push_str(unsafe { std::str::from_utf8_unchecked(buf) });
387             self.flush()?;
388             Ok(buf.len())
389         }
390 
flush(&mut self) -> std::io::Result<()>391         fn flush(&mut self) -> std::io::Result<()> {
392             Ok(())
393         }
394     }
395 
396     macro_rules! encoder_test_case {
397         ($encoder: ident, $input: expr, $output: expr $(,)?) => {
398             let value = JsonValue::from_text($input).unwrap();
399             let mut writer = StringWriter::new();
400             let mut encoder = $encoder::new(&mut writer);
401             assert!(encoder.encode(&value).is_ok());
402             assert_eq!(writer.string, $output);
403         };
404     }
405 
406     /// UT test for `FormattedEncoder`.
407     ///
408     /// # Title
409     /// ut_formatted_encoder
410     ///
411     /// # Brief
412     /// 1. Creates a `JsonValue` called `json_value`.
413     /// 2. Creates a `FormattedEncoder` called `encoder`.
414     /// 3. Uses `encoder` to encode `json_value`.
415     /// 4. Checks if the results are correct.
416     #[test]
ut_formatted_encoder()417     fn ut_formatted_encoder() {
418         encoder_test_case!(
419             FormattedEncoder,
420             "{\"null\":null}",
421             "{\n    \"null\": null\n}\n",
422         );
423 
424         encoder_test_case!(
425             FormattedEncoder,
426             "{\"true\":true}",
427             "{\n    \"true\": true\n}\n",
428         );
429 
430         encoder_test_case!(
431             FormattedEncoder,
432             "{\"false\":false}",
433             "{\n    \"false\": false\n}\n",
434         );
435 
436         encoder_test_case!(
437             FormattedEncoder,
438             "{\"number\":3.14}",
439             "{\n    \"number\": 3.14\n}\n",
440         );
441 
442         encoder_test_case!(
443             FormattedEncoder,
444             "{\"string\":\"HelloWorld\"}",
445             "{\n    \"string\": \"HelloWorld\"\n}\n",
446         );
447 
448         encoder_test_case!(
449             FormattedEncoder,
450             "{\"array\":[1, 2, 3]}",
451             "{\n    \"array\": [1, 2, 3]\n}\n",
452         );
453 
454         encoder_test_case!(
455             FormattedEncoder,
456             "{\"object\":{\"key1\":1}}",
457             "{\n    \"object\": {\n        \"key1\": 1\n    }\n}\n",
458         );
459     }
460 
461     /// UT test for `CompactEncoder`.
462     ///
463     /// # Title
464     /// ut_compact_encoder
465     ///
466     /// # Brief
467     /// 1. Creates a `JsonValue` called `json_value`.
468     /// 2. Creates a `Compact` called `encoder`.
469     /// 3. Uses `encoder` to encode `json_value`.
470     /// 4. Checks if the results are correct.
471     #[test]
ut_compact_encoder()472     fn ut_compact_encoder() {
473         encoder_test_case!(CompactEncoder, "{\"null\":null}", "{\"null\":null}",);
474 
475         encoder_test_case!(CompactEncoder, "{\"true\":true}", "{\"true\":true}",);
476 
477         encoder_test_case!(CompactEncoder, "{\"false\":false}", "{\"false\":false}",);
478 
479         encoder_test_case!(CompactEncoder, "{\"number\":3.14}", "{\"number\":3.14}",);
480 
481         encoder_test_case!(
482             CompactEncoder,
483             "{\"string\":\"HelloWorld\"}",
484             "{\"string\":\"HelloWorld\"}",
485         );
486 
487         #[cfg(not(feature = "ascii_only"))]
488         encoder_test_case!(
489             CompactEncoder,
490             "{\"string\":\"\\b\\t\\f\\n\\u0000\\u2764\"}",
491             "{\"string\":\"\\b\\t\\f\\n\\u0000\\u2764\"}",
492         );
493 
494         #[cfg(feature = "ascii_only")]
495         encoder_test_case!(
496             CompactEncoder,
497             "{\"string\":\"\\b\\t\\f\\n\\u0000\\u2764\"}",
498             "{\"string\":\"\\b\\t\\f\\n\\u0000\u{2764}\"}",
499         );
500 
501         encoder_test_case!(CompactEncoder, "{\"array\":[1,2,3]}", "{\"array\":[1,2,3]}",);
502 
503         encoder_test_case!(
504             CompactEncoder,
505             "{\"object\":{\"key1\":1,\"key2\":2}}",
506             "{\"object\":{\"key1\":1,\"key2\":2}}",
507         );
508     }
509 }
510