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#[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#[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
71fn 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 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 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 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 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
223fn 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
230fn 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 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 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 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
294fn 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
312fn 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
323fn 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
353fn parse_json(input_string: &str) -> Option<Json> {
355 let lex = lex_json();
356 let tokens = lex.parse(input_string).ok()?.1;
358 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 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 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 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 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"; assert_none!(parse_json(i64max_plus1_str));
488 assert_none!(parse_json(
489 "9999999999999999999999999999999999999999999999999"
490 ));
491
492 }
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 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 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 assert_none!(parse_json("\"\0\""));
527 assert_none!(parse_json("\"\n\""));
528 assert_none!(parse_json("\"\u{1B}\""));
529
530 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 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 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 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 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 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 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}