lite_json/
json.rs

1#[cfg(not(feature = "std"))]
2extern crate alloc;
3
4#[cfg(not(feature = "std"))]
5use alloc::vec::Vec;
6
7#[cfg(not(feature = "std"))]
8use alloc::string::ToString;
9
10use crate::traits::Serialize;
11
12#[cfg_attr(feature = "std", derive(Debug))]
13#[derive(Clone, PartialEq, Copy)]
14pub struct NumberValue {
15    pub integer: u64,
16    pub fraction: u64,
17    pub fraction_length: u32,
18    pub exponent: i32,
19    pub negative: bool,
20}
21
22impl NumberValue {
23    /// Losslessly convert the inner value to `f64`.
24    #[cfg(any(feature = "std", feature = "float"))]
25    pub fn to_f64(self) -> f64 {
26        self.into()
27    }
28}
29
30#[cfg(any(feature = "std", feature = "float"))]
31impl Into<f64> for NumberValue {
32    fn into(self) -> f64 {
33        #[cfg(not(feature = "std"))]
34        use num_traits::float::FloatCore as _;
35
36        let sign = if self.negative { -1.0 } else { 1.0 };
37        (self.integer as f64 + self.fraction as f64 / 10f64.powi(self.fraction_length as i32))
38            * 10f64.powi(self.exponent)
39            * sign
40    }
41}
42
43pub type JsonObject = Vec<(Vec<char>, JsonValue)>;
44
45#[cfg_attr(feature = "std", derive(Debug))]
46#[derive(Clone, PartialEq)]
47pub enum JsonValue {
48    Object(JsonObject),
49    Array(Vec<JsonValue>),
50    String(Vec<char>),
51    Number(NumberValue),
52    Boolean(bool),
53    Null,
54}
55
56impl JsonValue {
57    /// Returns a boolean indicating whether this value is an object or not.
58    pub fn is_object(&self) -> bool {
59        match self {
60            JsonValue::Object(_) => true,
61            _ => false,
62        }
63    }
64
65    /// Returns a reference to the key-value vec if this value is an object, otherwise returns None.
66    pub fn as_object(&self) -> Option<&[(Vec<char>, JsonValue)]> {
67        match self {
68            JsonValue::Object(obj) => Some(obj),
69            _ => None,
70        }
71    }
72
73    /// Returns the wrapped object if the value is an object, otherwise returns None.
74    pub fn to_object(self) -> Option<JsonObject> {
75        match self {
76            JsonValue::Object(obj) => Some(obj),
77            _ => None,
78        }
79    }
80
81    /// Returns a boolean indicating whether this value is an array or not.
82    pub fn is_array(&self) -> bool {
83        match self {
84            JsonValue::Array(_) => true,
85            _ => false,
86        }
87    }
88
89    /// Returns a reference to the wrapped array if this value is an array, otherwise returns None.
90    pub fn as_array(&self) -> Option<&[JsonValue]> {
91        match self {
92            JsonValue::Array(arr) => Some(arr),
93            _ => None,
94        }
95    }
96
97    /// Returns the wrapped vector if the value is an array, otherwise returns None.
98    pub fn to_array(self) -> Option<Vec<JsonValue>> {
99        match self {
100            JsonValue::Array(arr) => Some(arr),
101            _ => None,
102        }
103    }
104
105    /// Returns a boolean indicating whether this value is a string or not.
106    pub fn is_string(&self) -> bool {
107        match self {
108            JsonValue::String(_) => true,
109            _ => false,
110        }
111    }
112
113    /// Returns a char slice if this value is a string, otherwise returns None.
114    pub fn as_string(&self) -> Option<&[char]> {
115        match self {
116            JsonValue::String(s) => Some(s),
117            _ => None,
118        }
119    }
120
121    /// Returns the wrapped vector if the value is a string, otherwise returns None.
122    pub fn to_string(self) -> Option<Vec<char>> {
123        match self {
124            JsonValue::String(s) => Some(s),
125            _ => None,
126        }
127    }
128
129    /// Returns a boolean indicating whether this value is a number or not.
130    pub fn is_number(&self) -> bool {
131        match self {
132            JsonValue::Number(_) => true,
133            _ => false,
134        }
135    }
136
137    /// Returns a reference to wrapped `NumberValue` if this value is a number, otherwise returns None.
138    pub fn as_number(&self) -> Option<&NumberValue> {
139        match self {
140            JsonValue::Number(n) => Some(n),
141            _ => None,
142        }
143    }
144
145    /// Returns the wrapped NumberValue if the value is a number, otherwise returns None.
146    pub fn to_number(self) -> Option<NumberValue> {
147        match self {
148            JsonValue::Number(n) => Some(n),
149            _ => None,
150        }
151    }
152
153    /// Returns a boolean indicating whether this value is a boolean or not.
154    pub fn is_bool(&self) -> bool {
155        match self {
156            JsonValue::Boolean(_) => true,
157            _ => false,
158        }
159    }
160
161    /// Returns a reference to the wrapped boolean if this value is a boolean, otherwise returns None.
162    pub fn as_bool(&self) -> Option<&bool> {
163        match self {
164            JsonValue::Boolean(b) => Some(b),
165            _ => None,
166        }
167    }
168
169    /// Returns the wrapped boolean if the value is a boolean, otherwise returns None.
170    pub fn to_bool(self) -> Option<bool> {
171        match self {
172            JsonValue::Boolean(b) => Some(b),
173            _ => None,
174        }
175    }
176
177    /// Returns a boolean indicating whether this value is null or not.
178    pub fn is_null(&self) -> bool {
179        match self {
180            JsonValue::Null => true,
181            _ => false,
182        }
183    }
184}
185
186impl Serialize for NumberValue {
187    fn serialize_to(&self, buffer: &mut Vec<u8>, _indent: u32, _level: u32) {
188        if self.negative {
189            buffer.push(b'-');
190        }
191        buffer.extend_from_slice(self.integer.to_string().as_bytes());
192
193        if self.fraction > 0 {
194            buffer.push(b'.');
195
196            let fraction_nums = self.fraction.to_string();
197            let fraction_length = self.fraction_length as usize;
198            for _ in 0..fraction_length - fraction_nums.len() {
199                buffer.push(b'0');
200            }
201            buffer.extend_from_slice(fraction_nums.as_bytes())
202        }
203        if self.exponent != 0 {
204            buffer.push(b'e');
205            if self.exponent < 0 {
206                buffer.push(b'-');
207            }
208            buffer.extend_from_slice(self.exponent.abs().to_string().as_bytes());
209        }
210    }
211}
212
213fn push_string(buffer: &mut Vec<u8>, chars: &Vec<char>) {
214    buffer.push('"' as u8);
215    for ch in chars {
216        match ch {
217            '\x08' => buffer.extend_from_slice(br#"\b"#),
218            '\x0c' => buffer.extend_from_slice(br#"\f"#),
219            '\n' => buffer.extend_from_slice(br#"\n"#),
220            '\r' => buffer.extend_from_slice(br#"\r"#),
221            '\t' => buffer.extend_from_slice(br#"\t"#),
222            '\"' => buffer.extend_from_slice(br#"\""#),
223            '\\' => buffer.extend_from_slice(br#"\\"#),
224            _ => match ch.len_utf8() {
225                1 => {
226                    let mut buff = [0u8; 1];
227                    ch.encode_utf8(&mut buff);
228                    buffer.push(buff[0]);
229                }
230                2 => {
231                    let mut buff = [0u8; 2];
232                    ch.encode_utf8(&mut buff);
233                    buffer.extend_from_slice(&buff);
234                }
235                3 => {
236                    let mut buff = [0u8; 3];
237                    ch.encode_utf8(&mut buff);
238                    buffer.extend_from_slice(&buff);
239                }
240                4 => {
241                    let mut buff = [0u8; 4];
242                    ch.encode_utf8(&mut buff);
243                    buffer.extend_from_slice(&buff);
244                }
245                _ => panic!("Invalid UTF8 character"),
246            },
247        }
248    }
249    buffer.push('"' as u8);
250}
251
252fn push_new_line_indent(buffer: &mut Vec<u8>, indent: u32, level: u32) {
253    if indent > 0 {
254        buffer.push('\n' as u8);
255    }
256    let count = (indent * level) as usize;
257    buffer.reserve(count);
258    for _ in 0..count {
259        buffer.push(' ' as u8);
260    }
261}
262
263impl Serialize for JsonValue {
264    fn serialize_to(&self, buffer: &mut Vec<u8>, indent: u32, level: u32) {
265        match self {
266            JsonValue::Object(obj) => {
267                buffer.push('{' as u8);
268                if obj.len() > 0 {
269                    push_new_line_indent(buffer, indent, level + 1);
270                    push_string(buffer, &obj[0].0);
271                    buffer.push(':' as u8);
272                    if indent > 0 {
273                        buffer.push(' ' as u8);
274                    }
275                    obj[0].1.serialize_to(buffer, indent, level + 1);
276                    for (key, val) in obj.iter().skip(1) {
277                        buffer.push(',' as u8);
278                        push_new_line_indent(buffer, indent, level + 1);
279                        push_string(buffer, key);
280                        buffer.push(':' as u8);
281                        if indent > 0 {
282                            buffer.push(' ' as u8);
283                        }
284                        val.serialize_to(buffer, indent, level + 1);
285                    }
286                    push_new_line_indent(buffer, indent, level);
287                    buffer.push('}' as u8);
288                } else {
289                    buffer.push('}' as u8);
290                }
291            }
292            JsonValue::Array(arr) => {
293                buffer.push('[' as u8);
294                if arr.len() > 0 {
295                    push_new_line_indent(buffer, indent, level + 1);
296                    arr[0].serialize_to(buffer, indent, level + 1);
297                    for val in arr.iter().skip(1) {
298                        buffer.push(',' as u8);
299                        push_new_line_indent(buffer, indent, level + 1);
300                        val.serialize_to(buffer, indent, level);
301                    }
302                    push_new_line_indent(buffer, indent, level);
303                    buffer.push(']' as u8);
304                } else {
305                    buffer.push(']' as u8);
306                }
307            }
308            JsonValue::String(str) => push_string(buffer, str),
309            JsonValue::Number(num) => num.serialize_to(buffer, indent, level),
310            JsonValue::Boolean(true) => buffer.extend_from_slice(b"true"),
311            JsonValue::Boolean(false) => buffer.extend_from_slice(b"false"),
312            JsonValue::Null => buffer.extend_from_slice(b"null"),
313        }
314    }
315}
316
317#[cfg(test)]
318mod tests {
319    use super::*;
320
321    #[test]
322    fn json_value_convenience_methods() {
323        let obj = JsonValue::Object(vec![(vec![], JsonValue::Null)]);
324        assert!(obj.is_object());
325        assert_eq!(obj.as_object(), Some(&[(vec![], JsonValue::Null)][..]));
326        assert_eq!(obj.as_array(), None);
327        assert_eq!(obj.as_bool(), None);
328        assert_eq!(obj.as_number(), None);
329        assert_eq!(obj.as_string(), None);
330        assert_eq!(
331            obj.clone().to_object(),
332            Some(vec![(vec![], JsonValue::Null)]),
333        );
334        assert_eq!(obj.clone().to_array(), None);
335        assert_eq!(obj.clone().to_bool(), None);
336        assert_eq!(obj.clone().to_number(), None);
337        assert_eq!(obj.clone().to_string(), None);
338
339        let arr = JsonValue::Array(vec![JsonValue::Null]);
340        assert!(arr.is_array());
341        assert_eq!(arr.as_array(), Some(&[JsonValue::Null][..]));
342        assert_eq!(arr.as_object(), None);
343        assert_eq!(arr.as_bool(), None);
344        assert_eq!(arr.as_number(), None);
345        assert_eq!(arr.as_string(), None);
346        assert_eq!(arr.clone().to_array(), Some(vec![JsonValue::Null]));
347        assert_eq!(arr.clone().to_object(), None);
348        assert_eq!(arr.clone().to_bool(), None);
349        assert_eq!(arr.clone().to_number(), None);
350        assert_eq!(arr.clone().to_string(), None);
351
352        let s = JsonValue::String(vec!['a']);
353        assert!(s.is_string());
354        assert_eq!(s.as_string(), Some(&['a'][..]));
355        assert_eq!(s.as_object(), None);
356        assert_eq!(s.as_bool(), None);
357        assert_eq!(s.as_number(), None);
358        assert_eq!(s.as_array(), None);
359        assert_eq!(s.clone().to_string(), Some(vec!['a']));
360        assert_eq!(s.clone().to_object(), None);
361        assert_eq!(s.clone().to_bool(), None);
362        assert_eq!(s.clone().to_number(), None);
363        assert_eq!(s.clone().to_array(), None);
364
365        let n = JsonValue::Number(NumberValue {
366            integer: 0,
367            fraction: 0,
368            fraction_length: 0,
369            exponent: 0,
370            negative: false,
371        });
372        assert!(n.is_number());
373        assert_eq!(
374            n.as_number(),
375            Some(&NumberValue {
376                integer: 0,
377                fraction: 0,
378                fraction_length: 0,
379                exponent: 0,
380                negative: false,
381            }),
382        );
383        assert_eq!(n.as_object(), None);
384        assert_eq!(n.as_bool(), None);
385        assert_eq!(n.as_string(), None);
386        assert_eq!(n.as_array(), None);
387        assert_eq!(
388            n.clone().to_number(),
389            Some(NumberValue {
390                integer: 0,
391                fraction: 0,
392                fraction_length: 0,
393                exponent: 0,
394                negative: false,
395            }),
396        );
397        assert_eq!(n.clone().to_object(), None);
398        assert_eq!(n.clone().to_bool(), None);
399        assert_eq!(n.clone().to_string(), None);
400        assert_eq!(n.clone().to_array(), None);
401
402        let b = JsonValue::Boolean(false);
403        assert!(b.is_bool());
404        assert_eq!(b.as_bool(), Some(&false));
405        assert_eq!(b.as_object(), None);
406        assert_eq!(b.as_number(), None);
407        assert_eq!(b.as_string(), None);
408        assert_eq!(b.as_array(), None);
409        assert_eq!(b.clone().to_bool(), Some(false));
410        assert_eq!(b.clone().to_object(), None);
411        assert_eq!(b.clone().to_number(), None);
412        assert_eq!(b.clone().to_string(), None);
413        assert_eq!(b.clone().to_array(), None);
414
415        let null = JsonValue::Null;
416        assert!(null.is_null());
417        assert_eq!(null.as_array(), None);
418        assert_eq!(null.as_bool(), None);
419        assert_eq!(null.as_number(), None);
420        assert_eq!(null.as_object(), None);
421        assert_eq!(null.as_string(), None);
422        assert_eq!(null.clone().to_array(), None);
423        assert_eq!(null.clone().to_bool(), None);
424        assert_eq!(null.clone().to_number(), None);
425        assert_eq!(null.clone().to_object(), None);
426        assert_eq!(null.clone().to_string(), None);
427    }
428
429    #[test]
430    fn serialize_number_value() {
431        let val = NumberValue {
432            integer: 1234,
433            fraction: 0,
434            fraction_length: 0,
435            exponent: 0,
436            negative: false,
437        };
438        assert_eq!(val.serialize(), b"1234");
439
440        let val = NumberValue {
441            integer: 1234,
442            fraction: 0,
443            fraction_length: 0,
444            exponent: 0,
445            negative: true,
446        };
447        assert_eq!(val.serialize(), b"-1234");
448
449        let val = NumberValue {
450            integer: 1234,
451            fraction: 5678,
452            fraction_length: 4,
453            exponent: 0,
454            negative: true,
455        };
456        assert_eq!(val.serialize(), b"-1234.5678");
457
458        let val = NumberValue {
459            integer: 1234,
460            fraction: 1,
461            fraction_length: 3,
462            exponent: 0,
463            negative: false,
464        };
465        assert_eq!(val.serialize(), b"1234.001");
466
467        let val = NumberValue {
468            integer: 1234,
469            fraction: 0,
470            fraction_length: 0,
471            exponent: 3,
472            negative: false,
473        };
474        assert_eq!(val.serialize(), b"1234e3");
475
476        let val = NumberValue {
477            integer: 1234,
478            fraction: 0,
479            fraction_length: 0,
480            exponent: -5,
481            negative: false,
482        };
483        assert_eq!(val.serialize(), b"1234e-5");
484
485        let val = NumberValue {
486            integer: 1234,
487            fraction: 56,
488            fraction_length: 4,
489            exponent: -5,
490            negative: false,
491        };
492        assert_eq!(val.serialize(), b"1234.0056e-5");
493
494        let val = NumberValue {
495            integer: 1234,
496            fraction: 5,
497            fraction_length: 2,
498            exponent: 5,
499            negative: true,
500        };
501        assert_eq!(val.serialize(), b"-1234.05e5");
502    }
503
504    #[test]
505    fn serialize_works() {
506        let obj = JsonValue::Object(vec![(
507            "test\"123".chars().into_iter().collect(),
508            JsonValue::Null,
509        )]);
510        assert_eq!(
511            std::str::from_utf8(&obj.format(4)[..]).unwrap(),
512            r#"{
513    "test\"123": null
514}"#
515        );
516
517        let obj = JsonValue::Object(vec![
518            (
519                vec!['t', 'e', 's', 't'],
520                JsonValue::Number(NumberValue {
521                    integer: 123,
522                    fraction: 4,
523                    fraction_length: 2,
524                    exponent: 0,
525                    negative: false,
526                }),
527            ),
528            (
529                vec!['t', 'e', 's', 't', '2'],
530                JsonValue::Array(vec![
531                    JsonValue::Number(NumberValue {
532                        integer: 1,
533                        fraction: 0,
534                        fraction_length: 0,
535                        exponent: -4,
536                        negative: false,
537                    }),
538                    JsonValue::Number(NumberValue {
539                        integer: 2,
540                        fraction: 41,
541                        fraction_length: 3,
542                        exponent: 2,
543                        negative: false,
544                    }),
545                    JsonValue::Boolean(true),
546                    JsonValue::Boolean(false),
547                    JsonValue::Null,
548                    JsonValue::String(vec!['\"', '1', 'n', '\"']),
549                    JsonValue::Object(vec![]),
550                    JsonValue::Array(vec![]),
551                ]),
552            ),
553        ]);
554
555        assert_eq!(
556            std::str::from_utf8(&obj.format(4)[..]).unwrap(),
557            r#"{
558    "test": 123.04,
559    "test2": [
560        1e-4,
561        2.041e2,
562        true,
563        false,
564        null,
565        "\"1n\"",
566        {},
567        []
568    ]
569}"#
570        );
571
572        assert_eq!(
573            std::str::from_utf8(&obj.serialize()[..]).unwrap(),
574            r#"{"test":123.04,"test2":[1e-4,2.041e2,true,false,null,"\"1n\"",{},[]]}"#
575        );
576    }
577
578    #[test]
579    fn to_f64_works() {
580        use assert_float_eq::*;
581
582        assert_f64_near!(
583            NumberValue {
584                integer: 1,
585                fraction: 5,
586                fraction_length: 1,
587                exponent: 0,
588                negative: true,
589            }
590            .to_f64(),
591            -1.5
592        );
593
594        assert_f64_near!(
595            NumberValue {
596                integer: 0,
597                fraction: 5,
598                fraction_length: 1,
599                exponent: 0,
600                negative: true,
601            }
602            .to_f64(),
603            -0.5
604        );
605
606        assert_f64_near!(
607            NumberValue {
608                integer: 0,
609                fraction: 5,
610                fraction_length: 1,
611                exponent: 0,
612                negative: false,
613            }
614            .to_f64(),
615            0.5
616        );
617
618        assert_f64_near!(
619            NumberValue {
620                integer: 1,
621                fraction: 15,
622                fraction_length: 3,
623                exponent: 1,
624                negative: false,
625            }
626            .to_f64(),
627            10.15
628        );
629
630        assert_f64_near!(
631            NumberValue {
632                integer: 1,
633                fraction: 15,
634                fraction_length: 3,
635                exponent: -1,
636                negative: true,
637            }
638            .to_f64(),
639            -0.1015
640        );
641    }
642}