json/
json.rs

1#[allow(dead_code)]
2extern crate bad_parsers;
3
4use std::collections::HashMap;
5use std::str::FromStr;
6
7use bad_parsers::{
8    eof, first_of, lazy, string, token, token_satisfies, ParseError, Parser, Tokens,
9};
10
11// JSON is being parsed according to the grammar at: https://www.json.org/json-en.html
12// It's not exactly produciton-ready, but it works well enough
13// Also, lexing JSON and then parsing the tokens is overkill for such a simple format,
14// but I want to demonstrate the fact that you can do both
15#[allow(dead_code)]
16#[derive(Debug, PartialEq)]
17enum Json {
18    Null,
19    Bool(bool),
20    Int(i64),
21    Float(f64),
22    String(String),
23    Array(Vec<Json>),
24    Object(HashMap<String, Json>),
25}
26
27macro_rules! impl_json_from {
28    ($t:ty, $i:ident) => {
29        impl From<$t> for Json {
30            fn from(value: $t) -> Self {
31                Json::$i(value)
32            }
33        }
34    };
35}
36
37impl_json_from!(bool, Bool);
38impl_json_from!(i64, Int);
39impl_json_from!(f64, Float);
40impl_json_from!(String, String);
41impl_json_from!(Vec<Json>, Array);
42impl_json_from!(HashMap<String, Json>, Object);
43
44impl From<&str> for Json {
45    fn from(value: &str) -> Self {
46        Json::String(value.to_owned())
47    }
48}
49
50// digit string is one or more ascii digits, does not check for leading zeroes
51// string literal contains the chars between the quote marks, may be empty
52#[derive(Debug, Clone, PartialEq, Eq)]
53enum JToken {
54    StringLiteral(String),
55    DigitString(String),
56    True,
57    False,
58    Null,
59    OpenCurly,
60    CloseCurly,
61    Colon,
62    Comma,
63    OpenSquare,
64    CloseSquare,
65    Minus,
66    Plus,
67    E,
68    Dot,
69}
70
71// using the definition of whitespace found in the spec
72fn is_whitespace(c: &char) -> bool {
73    matches!(c, '\u{20}' | '\u{0D}' | '\u{0A}' | '\u{09}')
74}
75
76fn ws<'a>() -> impl Parser<'a, &'a str, char, ()> {
77    token_satisfies(is_whitespace).mult().ignore()
78}
79
80macro_rules! lex_simple {
81    ($name:ident, $pat:literal, $tok:ident) => {
82        fn $name<'a>() -> impl Parser<'a, &'a str, char, JToken> {
83            string($pat).replace(JToken::$tok)
84        }
85    };
86}
87lex_simple!(lex_true, "true", True);
88lex_simple!(lex_false, "false", False);
89lex_simple!(lex_null, "null", Null);
90lex_simple!(lex_open_curly, "{", OpenCurly);
91lex_simple!(lex_close_curly, "}", CloseCurly);
92lex_simple!(lex_colon, ":", Colon);
93lex_simple!(lex_comma, ",", Comma);
94lex_simple!(lex_open_square, "[", OpenSquare);
95lex_simple!(lex_close_square, "]", CloseSquare);
96lex_simple!(lex_minus, "-", Minus);
97lex_simple!(lex_plus, "+", Plus);
98lex_simple!(lex_dot, ".", Dot);
99
100fn lex_e<'a>() -> impl Parser<'a, &'a str, char, JToken> {
101    token('e').or(token('E')).replace(JToken::E)
102}
103
104fn lex_digit_string<'a>() -> impl Parser<'a, &'a str, char, JToken> {
105    token_satisfies(char::is_ascii_digit)
106        .mult1()
107        .map(|cs| JToken::DigitString(String::from_iter(cs)))
108}
109
110fn extract_codepoint(text: &str) -> Option<(&str, char)> {
111    let (point_text, rest) = text.split_at_checked(4)?;
112    // note: from_str_radix(_, 16) allows for mixed-case hex literals,
113    // so no upper/lower case conversion is required
114    let u = u32::from_str_radix(point_text, 16).ok()?;
115    let c = char::try_from(u).ok()?;
116    Some((rest, c))
117}
118
119fn string_char<'a>() -> impl Parser<'a, &'a str, char, char> {
120    |input: &'a str| {
121        if let Some(input2) = input.strip_prefix('\\') {
122            match input2.take_one() {
123                None => Err(ParseError::no_parse(
124                    "expected escape sequence to continue but found end-of-input",
125                    input,
126                )),
127                Some((input3, 'u')) => match extract_codepoint(input3) {
128                    Some((input4, c)) => Ok((input4, c)),
129                    None => Err(ParseError::no_parse("invalid codepoint literal", input)),
130                },
131                Some((input3, '\\')) => Ok((input3, '\\')),
132                Some((input3, '"')) => Ok((input3, '"')),
133                Some((input3, 'n')) => Ok((input3, '\n')),
134                Some((input3, 'r')) => Ok((input3, '\r')),
135                Some((input3, 't')) => Ok((input3, '\t')),
136                Some((input3, 'f')) => Ok((input3, '\u{000c}')),
137                Some((input3, 'b')) => Ok((input3, '\u{0008}')),
138                // i'm not sure why this needs an escape sequence, but it's in the spec
139                Some((input3, '/')) => Ok((input3, '/')),
140                Some(_) => Err(ParseError::no_parse("invalid escape sequence", input)),
141            }
142        } else {
143            match input.take_one() {
144                None => Err(ParseError::empty_input(
145                    "expected string literal to continue, but got end of input",
146                )),
147                Some((_inp2, '"')) => Err(ParseError::no_parse(
148                    "unescaped double-quotes are not valid string body characters",
149                    input,
150                )),
151                // only need to check the lower limit, chars with scalar-values
152                // higher than 0x10ffff don't show up in safe rust
153                Some((_inp2, '\u{0000}'..'\u{0020}')) => Err(ParseError::no_parse(
154                    "found char with a non-allowed scalar value",
155                    input,
156                )),
157                Some((rest, c)) => Ok((rest, c)),
158            }
159        }
160    }
161}
162
163fn string_literal<'a>() -> impl Parser<'a, &'a str, char, String> {
164    string_char()
165        .mult()
166        .within(token('"'))
167        .map(String::from_iter)
168}
169
170fn lex_string_literal<'a>() -> impl Parser<'a, &'a str, char, JToken> {
171    string_literal().map(JToken::StringLiteral)
172}
173
174fn lex_lexeme<'a>() -> impl Parser<'a, &'a str, char, JToken> {
175    first_of![
176        lex_true(),
177        lex_false(),
178        lex_null(),
179        lex_open_curly(),
180        lex_close_curly(),
181        lex_colon(),
182        lex_comma(),
183        lex_open_square(),
184        lex_close_square(),
185        lex_minus(),
186        lex_plus(),
187        lex_dot(),
188        lex_digit_string(),
189        lex_string_literal(),
190        lex_e(),
191    ]
192}
193
194fn lex_json<'a>() -> impl Parser<'a, &'a str, char, Vec<JToken>> {
195    lex_lexeme().sep_by(ws()).within(ws())
196}
197
198fn json_null<'a>() -> impl Parser<'a, &'a [JToken], JToken, Json> {
199    // map instead of replace saves implementing clone for Json
200    token(JToken::Null).map(|_| Json::Null)
201}
202
203fn json_bool<'a>() -> impl Parser<'a, &'a [JToken], JToken, Json> {
204    token(JToken::True)
205        .replace(true)
206        .or(token(JToken::False).replace(false))
207        .convert()
208}
209
210fn json_digit_string<'a>() -> impl Parser<'a, &'a [JToken], JToken, String> {
211    |input: &'a [JToken]| match input.take_one() {
212        Some((rest, JToken::DigitString(s))) => Ok((rest, s)),
213        Some((_rest, t)) => {
214            let msg = format!("expected digit string, but found: {:?}", t);
215            Err(ParseError::no_parse(&msg, input))
216        }
217        None => Err(ParseError::empty_input(
218            "expected digit string but found nothing",
219        )),
220    }
221}
222
223// parses ::Plus or ::Minus, returns (== ::Minus)
224fn json_sign_is_negative<'a>() -> impl Parser<'a, &'a [JToken], JToken, bool> {
225    token(JToken::Minus)
226        .replace(true)
227        .or(token(JToken::Plus).replace(false))
228}
229
230// returns Int and Float Json variants
231fn json_number<'a>() -> impl Parser<'a, &'a [JToken], JToken, Json> {
232    let integer = token(JToken::Minus)
233        .optional()
234        .plus(json_digit_string().ensure(|s| s == "0" || !s.starts_with('0')));
235    let fraction = token(JToken::Dot).right(json_digit_string());
236    let exponent = token(JToken::E).right(
237        json_sign_is_negative()
238            .recover(false)
239            .plus(json_digit_string()),
240    );
241
242    let p = integer.plus(fraction.optional()).plus(exponent.optional());
243
244    move |input: &'a [JToken]| {
245        let (inp, (((opt_neg_sign, i_body), frac), exp)) = p.parse(input)?;
246
247        // Implementation choice: if the string contains a fraction component AND/OR
248        // an exponent component, it is treated as a float
249        if frac.is_some() || exp.is_some() {
250            let exp_str = if let Some((exp_sign, exp_digits)) = exp {
251                format!("e{}{}", if exp_sign { "-" } else { "" }, exp_digits)
252            } else {
253                "".to_string()
254            };
255            let full_string = format!(
256                "{}{}.{}{}",
257                if opt_neg_sign.is_some() { "-" } else { "" },
258                i_body,
259                frac.unwrap_or("0".to_string()),
260                exp_str,
261            );
262            // i promise this isn't cheating
263            match f64::from_str(&full_string) {
264                Ok(f) => Ok((inp, Json::Float(f))),
265                Err(parse_float_error) => {
266                    let details = &format!(
267                        "successfully parsed the float ({}), but the type conversion failed",
268                        full_string
269                    );
270                    Err(ParseError::other(details, inp, parse_float_error))
271                }
272            }
273        } else {
274            let full_string = format!(
275                "{}{}",
276                if opt_neg_sign.is_some() { "-" } else { "" },
277                i_body
278            );
279            // i still promise this isn't cheating
280            match i64::from_str(&full_string) {
281                Ok(i) => Ok((inp, Json::Int(i))),
282                Err(parse_int_error) => {
283                    let details = &format!(
284                        "successfully parsed the int ({}), but the type conversion failed",
285                        full_string
286                    );
287                    Err(ParseError::other(details, inp, parse_int_error))
288                }
289            }
290        }
291    }
292}
293
294// used for string values and object keys
295fn json_string_literal<'a>() -> impl Parser<'a, &'a [JToken], JToken, String> {
296    |input: &'a [JToken]| match input.take_one() {
297        Some((rest, JToken::StringLiteral(s))) => Ok((rest, s)),
298        Some((_rest, t)) => {
299            let msg = format!("expected string literal, but found: {:?}", t);
300            Err(ParseError::no_parse(&msg, input))
301        }
302        None => Err(ParseError::empty_input(
303            "expected string literal but found nothing",
304        )),
305    }
306}
307
308fn json_string<'a>() -> impl Parser<'a, &'a [JToken], JToken, Json> {
309    json_string_literal().convert()
310}
311
312// spec does not support trailing commas for arrays
313fn json_array<'a>() -> impl Parser<'a, &'a [JToken], JToken, Json> {
314    let arr_body = lazy(json_value)
315        .sep_by(token(JToken::Comma))
316        .recover_default()
317        .boxed();
318    arr_body
319        .between(token(JToken::OpenSquare), token(JToken::CloseSquare))
320        .convert()
321}
322
323// Implementation choice: duplicate object keys will be handled
324// according to ECMA-262: "In the case where there are duplicate
325// name Strings within an object, lexically preceding values
326// for the same key shall be overwritten."
327// This is also the current behavior for HashMap::from([(K, V); const N])
328// as well as HashMap::from_iter(), so this behavior should be implemented for free.
329fn json_object<'a>() -> impl Parser<'a, &'a [JToken], JToken, Json> {
330    let member = json_string_literal()
331        .left(token(JToken::Colon))
332        .plus(lazy(json_value))
333        .boxed();
334    member
335        .sep_by(token(JToken::Comma))
336        .recover_default()
337        .between(token(JToken::OpenCurly), token(JToken::CloseCurly))
338        .map(HashMap::<String, Json>::from_iter)
339        .convert()
340}
341
342fn json_value<'a>() -> impl Parser<'a, &'a [JToken], JToken, Json> {
343    first_of![
344        json_null(),
345        json_bool(),
346        json_number(),
347        json_string(),
348        json_array(),
349        json_object(),
350    ]
351}
352
353// yes, this discards all of the error information, i don't care
354fn parse_json(input_string: &str) -> Option<Json> {
355    let lex = lex_json();
356    //println!("About to lex");
357    let tokens = lex.parse(input_string).ok()?.1;
358    //println!("Got tokens: {:?}", tokens);
359
360    //println!("About to parse");
361    let p = json_value().left(eof());
362    p.parse(tokens.as_slice()).ok().map(|tup| tup.1)
363}
364
365fn main() {
366    let r = parse_json(r#"[null, true, 3, 4.5]"#);
367    println!("parsed: {:?}", r);
368}
369
370#[cfg(test)]
371mod tests {
372    use super::*;
373
374    macro_rules! assert_none {
375        ($e:expr) => {
376            assert!($e.is_none());
377        };
378    }
379
380    #[test]
381    fn example_json_test_null() {
382        assert_eq!(Json::Null, parse_json("null").unwrap());
383        assert_eq!(Json::Null, parse_json("null_extra").unwrap());
384
385        assert_none!(parse_json(""));
386        assert_none!(parse_json("nUll"));
387        assert_none!(parse_json("nil"));
388        assert_none!(parse_json("Null"));
389    }
390
391    #[test]
392    fn example_json_test_bool() {
393        assert_eq!(Json::Bool(true), parse_json("true").unwrap());
394        assert_eq!(Json::Bool(false), parse_json("false").unwrap());
395        assert_eq!(Json::Bool(true), parse_json("true_extra").unwrap());
396        assert_eq!(Json::Bool(false), parse_json("false_extra").unwrap());
397
398        assert_none!(parse_json(""));
399        assert_none!(parse_json("frue"));
400        assert_none!(parse_json("tralse"));
401        assert_none!(parse_json("False"));
402        assert_none!(parse_json("True"));
403    }
404
405    #[test]
406    fn example_json_test_number() {
407        assert_eq!(Json::Int(0), parse_json("0").unwrap());
408        assert_eq!(Json::Int(0), parse_json("-0").unwrap());
409        assert_eq!(Json::Int(123450), parse_json("123450").unwrap());
410        assert_eq!(Json::Int(-67890), parse_json("-67890").unwrap());
411
412        assert_eq!(Json::Int(123), parse_json("123_450").unwrap());
413        assert_eq!(Json::Int(123), parse_json("123_450.678").unwrap());
414
415        assert_eq!(Json::Float(0.0), parse_json("0.0").unwrap());
416        assert_eq!(Json::Float(-0.0), parse_json("-0.0").unwrap());
417
418        assert_eq!(Json::Float(12345.06789), parse_json("12345.06789").unwrap());
419        assert_eq!(
420            Json::Float(-12345.06789),
421            parse_json("-12345.06789").unwrap()
422        );
423
424        // exhaustive format checks, '2' added to end of all patterns
425        // with decimal point
426        assert_eq!(Json::Float(12.342), parse_json("12.342").unwrap());
427        assert_eq!(Json::Float(-12.342), parse_json("-12.342").unwrap());
428        assert_eq!(Json::Float(1234.0), parse_json("12.34e2").unwrap());
429        assert_eq!(Json::Float(-1234.0), parse_json("-12.34e2").unwrap());
430        assert_eq!(Json::Float(1234.0), parse_json("12.34E2").unwrap());
431        assert_eq!(Json::Float(-1234.0), parse_json("-12.34E2").unwrap());
432        assert_none!(parse_json("12.34+2"));
433        assert_none!(parse_json("-12.34+2"));
434        assert_eq!(Json::Float(1234.0), parse_json("12.34e+2").unwrap());
435        assert_eq!(Json::Float(-1234.0), parse_json("-12.34e+2").unwrap());
436        assert_eq!(Json::Float(1234.0), parse_json("12.34E+2").unwrap());
437        assert_eq!(Json::Float(-1234.0), parse_json("-12.34E+2").unwrap());
438        assert_none!(parse_json("12.34-2"));
439        assert_none!(parse_json("-12.34-2"));
440        assert_eq!(Json::Float(0.1234), parse_json("12.34e-2").unwrap());
441        assert_eq!(Json::Float(-0.1234), parse_json("-12.34e-2").unwrap());
442        assert_eq!(Json::Float(0.1234), parse_json("12.34E-2").unwrap());
443        assert_eq!(Json::Float(-0.1234), parse_json("-12.34E-2").unwrap());
444        //without decimal point
445        assert_eq!(Json::Int(12342), parse_json("12342").unwrap());
446        assert_eq!(Json::Int(-12342), parse_json("-12342").unwrap());
447        assert_eq!(Json::Float(123400.0), parse_json("1234e2").unwrap());
448        assert_eq!(Json::Float(-123400.0), parse_json("-1234e2").unwrap());
449        assert_eq!(Json::Float(123400.0), parse_json("1234E2").unwrap());
450        assert_eq!(Json::Float(-123400.0), parse_json("-1234E2").unwrap());
451        assert_none!(parse_json("1234+2"));
452        assert_none!(parse_json("-1234+2"));
453        assert_eq!(Json::Float(123400.0), parse_json("1234e+2").unwrap());
454        assert_eq!(Json::Float(-123400.0), parse_json("-1234e+2").unwrap());
455        assert_eq!(Json::Float(123400.0), parse_json("1234E+2").unwrap());
456        assert_eq!(Json::Float(-123400.0), parse_json("-1234E+2").unwrap());
457        assert_none!(parse_json("1234-2"));
458        assert_none!(parse_json("-1234-2"));
459        assert_eq!(Json::Float(12.34), parse_json("1234e-2").unwrap());
460        assert_eq!(Json::Float(-12.34), parse_json("-1234e-2").unwrap());
461        assert_eq!(Json::Float(12.34), parse_json("1234E-2").unwrap());
462        assert_eq!(Json::Float(-12.34), parse_json("-1234E-2").unwrap());
463
464        // only 'zero' values can begin their whole component with zero:
465        assert_none!(parse_json("01"));
466        assert_none!(parse_json("01.0"));
467        assert_none!(parse_json("-01"));
468        assert_none!(parse_json("-01.0e4"));
469
470        // correct handling of values out of range of i64
471        let i64min_str = "-9223372036854775808";
472        assert_eq!(
473            Json::Int(-9_223_372_036_854_775_808i64),
474            parse_json(i64min_str).unwrap()
475        );
476        let i64min_minus1_str = "-9223372036854775809";
477        assert_none!(parse_json(i64min_minus1_str));
478        assert_none!(parse_json(
479            "-9999999999999999999999999999999999999999999999999"
480        ));
481        let i64max_str = "9223372036854775807";
482        assert_eq!(
483            Json::Int(9_223_372_036_854_775_807i64),
484            parse_json(i64max_str).unwrap()
485        );
486        let i64max_plus1_str = "9223372036854775808"; //-1.7976931348623157E+308f64
487        assert_none!(parse_json(i64max_plus1_str));
488        assert_none!(parse_json(
489            "9999999999999999999999999999999999999999999999999"
490        ));
491
492        // TODO: test extreme values of f64
493    }
494
495    #[test]
496    fn example_json_test_string() {
497        assert_eq!(Json::String("".into()), parse_json("\"\"").unwrap());
498        assert_eq!(Json::String("foo".into()), parse_json("\"foo\"").unwrap());
499
500        assert_eq!(
501            Json::String("text with \" some \\ escapes".into()),
502            parse_json("\"text with \\\" some \\\\ escapes\"").unwrap()
503        );
504
505        // every (supported) escape sequence
506        assert_eq!(Json::String("\\".into()), parse_json(r#""\\""#).unwrap());
507        assert_eq!(Json::String("/".into()), parse_json(r#""\/""#).unwrap());
508        assert_eq!(Json::String("\"".into()), parse_json(r#""\"""#).unwrap());
509        assert_eq!(
510            Json::String("\u{0008}".into()),
511            parse_json(r#""\b""#).unwrap()
512        );
513        assert_eq!(
514            Json::String("\u{000C}".into()),
515            parse_json(r#""\f""#).unwrap()
516        );
517        assert_eq!(Json::String("\n".into()), parse_json(r#""\n""#).unwrap());
518        assert_eq!(Json::String("\r".into()), parse_json(r#""\r""#).unwrap());
519        assert_eq!(Json::String("\t".into()), parse_json(r#""\t""#).unwrap());
520        // unicode codepoints
521        assert_eq!(Json::String("A".into()), parse_json(r#""\u0041""#).unwrap());
522        assert_eq!(Json::String("Σ".into()), parse_json(r#""\u03a3""#).unwrap());
523        assert_eq!(Json::String("Σ".into()), parse_json(r#""\u03A3""#).unwrap());
524
525        // un-escaped control characters
526        assert_none!(parse_json("\"\0\""));
527        assert_none!(parse_json("\"\n\""));
528        assert_none!(parse_json("\"\u{1B}\""));
529
530        // invalid escape sequences
531        assert_none!(parse_json(r#""\""#));
532        assert_none!(parse_json(r#""\j""#));
533        assert_none!(parse_json(r#""\0""#));
534        assert_none!(parse_json(r#""\xab""#));
535
536        // invalid unicode codepoints
537        assert_none!(parse_json(r#""\uD800""#));
538        assert_none!(parse_json(r#""\uDFFF""#));
539        assert_none!(parse_json(r#""\uDE01""#));
540    }
541
542    #[test]
543    fn example_json_test_array() {
544        assert_eq!(Json::Array(vec![]), parse_json("[]").unwrap());
545        assert_eq!(Json::Array(vec![]), parse_json("[  ]").unwrap());
546        assert_none!(parse_json("[  ]extra"));
547        assert_eq!(
548            Json::Array(vec![Json::Null]),
549            parse_json("[ null]").unwrap()
550        );
551        assert_eq!(
552            Json::Array(vec![Json::Bool(true), Json::Bool(false)]),
553            parse_json("[true, false ]").unwrap()
554        );
555        assert_eq!(
556            Json::Array(vec![
557                Json::from(1),
558                Json::from(2),
559                Json::from(3),
560                Json::from(-4.5),
561                Json::from(1.0e2),
562            ]),
563            parse_json("[1, 2, 3, -4.5, 1e2]").unwrap()
564        );
565        assert_eq!(
566            Json::Array(vec!["strings".into(), "in".into(), "arrays".into(),]),
567            parse_json(r#"[ "strings", "in", "arrays" ]"#).unwrap()
568        );
569        assert_eq!(
570            Json::Array(vec![
571                Json::from("we"),
572                Json::from(vec![Json::from("even")]),
573                Json::from(vec![Json::from(vec![
574                    Json::from("have"),
575                    Json::from(vec![Json::from("nested"), Json::from("arrays"),]),
576                ]),]),
577            ]),
578            parse_json(r#"["we",["even"],[["have",["nested","arrays"]]]]"#).unwrap()
579        );
580
581        assert_eq!(
582            Json::Array(vec![
583                Json::from(HashMap::from([
584                    ("objects".into(), "with".into()),
585                    ("multiple".into(), "keys".into()),
586                ])),
587                Json::from(HashMap::from([])),
588                Json::from(HashMap::from([("inside".into(), "arrays".into())])),
589            ]),
590            parse_json(
591                r#"[
592                {"objects": "with", "multiple": "keys"},
593                {},
594                {"inside": "arrays"}
595            ]"#
596            )
597            .unwrap()
598        );
599
600        // internal whitespace is fine
601        assert_eq!(Json::Array(vec![]), parse_json("[ \t\n\r  ]").unwrap());
602        assert_eq!(Json::Array(vec![Json::Null]), parse_json("[null]").unwrap());
603        assert_eq!(
604            Json::Array(vec![Json::Null]),
605            parse_json("[ null]").unwrap()
606        );
607        assert_eq!(
608            Json::Array(vec![Json::Null]),
609            parse_json("[null ]").unwrap()
610        );
611        assert_eq!(
612            Json::Array(vec![Json::Null]),
613            parse_json("[    null   ]").unwrap()
614        );
615
616        macro_rules! a {
617            () => {
618                Json::Array(vec![Json::Null, Json::Null])
619            };
620        }
621        assert_eq!(a!(), parse_json("[null,null]").unwrap());
622        assert_eq!(a!(), parse_json("[null,null ]").unwrap());
623        assert_eq!(a!(), parse_json("[null, null]").unwrap());
624        assert_eq!(a!(), parse_json("[null, null ]").unwrap());
625        assert_eq!(a!(), parse_json("[null ,null]").unwrap());
626        assert_eq!(a!(), parse_json("[null ,null ]").unwrap());
627        assert_eq!(a!(), parse_json("[null , null]").unwrap());
628        assert_eq!(a!(), parse_json("[null , null ]").unwrap());
629        assert_eq!(a!(), parse_json("[ null,null]").unwrap());
630        assert_eq!(a!(), parse_json("[ null,null ]").unwrap());
631        assert_eq!(a!(), parse_json("[ null, null]").unwrap());
632        assert_eq!(a!(), parse_json("[ null, null ]").unwrap());
633        assert_eq!(a!(), parse_json("[ null ,null]").unwrap());
634        assert_eq!(a!(), parse_json("[ null ,null ]").unwrap());
635        assert_eq!(a!(), parse_json("[ null , null]").unwrap());
636        assert_eq!(a!(), parse_json("[ null , null ]").unwrap());
637
638        assert_none!(parse_json(r#""#));
639        assert_none!(parse_json("[ bhsrlre ]"));
640        assert_none!(parse_json(r#"[ "oops\", "forgot the closing bracket" "#));
641        assert_none!(parse_json(r#" "forgot the opening bracket too" ]"#));
642        assert_none!(parse_json(r#" "are brackets", " even real?" "#));
643
644        // no trailing commas
645        assert_none!(parse_json("[ , ]"));
646        assert_none!(parse_json("[ 8, ]"));
647        assert_none!(parse_json("[8, 9 10,]"));
648        assert_none!(parse_json("[8, [9,], 10]"));
649    }
650
651    #[test]
652    fn example_json_test_object() {
653        assert_eq!(Json::from(HashMap::from([])), parse_json("{}").unwrap());
654        assert_eq!(
655            Json::Object(HashMap::from([("foo".into(), Json::Null)]).into()),
656            parse_json(r#"{"foo":null}"#).unwrap()
657        );
658        assert_eq!(
659            Json::Object(HashMap::from([
660                ("attribute".into(), Json::Null),
661                ("values".into(), false.into()),
662                ("can".into(), 12.into()),
663                ("be".into(), 21.0.into()),
664                ("any".into(), "type".into()),
665                ("including".into(), vec!["arrays".into()].into()),
666                (
667                    "and".into(),
668                    HashMap::from([("other".into(), "objects".into())]).into()
669                ),
670            ])),
671            parse_json(
672                r#"{
673                "attribute": null,
674                "values": false,
675                "can": 12,
676                "be": 21.0,
677                "any": "type",
678                "including": ["arrays"],
679                "and": {"other": "objects"}
680            }"#
681            )
682            .unwrap()
683        );
684        assert_eq!(
685            Json::Object(HashMap::from([
686                (
687                    "first".into(),
688                    HashMap::from([("one".into(), 1.into())]).into()
689                ),
690                (
691                    "second".into(),
692                    HashMap::from([("two_i".into(), 2.into()), ("two_f".into(), 2.0.into()),])
693                        .into()
694                ),
695                (
696                    "three".into(),
697                    HashMap::from([(
698                        "four".into(),
699                        HashMap::from([(
700                            "five".into(),
701                            HashMap::from([("six".into(), 7.into())]).into()
702                        )])
703                        .into()
704                    )])
705                    .into()
706                ),
707            ])),
708            parse_json(
709                r#"{
710                "first": {"one":1},
711                "second": {
712                    "two_i": 2,
713                    "two_f": 2.0
714                },
715                "three": {"four": {"five": {"six":7} }}
716            }"#
717            )
718            .unwrap()
719        );
720
721        assert_none!(parse_json(r#""#));
722        assert_none!(parse_json(r#" {"oh": "no" "#));
723        assert_none!(parse_json(r#" "it's happening": "again" } "#));
724        assert_none!(parse_json(r#" "why am i":"like this" "#));
725
726        // internal whitespace is ok
727        macro_rules! o {
728            () => {
729                Json::Object(HashMap::from([(String::from("one"), Json::Int(1))]))
730            };
731        }
732        assert_eq!(o!(), parse_json(r#"{"one":1}"#).unwrap());
733        assert_eq!(o!(), parse_json(r#"{ "one":1}"#).unwrap());
734        assert_eq!(o!(), parse_json(r#"{ "one" :1}"#).unwrap());
735        assert_eq!(o!(), parse_json(r#"{ "one" : 1}"#).unwrap());
736        assert_eq!(o!(), parse_json(r#"{ "one" : 1 }"#).unwrap());
737
738        // no trailing commas
739        assert_none!(parse_json("{,}"));
740        assert_none!(parse_json(r#"{ "one":1, }"#));
741        assert_none!(parse_json(r#"{ "one":1, "two":2, "three":3 , }"#));
742        assert_none!(parse_json(
743            r#"{
744            "one":1,
745            "two": {
746                "nested":"object",
747                "with":"trailing comma",
748            },
749            "three":3
750        }"#
751        ));
752
753        // later identical keys replace earlier ones
754        assert_eq!(
755            Json::Object(HashMap::from([
756                ("one".into(), 100.into()),
757                ("two".into(), 2.into()),
758                ("three".into(), 3.into()),
759            ])),
760            parse_json(
761                r#"{
762                "one": 1,
763                "two": 2,
764                "one": 10,
765                "three": 3,
766                "one": 100
767            }"#
768            )
769            .unwrap()
770        );
771    }
772
773    #[test]
774    fn example_json_test_final_boss() {
775        let final_boss_input = r#"{
776            "nulls": null,
777            "bools": [true, false],
778            "ints": {
779                "zero": 0,
780                "positive": 56789,
781                "negative": -1234
782            },
783            "floats": {
784                "zeroes": [0.0, -0e1],
785                "positive": 12340.56789,
786                "negative": -98765.04321,
787                "exponents": [1e4, 1E+4, 1E-4]
788            },
789            "strings": "新しい日の誕生",
790            "funkier strings": "weird begins > \"\\\/\r\n\u03a3\f _\b \t< weird ends",
791            "nesting": [
792                {"child1": 1},
793                {"child2" :2},
794                {"child3" : 3},
795                {"children456":[4,5,6]}
796            ],
797            "matrix": [
798                [1, 2, 3],
799                [4, 5, 6],
800                [7, 8, 9]
801            ],
802            "strange object keys": {
803                "": "empty key",
804                "foo\u0000bar": "escaped null",
805                "\u041f\u043e\u043b\u0442\u043e\u0440\u0430 \u0417\u0435\u043c\u043b\u0435\u043a\u043e\u043f\u0430": "text -Полтора Землекопа- in unicode escapes"
806            }
807        }"#;
808        let final_boss_expected = Json::Object(HashMap::from([
809            ("nulls".into(), Json::Null),
810            ("bools".into(), Json::Array(vec![true.into(), false.into()])),
811            (
812                "ints".into(),
813                Json::Object(HashMap::from([
814                    ("zero".into(), 0.into()),
815                    ("positive".into(), 56789.into()),
816                    ("negative".into(), (-1234).into()),
817                ])),
818            ),
819            (
820                "floats".into(),
821                Json::Object(HashMap::from([
822                    (
823                        "zeroes".into(),
824                        Json::Array(vec![0.0.into(), (-0.0).into()]),
825                    ),
826                    ("positive".into(), 12340.56789.into()),
827                    ("negative".into(), (-98765.04321).into()),
828                    (
829                        "exponents".into(),
830                        Json::Array(vec![10000.0.into(), 10000.0.into(), 0.0001.into()]),
831                    ),
832                ])),
833            ),
834            ("strings".into(), "新しい日の誕生".into()),
835            (
836                "funkier strings".into(),
837                "weird begins > \"\\/\r\nΣ\u{000C} _\u{0008} \t< weird ends".into(),
838            ),
839            (
840                "nesting".into(),
841                Json::Array(vec![
842                    Json::Object(HashMap::from([("child1".into(), 1.into())])),
843                    Json::Object(HashMap::from([("child2".into(), 2.into())])),
844                    Json::Object(HashMap::from([("child3".into(), 3.into())])),
845                    Json::Object(HashMap::from([(
846                        "children456".into(),
847                        vec![4.into(), 5.into(), 6.into()].into(),
848                    )])),
849                ]),
850            ),
851            (
852                "matrix".into(),
853                Json::Array(vec![
854                    Json::Array(vec![1.into(), 2.into(), 3.into()]),
855                    Json::Array(vec![4.into(), 5.into(), 6.into()]),
856                    Json::Array(vec![7.into(), 8.into(), 9.into()]),
857                ]),
858            ),
859            (
860                "strange object keys".into(),
861                Json::Object(HashMap::from([
862                    ("".into(), "empty key".into()),
863                    ("foo\0bar".into(), "escaped null".into()),
864                    (
865                        "Полтора Землекопа".into(),
866                        "text -Полтора Землекопа- in unicode escapes".into(),
867                    ),
868                ])),
869            ),
870        ]));
871
872        assert_eq!(final_boss_expected, parse_json(final_boss_input).unwrap());
873    }
874}