1#[derive(Debug, Clone, PartialEq)]
28pub enum Json {
29 Null,
31 Bool(bool),
33 Int(i64),
35 Real(f64),
37 Text(String),
39 Array(Vec<Json>),
41 Object(Vec<(String, Json)>),
43}
44
45impl Json {
46 pub fn get(&self, key: &str) -> Option<&Json> {
50 match self {
51 Json::Object(pairs) => pairs
52 .iter()
53 .find(|(name, _)| name == key)
54 .map(|(_, value)| value),
55 _ => None,
56 }
57 }
58
59 pub fn text(&self) -> Option<&str> {
65 match self {
66 Json::Text(text) => Some(text),
67 _ => None,
68 }
69 }
70
71 pub fn integer(&self) -> Option<i64> {
73 match self {
74 Json::Int(number) => Some(*number),
75 Json::Real(number) if number.fract() == 0.0 => Some(*number as i64),
79 _ => None,
80 }
81 }
82
83 pub fn boolean(&self) -> Option<bool> {
85 match self {
86 Json::Bool(value) => Some(*value),
87 _ => None,
88 }
89 }
90
91 pub fn array(&self) -> Option<&[Json]> {
93 match self {
94 Json::Array(items) => Some(items),
95 _ => None,
96 }
97 }
98
99 pub fn write(&self) -> String {
101 let mut out = String::new();
102 self.write_into(&mut out);
103 out
104 }
105
106 fn write_into(&self, out: &mut String) {
110 match self {
111 Json::Null => out.push_str("null"),
112 Json::Bool(true) => out.push_str("true"),
113 Json::Bool(false) => out.push_str("false"),
114 Json::Int(number) => out.push_str(&number.to_string()),
115 Json::Real(number) => out.push_str(&real(*number)),
116 Json::Text(text) => {
117 out.push('"');
118 out.push_str(&escape(text));
119 out.push('"');
120 }
121 Json::Array(items) => {
122 out.push('[');
123 for (nth, item) in items.iter().enumerate() {
124 if nth > 0 {
125 out.push(',');
126 }
127 item.write_into(out);
128 }
129 out.push(']');
130 }
131 Json::Object(pairs) => {
132 out.push('{');
133 for (nth, (name, value)) in pairs.iter().enumerate() {
134 if nth > 0 {
135 out.push(',');
136 }
137 out.push('"');
138 out.push_str(&escape(name));
139 out.push_str("\":");
140 value.write_into(out);
141 }
142 out.push('}');
143 }
144 }
145 }
146
147 pub fn pretty(&self, depth: usize) -> String {
151 let pad = " ".repeat(depth + 1);
152 let close = " ".repeat(depth);
153 match self {
154 Json::Array(items) if !items.is_empty() => {
155 let inner: Vec<String> = items
156 .iter()
157 .map(|item| format!("{pad}{}", item.pretty(depth + 1)))
158 .collect();
159 format!("[\n{}\n{close}]", inner.join(",\n"))
160 }
161 Json::Object(pairs) if !pairs.is_empty() => {
162 let inner: Vec<String> = pairs
163 .iter()
164 .map(|(name, value)| {
165 format!("{pad}\"{}\": {}", escape(name), value.pretty(depth + 1))
166 })
167 .collect();
168 format!("{{\n{}\n{close}}}", inner.join(",\n"))
169 }
170 other => other.write(),
171 }
172 }
173}
174
175fn real(number: f64) -> String {
183 if number.is_finite() {
184 let rendered = format!("{number}");
185 if rendered.contains(['.', 'e', 'E']) {
188 rendered
189 } else {
190 format!("{rendered}.0")
191 }
192 } else {
193 "null".to_string()
194 }
195}
196
197pub fn escape(text: &str) -> String {
205 inillucent_base::json::escape(text)
206}
207
208pub fn object(pairs: Vec<(&str, Json)>) -> Json {
212 Json::Object(
213 pairs
214 .into_iter()
215 .map(|(name, value)| (name.to_string(), value))
216 .collect(),
217 )
218}
219
220pub fn text(text: impl Into<String>) -> Json {
224 Json::Text(text.into())
225}
226
227pub fn parse(source: &str) -> Result<Json, String> {
231 let characters: Vec<char> = source.chars().collect();
232 let mut reader = Reader {
233 characters: &characters,
234 at: 0,
235 depth: 0,
236 };
237 reader.skip_space();
238 let value = reader.value()?;
239 reader.skip_space();
240 if reader.at < reader.characters.len() {
241 return Err(format!("trailing input at character {}", reader.at));
242 }
243 Ok(value)
244}
245
246struct Reader<'a> {
248 characters: &'a [char],
250 at: usize,
252 depth: usize,
267}
268
269const MAX_DEPTH: usize = 1000;
276
277impl Reader<'_> {
278 fn peek(&self) -> Option<char> {
280 self.characters.get(self.at).copied()
281 }
282
283 fn next(&mut self) -> Option<char> {
285 let character = self.peek();
286 if character.is_some() {
287 self.at += 1;
288 }
289 character
290 }
291
292 fn skip_space(&mut self) {
294 while matches!(self.peek(), Some(character) if character.is_whitespace()) {
295 self.at += 1;
296 }
297 }
298
299 fn expect(&mut self, wanted: char) -> Result<(), String> {
303 match self.next() {
304 Some(character) if character == wanted => Ok(()),
305 Some(character) => Err(format!(
306 "expected '{wanted}' at character {}, found '{character}'",
307 self.at - 1
308 )),
309 None => Err(format!("expected '{wanted}', found end of input")),
310 }
311 }
312
313 fn descend(&mut self) -> Result<(), String> {
322 if self.depth >= MAX_DEPTH {
323 return Err(format!(
324 "nested more than {MAX_DEPTH} deep at character {}",
325 self.at
326 ));
327 }
328 self.depth = self.depth.saturating_add(1);
329 Ok(())
330 }
331
332 fn ascend(&mut self) {
334 self.depth = self.depth.saturating_sub(1);
335 }
336
337 fn value(&mut self) -> Result<Json, String> {
339 match self.peek() {
340 Some('{') => self.object(),
341 Some('[') => self.array(),
342 Some('"') => Ok(Json::Text(self.string()?)),
343 Some('t') => self.word("true", Json::Bool(true)),
344 Some('f') => self.word("false", Json::Bool(false)),
345 Some('n') => self.word("null", Json::Null),
346 Some(character) if character == '-' || character.is_ascii_digit() => self.number(),
347 Some(character) => Err(format!("unexpected '{character}' at character {}", self.at)),
348 None => Err("unexpected end of input".to_string()),
349 }
350 }
351
352 fn word(&mut self, word: &str, value: Json) -> Result<Json, String> {
357 for wanted in word.chars() {
358 self.expect(wanted)?;
359 }
360 Ok(value)
361 }
362
363 fn object(&mut self) -> Result<Json, String> {
365 self.descend()?;
366 let produced = self.object_body();
367 self.ascend();
368 produced
369 }
370
371 fn object_body(&mut self) -> Result<Json, String> {
373 self.expect('{')?;
374 let mut pairs = Vec::new();
375 self.skip_space();
376 if self.peek() == Some('}') {
377 self.at += 1;
378 return Ok(Json::Object(pairs));
379 }
380 loop {
381 self.skip_space();
382 let name = self.string()?;
383 self.skip_space();
384 self.expect(':')?;
385 self.skip_space();
386 let value = self.value()?;
387 pairs.push((name, value));
388 self.skip_space();
389 match self.next() {
390 Some(',') => continue,
391 Some('}') => return Ok(Json::Object(pairs)),
392 Some(character) => {
393 return Err(format!(
394 "expected ',' or '}}' at character {}, found '{character}'",
395 self.at - 1
396 ))
397 }
398 None => return Err("unterminated object".to_string()),
399 }
400 }
401 }
402
403 fn array(&mut self) -> Result<Json, String> {
405 self.descend()?;
406 let produced = self.array_body();
407 self.ascend();
408 produced
409 }
410
411 fn array_body(&mut self) -> Result<Json, String> {
413 self.expect('[')?;
414 let mut items = Vec::new();
415 self.skip_space();
416 if self.peek() == Some(']') {
417 self.at += 1;
418 return Ok(Json::Array(items));
419 }
420 loop {
421 self.skip_space();
422 items.push(self.value()?);
423 self.skip_space();
424 match self.next() {
425 Some(',') => continue,
426 Some(']') => return Ok(Json::Array(items)),
427 Some(character) => {
428 return Err(format!(
429 "expected ',' or ']' at character {}, found '{character}'",
430 self.at - 1
431 ))
432 }
433 None => return Err("unterminated array".to_string()),
434 }
435 }
436 }
437
438 fn string(&mut self) -> Result<String, String> {
440 self.expect('"')?;
441 let mut out = String::new();
442 loop {
443 match self.next() {
444 Some('"') => return Ok(out),
445 Some('\\') => match self.next() {
446 Some('"') => out.push('"'),
447 Some('\\') => out.push('\\'),
448 Some('/') => out.push('/'),
449 Some('n') => out.push('\n'),
450 Some('r') => out.push('\r'),
451 Some('t') => out.push('\t'),
452 Some('b') => out.push('\u{8}'),
453 Some('f') => out.push('\u{c}'),
454 Some('u') => out.push(self.escape_sequence()?),
455 Some(character) => {
456 return Err(format!("unknown escape '\\{character}'"));
457 }
458 None => return Err("unterminated escape".to_string()),
459 },
460 Some(character) => out.push(character),
461 None => return Err("unterminated string".to_string()),
462 }
463 }
464 }
465
466 fn escape_sequence(&mut self) -> Result<char, String> {
474 let first = self.hex4()?;
475 if (0xD800..0xDC00).contains(&first) {
476 self.expect('\\')?;
477 self.expect('u')?;
478 let second = self.hex4()?;
479 if !(0xDC00..0xE000).contains(&second) {
480 return Err("a high surrogate was not followed by a low one".to_string());
481 }
482 let combined = 0x10000 + ((first - 0xD800) << 10) + (second - 0xDC00);
483 return char::from_u32(combined).ok_or_else(|| "invalid surrogate pair".to_string());
484 }
485 char::from_u32(first).ok_or_else(|| format!("\\u{first:04x} is not a character"))
486 }
487
488 fn hex4(&mut self) -> Result<u32, String> {
490 let mut value = 0u32;
491 for _ in 0..4 {
492 match self.next().and_then(|character| character.to_digit(16)) {
493 Some(digit) => value = value * 16 + digit,
494 None => return Err("a \\u escape needs four hexadecimal digits".to_string()),
495 }
496 }
497 Ok(value)
498 }
499
500 fn number(&mut self) -> Result<Json, String> {
502 let start = self.at;
503 if self.peek() == Some('-') {
504 self.at += 1;
505 }
506 let mut fractional = false;
507 while let Some(character) = self.peek() {
508 match character {
509 '0'..='9' => self.at += 1,
510 '.' | 'e' | 'E' | '+' | '-' => {
511 fractional = true;
512 self.at += 1;
513 }
514 _ => break,
515 }
516 }
517 let literal: String = self
518 .characters
519 .get(start..self.at)
520 .unwrap_or_default()
521 .iter()
522 .collect();
523 if literal.is_empty() {
524 return Err(format!("expected a number at character {start}"));
525 }
526 if !fractional {
527 if let Ok(number) = literal.parse::<i64>() {
528 return Ok(Json::Int(number));
529 }
530 }
531 literal
532 .parse::<f64>()
533 .map(Json::Real)
534 .map_err(|_| format!("'{literal}' is not a number"))
535 }
536}
537
538#[cfg(test)]
539mod tests {
540 use super::*;
541
542 #[test]
544 fn scalars_round_trip() {
545 assert_eq!(parse("null"), Ok(Json::Null));
546 assert_eq!(parse("true"), Ok(Json::Bool(true)));
547 assert_eq!(parse("-12"), Ok(Json::Int(-12)));
548 assert_eq!(parse("1.5"), Ok(Json::Real(1.5)));
549 assert_eq!(parse("\"hi\""), Ok(text("hi")));
550 }
551
552 #[test]
554 fn an_integer_is_not_a_double() {
555 assert_eq!(parse("9007199254740993"), Ok(Json::Int(9007199254740993)));
556 assert_eq!(Json::Int(7).write(), "7");
557 assert_eq!(Json::Real(7.0).write(), "7.0");
558 }
559
560 #[test]
563 fn a_whole_double_reads_as_an_integer() {
564 assert_eq!(Json::Real(5.0).integer(), Some(5));
565 assert_eq!(Json::Real(5.5).integer(), None);
566 }
567
568 #[test]
570 fn objects_keep_their_order() {
571 let value = object(vec![("b", Json::Int(1)), ("a", Json::Int(2))]);
572 assert_eq!(value.write(), "{\"b\":1,\"a\":2}");
573 }
574
575 #[test]
577 fn escapes_round_trip() {
578 let original = "a\"b\\c\nd\te\u{1}f";
579 let written = text(original).write();
580 assert_eq!(parse(&written), Ok(text(original)));
581 assert!(written.contains("\\u0001"));
582 }
583
584 #[test]
586 fn a_surrogate_pair_becomes_one_character() {
587 assert_eq!(parse("\"\\ud83d\\ude00\""), Ok(text("\u{1f600}")));
588 }
589
590 #[test]
592 fn nesting_reads_back() {
593 let value = parse("{\"a\": [1, {\"b\": null}], \"c\": \"d\"}").unwrap_or(Json::Null);
594 assert_eq!(value.get("c").and_then(Json::text), Some("d"));
595 let inner = value.get("a").and_then(Json::array).unwrap_or_default();
596 assert_eq!(inner.len(), 2);
597 }
598
599 #[test]
601 fn a_bad_document_is_refused() {
602 assert!(parse("{\"a\": }").is_err());
603 assert!(parse("[1, 2").is_err());
604 assert!(parse("nul").is_err());
605 assert!(parse("{} {}").is_err());
606 }
607
608 #[test]
610 fn a_non_finite_double_becomes_null() {
611 assert_eq!(Json::Real(f64::NAN).write(), "null");
612 assert_eq!(Json::Real(f64::INFINITY).write(), "null");
613 }
614
615 #[test]
617 fn whitespace_is_ignored() {
618 assert_eq!(
619 parse(" {\n \"a\" : [ 1 , 2 ]\n} "),
620 parse("{\"a\":[1,2]}")
621 );
622 }
623}
624
625#[cfg(test)]
626mod fuzz_seeded {
627 const CASES: usize = 20_000;
629
630 const ALPHABET: &[u8] = b"{}[]\",:0123456789.-+eEtruefalsnl /\t\n\r\0\xff";
636
637 fn next(state: &mut u64) -> u64 {
641 *state ^= *state << 13;
642 *state ^= *state >> 7;
643 *state ^= *state << 17;
644 *state
645 }
646
647 #[test]
654 fn the_request_parser_never_panics_on_arbitrary_text() {
655 let mut state = 0x1932_0003_u64;
656 let mut parsed = 0usize;
657 for _ in 0..CASES {
658 let length = (next(&mut state) % 64) as usize;
659 let bytes: Vec<u8> = (0..length)
660 .map(|_| {
661 let at = (next(&mut state) as usize) % ALPHABET.len();
662 ALPHABET.get(at).copied().unwrap_or(b'?')
663 })
664 .collect();
665 let text = String::from_utf8_lossy(&bytes).into_owned();
666 parsed += usize::from(super::parse(&text).is_ok());
667 }
668 assert!(parsed <= CASES);
669 }
670}