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