1use core::fmt::Write as _;
57
58use yo_common::{Code, Error, Result};
59
60use crate::build::Builder;
61use crate::head::{DEPTH_MAX, Kind};
62use crate::read::Value;
63
64pub fn from_json(text: &[u8]) -> Result<Vec<u8>> {
70 let mut b = Builder::new();
71 b.json(text)?;
72 Ok(b.finish()?.to_vec())
73}
74
75impl Builder {
76 pub fn json(&mut self, text: &[u8]) -> Result<()> {
88 if core::str::from_utf8(text).is_err() {
92 return Err(Error::new(Code::Invalid, "the JSON text is not UTF-8"));
93 }
94 let mut r = Reader {
95 text,
96 at: 0,
97 scratch: Vec::new(),
98 };
99 r.space();
100 r.value(self)?;
101 r.space();
102 if r.at < text.len() {
103 return Err(r.bad("more text after the value the document is"));
104 }
105 Ok(())
106 }
107}
108
109#[derive(Debug, Clone, Copy, Default)]
116pub struct Format<'a> {
117 pub indent: &'a [u8],
119 pub newline: &'a [u8],
121 pub space: &'a [u8],
123}
124
125impl Format<'_> {
126 #[must_use]
133 pub fn is_plain(&self) -> bool {
134 self.indent.is_empty() && self.newline.is_empty() && self.space.is_empty()
135 }
136}
137
138impl Value<'_> {
139 pub fn to_json(&self) -> Result<Vec<u8>> {
141 let mut out = Vec::new();
142 self.write_json(&mut out)?;
143 Ok(out)
144 }
145
146 pub fn write_json(&self, out: &mut Vec<u8>) -> Result<()> {
151 write_value(self, &Format::default(), out, 0)
152 }
153
154 pub fn write_json_with(&self, f: &Format<'_>, out: &mut Vec<u8>) -> Result<()> {
156 write_value(self, f, out, 0)
157 }
158
159 pub fn write_json_at(&self, f: &Format<'_>, out: &mut Vec<u8>, depth: usize) -> Result<()> {
167 write_value(self, f, out, depth)
168 }
169}
170
171struct Reader<'a> {
175 text: &'a [u8],
176 at: usize,
177 scratch: Vec<u8>,
181}
182
183enum Str {
190 Plain(usize, usize),
191 Escaped,
192}
193
194impl<'a> Reader<'a> {
195 fn space(&mut self) {
197 while let Some(&c) = self.text.get(self.at) {
198 if c == b' ' || c == b'\t' || c == b'\n' || c == b'\r' {
199 self.at += 1;
200 } else {
201 break;
202 }
203 }
204 }
205
206 fn peek(&self) -> Option<u8> {
207 self.text.get(self.at).copied()
208 }
209
210 fn word(&mut self, word: &[u8]) -> bool {
212 if self.text[self.at..].starts_with(word) {
213 self.at += word.len();
214 true
215 } else {
216 false
217 }
218 }
219
220 fn value(&mut self, b: &mut Builder) -> Result<()> {
226 match self.peek() {
227 None => Err(self.bad("the text ends where a value should be")),
228 Some(b'n') if self.word(b"null") => b.null(),
229 Some(b't') if self.word(b"true") => b.bool(true),
230 Some(b'f') if self.word(b"false") => b.bool(false),
231 Some(b'"') => {
232 let s = self.string()?;
233 let bytes = self.bytes_of(&s);
234 b.text_bytes(bytes)
235 }
236 Some(b'[') => self.array(b),
237 Some(b'{') => self.object(b),
238 Some(c) if c == b'-' || c.is_ascii_digit() => self.number(b),
239 Some(_) => Err(self.bad("this is not the start of a value")),
240 }
241 }
242
243 fn array(&mut self, b: &mut Builder) -> Result<()> {
244 self.at += 1;
245 b.begin_array()?;
246 self.space();
247 if self.peek() == Some(b']') {
248 self.at += 1;
249 return b.end_array();
250 }
251 loop {
252 self.space();
253 self.value(b)?;
254 self.space();
255 match self.peek() {
256 Some(b',') => self.at += 1,
257 Some(b']') => {
258 self.at += 1;
259 return b.end_array();
260 }
261 _ => return Err(self.bad("an array element is followed by `,` or by `]`")),
262 }
263 }
264 }
265
266 fn object(&mut self, b: &mut Builder) -> Result<()> {
267 self.at += 1;
268 b.begin_object()?;
269 self.space();
270 if self.peek() == Some(b'}') {
271 self.at += 1;
272 return b.end_object();
273 }
274 loop {
275 self.space();
276 if self.peek() != Some(b'"') {
277 return Err(self.bad("an object key is a string"));
278 }
279 let s = self.string()?;
280 b.key(self.bytes_of(&s))?;
281 self.space();
282 if self.peek() != Some(b':') {
283 return Err(self.bad("an object key is followed by `:`"));
284 }
285 self.at += 1;
286 self.space();
287 self.value(b)?;
288 self.space();
289 match self.peek() {
290 Some(b',') => self.at += 1,
291 Some(b'}') => {
292 self.at += 1;
293 return b.end_object();
294 }
295 _ => return Err(self.bad("an object member is followed by `,` or by `}`")),
296 }
297 }
298 }
299
300 fn bytes_of(&self, s: &Str) -> &[u8] {
302 match *s {
303 Str::Plain(from, to) => &self.text[from..to],
304 Str::Escaped => &self.scratch,
305 }
306 }
307
308 fn string(&mut self) -> Result<Str> {
310 self.at += 1;
311 let from = self.at;
312 while let Some(c) = self.peek() {
315 match c {
316 b'"' => {
317 let to = self.at;
318 self.at += 1;
319 return Ok(Str::Plain(from, to));
320 }
321 b'\\' => break,
322 0..=0x1f => return Err(self.bad("a control byte inside a string")),
326 _ => self.at += 1,
327 }
328 }
329
330 self.scratch.clear();
331 self.scratch.extend_from_slice(&self.text[from..self.at]);
332 loop {
333 let Some(c) = self.peek() else {
334 return Err(self.bad("the text ends inside a string"));
335 };
336 self.at += 1;
337 match c {
338 b'"' => return Ok(Str::Escaped),
339 0..=0x1f => return Err(self.bad("a control byte inside a string")),
340 b'\\' => self.escape()?,
341 _ => self.scratch.push(c),
342 }
343 }
344 }
345
346 fn escape(&mut self) -> Result<()> {
348 let Some(c) = self.peek() else {
349 return Err(self.bad("the text ends inside an escape"));
350 };
351 self.at += 1;
352 let plain = match c {
353 b'"' => b'"',
354 b'\\' => b'\\',
355 b'/' => b'/',
356 b'b' => 0x08,
357 b'f' => 0x0c,
358 b'n' => b'\n',
359 b'r' => b'\r',
360 b't' => b'\t',
361 b'u' => return self.unicode(),
362 _ => return Err(self.bad("this is not an escape JSON has")),
363 };
364 self.scratch.push(plain);
365 Ok(())
366 }
367
368 fn unicode(&mut self) -> Result<()> {
370 let first = self.hex4()?;
371 let ch = if (0xd800..0xdc00).contains(&first) {
372 if !(self.peek() == Some(b'\\') && self.text.get(self.at + 1) == Some(&b'u')) {
377 return Err(self.bad("a high surrogate with no low surrogate after it"));
378 }
379 self.at += 2;
380 let second = self.hex4()?;
381 if !(0xdc00..0xe000).contains(&second) {
382 return Err(
383 self.bad("a high surrogate followed by something that is not a low one")
384 );
385 }
386 0x10000 + ((first - 0xd800) << 10) + (second - 0xdc00)
387 } else if (0xdc00..0xe000).contains(&first) {
388 return Err(self.bad("a low surrogate with no high surrogate before it"));
389 } else {
390 first
391 };
392 let ch = char::from_u32(ch).ok_or_else(|| self.bad("an escape that is not a character"))?;
393 let mut buf = [0u8; 4];
394 self.scratch
395 .extend_from_slice(ch.encode_utf8(&mut buf).as_bytes());
396 Ok(())
397 }
398
399 fn hex4(&mut self) -> Result<u32> {
401 let Some(digits) = self.text.get(self.at..self.at + 4) else {
402 return Err(self.bad("an escape with fewer than four hex digits"));
403 };
404 let mut v = 0u32;
405 for &d in digits {
406 let n = match d {
407 b'0'..=b'9' => u32::from(d - b'0'),
408 b'a'..=b'f' => u32::from(d - b'a') + 10,
409 b'A'..=b'F' => u32::from(d - b'A') + 10,
410 _ => return Err(self.bad("an escape with something that is not a hex digit")),
411 };
412 v = v * 16 + n;
413 }
414 self.at += 4;
415 Ok(v)
416 }
417
418 fn number(&mut self, b: &mut Builder) -> Result<()> {
422 let from = self.at;
423 if self.peek() == Some(b'-') {
424 self.at += 1;
425 }
426 match self.peek() {
427 Some(b'0') => self.at += 1,
431 Some(c) if c.is_ascii_digit() => self.digits(),
432 _ => return Err(self.bad("a number with no digits in it")),
433 }
434 let mut whole = true;
435 if self.peek() == Some(b'.') {
436 self.at += 1;
437 if !self.peek().is_some_and(|c| c.is_ascii_digit()) {
438 return Err(self.bad("a decimal point with no digits after it"));
439 }
440 self.digits();
441 whole = false;
442 }
443 if matches!(self.peek(), Some(b'e' | b'E')) {
444 self.at += 1;
445 if matches!(self.peek(), Some(b'+' | b'-')) {
446 self.at += 1;
447 }
448 if !self.peek().is_some_and(|c| c.is_ascii_digit()) {
449 return Err(self.bad("an exponent with no digits in it"));
450 }
451 self.digits();
452 whole = false;
453 }
454
455 let text = core::str::from_utf8(&self.text[from..self.at])
456 .expect("a number is the ASCII this function just walked over");
457 if whole
464 && text != "-0"
465 && let Ok(i) = text.parse::<i64>()
466 {
467 return b.int(i);
468 }
469 let f: f64 = text
470 .parse()
471 .map_err(|_| self.bad("a number that does not fit in a double"))?;
472 b.float(f)
473 }
474
475 fn digits(&mut self) {
476 while self.peek().is_some_and(|c| c.is_ascii_digit()) {
477 self.at += 1;
478 }
479 }
480
481 fn bad(&self, what: &str) -> Error {
484 Error::fmt(
485 Code::Invalid,
486 format_args!("{what}, at byte {} of the JSON text", self.at),
487 )
488 }
489}
490
491fn write_value(v: &Value<'_>, f: &Format<'_>, out: &mut Vec<u8>, depth: usize) -> Result<()> {
494 match v.kind() {
495 Kind::Null => out.extend_from_slice(b"null"),
496 Kind::Bool => out.extend_from_slice(if v.as_bool() == Some(true) {
497 b"true".as_slice()
498 } else {
499 b"false".as_slice()
500 }),
501 Kind::Int => {
502 let i = v.as_int().ok_or_else(unreadable)?;
503 write!(Sink(out), "{i}").expect("a Vec never fails a write");
504 }
505 Kind::Float => write_float(v.as_float().ok_or_else(unreadable)?, out)?,
506 Kind::Text => write_string(v.text_bytes().ok_or_else(unreadable)?, out),
507 Kind::Array => {
508 deeper(depth)?;
509 let laid_out = !f.is_plain() && !v.is_empty();
510 out.push(b'[');
511 for (i, e) in v.iter().enumerate() {
512 if i > 0 {
513 out.push(b',');
514 }
515 if laid_out {
516 line(f, out, depth + 1);
517 }
518 write_value(&e, f, out, depth + 1)?;
519 }
520 if laid_out {
521 line(f, out, depth);
522 }
523 out.push(b']');
524 }
525 Kind::Object => {
526 deeper(depth)?;
527 if v.is_interned() {
528 return Err(Error::new(
529 Code::Invalid,
530 "an object whose keys are interned needs the collection's key table to be written as text",
531 ));
532 }
533 let laid_out = !f.is_plain() && !v.is_empty();
534 out.push(b'{');
535 for (i, (key, e)) in v.members().enumerate() {
536 if i > 0 {
537 out.push(b',');
538 }
539 if laid_out {
540 line(f, out, depth + 1);
541 }
542 write_string(key, out);
543 out.push(b':');
544 out.extend_from_slice(f.space);
545 write_value(&e, f, out, depth + 1)?;
546 }
547 if laid_out {
548 line(f, out, depth);
549 }
550 out.push(b'}');
551 }
552 }
553 Ok(())
554}
555
556fn line(f: &Format<'_>, out: &mut Vec<u8>, depth: usize) {
558 out.extend_from_slice(f.newline);
559 for _ in 0..depth {
560 out.extend_from_slice(f.indent);
561 }
562}
563
564fn deeper(depth: usize) -> Result<()> {
568 if depth >= DEPTH_MAX {
569 return Err(Error::fmt(
570 Code::Corrupt,
571 format_args!("the document nests past {DEPTH_MAX} levels"),
572 ));
573 }
574 Ok(())
575}
576
577pub(crate) fn write_float(f: f64, out: &mut Vec<u8>) -> Result<()> {
578 if !f.is_finite() {
579 return Err(Error::new(
580 Code::Invalid,
581 "JSON has no way to write an infinity or a NaN",
582 ));
583 }
584 let mag = f.abs();
589 if mag != 0.0 && !(1e-5..1e16).contains(&mag) {
590 write!(Sink(out), "{f:e}").expect("a Vec never fails a write");
591 return Ok(());
592 }
593 let from = out.len();
594 write!(Sink(out), "{f}").expect("a Vec never fails a write");
595 if !out[from..].iter().any(|&c| matches!(c, b'.' | b'e' | b'E')) {
599 out.extend_from_slice(b".0");
600 }
601 Ok(())
602}
603
604pub(crate) fn write_int(i: i64, out: &mut Vec<u8>) {
606 write!(Sink(out), "{i}").expect("a Vec never fails a write");
607}
608
609pub fn write_resp_float(f: f64, out: &mut Vec<u8>) {
625 if f.is_nan() {
626 out.extend_from_slice(b"nan");
627 return;
628 }
629 if f.is_infinite() {
630 out.extend_from_slice(if f < 0.0 { b"-inf" } else { b"inf" });
631 return;
632 }
633 if f == 0.0 {
634 if f.is_sign_negative() {
635 out.push(b'-');
636 }
637 out.push(b'0');
638 return;
639 }
640 #[expect(clippy::cast_precision_loss, reason = "a bound and not a round trip")]
644 let half = (i64::MAX / 2) as f64;
645 if f.abs() <= half {
646 #[expect(clippy::cast_possible_truncation, reason = "bounded on the line above")]
647 let whole = f as i64;
648 #[expect(clippy::cast_precision_loss, reason = "the test is that it was exact")]
649 let exact = whole as f64 == f;
650 if exact {
651 write_int(whole, out);
652 return;
653 }
654 }
655 let from = out.len();
659 write!(Sink(out), "{f:e}").expect("a Vec never fails a write");
660 let mut digits = [0u8; 17];
661 let mut count = 0;
662 let mut at = from;
663 let neg = out[at] == b'-';
664 if neg {
665 at += 1;
666 }
667 while at < out.len() && out[at] != b'e' {
668 if out[at] != b'.' {
669 digits[count] = out[at];
670 count += 1;
671 }
672 at += 1;
673 }
674 let exp: i32 = core::str::from_utf8(&out[at + 1..])
675 .expect("digits are UTF-8")
676 .parse()
677 .expect("Rust wrote the exponent");
678 out.truncate(from);
679 let digits = &digits[..count];
680 let len = i32::try_from(count).expect("at most seventeen");
681 let k = exp - (len - 1);
684 if neg {
685 out.push(b'-');
686 }
687 if k >= 0 && exp.abs() < len + 7 {
688 out.extend_from_slice(digits);
690 out.resize(
691 out.len() + usize::try_from(k).expect("checked to be positive"),
692 b'0',
693 );
694 } else if k < 0 && (k > -7 || exp.abs() < 4) {
695 let point = len + k;
697 if point <= 0 {
698 out.extend_from_slice(b"0.");
699 out.resize(
700 out.len() + usize::try_from(-point).expect("checked to be negative"),
701 b'0',
702 );
703 out.extend_from_slice(digits);
704 } else {
705 let point = usize::try_from(point).expect("checked to be positive");
706 out.extend_from_slice(&digits[..point]);
707 out.push(b'.');
708 out.extend_from_slice(&digits[point..]);
709 }
710 } else {
711 out.push(digits[0]);
712 if count > 1 {
713 out.push(b'.');
714 out.extend_from_slice(&digits[1..]);
715 }
716 out.push(b'e');
717 out.push(if exp < 0 { b'-' } else { b'+' });
718 write_int(i64::from(exp.abs()), out);
719 }
720}
721
722pub(crate) fn write_string(s: &[u8], out: &mut Vec<u8>) {
730 out.push(b'"');
731 for &c in s {
732 match c {
733 b'"' => out.extend_from_slice(b"\\\""),
734 b'\\' => out.extend_from_slice(b"\\\\"),
735 0x08 => out.extend_from_slice(b"\\b"),
736 0x0c => out.extend_from_slice(b"\\f"),
737 b'\n' => out.extend_from_slice(b"\\n"),
738 b'\r' => out.extend_from_slice(b"\\r"),
739 b'\t' => out.extend_from_slice(b"\\t"),
740 0..=0x1f => write!(Sink(out), "\\u{c:04x}").expect("a Vec never fails a write"),
741 _ => out.push(c),
742 }
743 }
744 out.push(b'"');
745}
746
747struct Sink<'a>(&'a mut Vec<u8>);
750
751impl core::fmt::Write for Sink<'_> {
752 fn write_str(&mut self, s: &str) -> core::fmt::Result {
753 self.0.extend_from_slice(s.as_bytes());
754 Ok(())
755 }
756}
757
758fn unreadable() -> Error {
759 Error::new(Code::Corrupt, "a value whose header and payload disagree")
760}
761
762#[cfg(test)]
763mod tests {
764 use super::*;
765 use yo_common::Rng;
766
767 fn round(text: &str) -> String {
769 let bytes = from_json(text.as_bytes()).expect("the text parses");
770 let v = Value::new(&bytes).expect("readable");
771 assert!(
772 v.validate(),
773 "the encoding this produced does not check out"
774 );
775 String::from_utf8(v.to_json().expect("writable")).expect("UTF-8")
776 }
777
778 fn why(text: &str) -> String {
779 from_json(text.as_bytes())
780 .expect_err("this should not parse")
781 .message()
782 .to_string()
783 }
784
785 fn laid_out(text: &str, f: &Format<'_>) -> String {
787 let bytes = from_json(text.as_bytes()).expect("the text parses");
788 let v = Value::new(&bytes).expect("readable");
789 let mut out = Vec::new();
790 v.write_json_with(f, &mut out).expect("writable");
791 String::from_utf8(out).expect("UTF-8")
792 }
793
794 #[test]
795 fn a_document_is_laid_out_the_way_json_get_asks_for() {
796 let f = Format {
797 indent: b" ",
798 newline: b"\n",
799 space: b" ",
800 };
801 assert_eq!(
802 laid_out(r#"{"a":1,"bb":[2,3]}"#, &f),
803 "{\n \"a\": 1,\n \"bb\": [\n 2,\n 3\n ]\n}"
804 );
805 assert_eq!(
808 laid_out(r#"{"a":{},"bb":[]}"#, &f),
809 "{\n \"a\": {},\n \"bb\": []\n}"
810 );
811 assert_eq!(laid_out("1.5", &f), "1.5");
813 assert_eq!(
815 laid_out(r#"{"a":1,"bb":[2,3]}"#, &Format::default()),
816 round(r#"{"a":1,"bb":[2,3]}"#)
817 );
818 let only_space = Format {
820 space: b" ",
821 ..Format::default()
822 };
823 assert_eq!(
824 laid_out(r#"{"a":1,"bb":2}"#, &only_space),
825 r#"{"a": 1,"bb": 2}"#
826 );
827 }
828
829 #[test]
830 fn a_document_comes_back_as_the_text_it_went_in_as() {
831 assert_eq!(round("null"), "null");
832 assert_eq!(round("true"), "true");
833 assert_eq!(round("false"), "false");
834 assert_eq!(round("0"), "0");
835 assert_eq!(round("-17"), "-17");
836 assert_eq!(round(r#""hello""#), r#""hello""#);
837 assert_eq!(round("[]"), "[]");
838 assert_eq!(round("{}"), "{}");
839 assert_eq!(round(r#"[1,[2,[3]]]"#), "[1,[2,[3]]]");
840 assert_eq!(round(r#"{"a":{"b":[1,2,3]}}"#), r#"{"a":{"b":[1,2,3]}}"#);
841 }
842
843 #[test]
844 fn whitespace_is_allowed_where_json_allows_it_and_is_not_kept() {
845 assert_eq!(round(" \t\r\n [ 1 , 2 ] \n"), "[1,2]");
846 assert_eq!(round("{ \"a\" : 1 , \"b\" : 2 }"), r#"{"a":1,"b":2}"#);
847 }
848
849 #[test]
850 fn a_whole_number_stays_whole_and_the_rest_do_not() {
851 assert_eq!(round("1"), "1");
852 assert_eq!(round("1.0"), "1.0");
853 assert_eq!(round("1e2"), "100.0");
854 assert_eq!(round("-0.5"), "-0.5");
855 assert_eq!(round("9223372036854775807"), "9223372036854775807");
856 assert_eq!(round("9223372036854775808"), "9.223372036854776e18");
860 assert_eq!(round("1e15"), "1000000000000000.0");
861 assert_eq!(round("1e16"), "1e16");
862 assert_eq!(round("1e-5"), "0.00001");
863 assert_eq!(round("1e-6"), "1e-6");
864 assert_eq!(round("-1e17"), "-1e17");
865 assert_eq!(round("5e-324"), "5e-324");
866 let bytes = from_json(b"1").expect("parses");
867 assert_eq!(Value::new(&bytes).expect("readable").kind(), Kind::Int);
868 let bytes = from_json(b"1.0").expect("parses");
869 assert_eq!(Value::new(&bytes).expect("readable").kind(), Kind::Float);
870 assert_eq!(round("-0"), "-0.0");
873 assert_eq!(round("0"), "0");
874 let bytes = from_json(b"-0").expect("parses");
875 assert_eq!(Value::new(&bytes).expect("readable").kind(), Kind::Float);
876 }
877
878 #[test]
879 fn json_resp_writes_a_double_the_way_redis_writes_one_and_not_the_way_json_does() {
880 fn resp(f: f64) -> String {
881 let mut out = Vec::new();
882 write_resp_float(f, &mut out);
883 String::from_utf8(out).expect("digits are UTF-8")
884 }
885
886 assert_eq!(resp(1.0), "1");
890 assert_eq!(resp(1e16), "10000000000000000");
891 assert_eq!(resp(4e18), "4000000000000000000");
892 assert_eq!(resp(-4e18), "-4000000000000000000");
893 assert_eq!(resp(5e18), "5e+18");
894 assert_eq!(resp(1.2345678901234567e19), "12345678901234567000");
897 assert_eq!(resp(1e19), "1e+19");
898 assert_eq!(resp(1.5e19), "1.5e+19");
899 assert_eq!(resp(1e300), "1e+300");
900 assert_eq!(resp(f64::MAX), "1.7976931348623157e+308");
901 assert_eq!(resp(2.5), "2.5");
904 assert_eq!(resp(0.1), "0.1");
905 assert_eq!(resp(123.456), "123.456");
906 assert_eq!(resp(1e-6), "0.000001");
907 assert_eq!(resp(1e-7), "1e-7");
908 assert_eq!(resp(5e-324), "5e-324");
909 assert_eq!(resp(-1.5), "-1.5");
910 assert_eq!(resp(0.0), "0");
913 assert_eq!(resp(-0.0), "-0");
914 }
915
916 #[test]
917 fn an_escape_is_read_and_only_written_back_when_it_has_to_be() {
918 assert_eq!(round(r#""a\"b""#), r#""a\"b""#);
919 assert_eq!(round(r#""a\\b""#), r#""a\\b""#);
920 assert_eq!(round(r#""a\nb""#), r#""a\nb""#);
921 assert_eq!(round(r#""a\tb""#), r#""a\tb""#);
922 assert_eq!(round(r#""a b""#), r#""a b""#);
923 assert_eq!(round(r#""a\/b""#), r#""a/b""#);
926 assert_eq!(round(r#""é""#), "\"\u{e9}\"");
929 assert_eq!(round(r#""😀""#), "\"\u{1f600}\"");
930 assert_eq!(round("\"caf\u{e9}\""), "\"caf\u{e9}\"");
931 }
932
933 #[test]
934 fn a_string_with_no_escapes_in_it_is_not_copied_through_the_scratch() {
935 let mut r = Reader {
936 text: br#""plain" "esc\n""#,
937 at: 0,
938 scratch: Vec::new(),
939 };
940 assert!(matches!(r.string().expect("parses"), Str::Plain(1, 6)));
941 r.space();
942 assert!(matches!(r.string().expect("parses"), Str::Escaped));
943 assert_eq!(r.scratch, b"esc\n");
944 }
945
946 #[test]
947 fn an_object_comes_back_in_key_order_and_the_last_of_a_repeated_key_wins() {
948 assert_eq!(round(r#"{"b":1,"a":2}"#), r#"{"a":2,"b":1}"#);
949 assert_eq!(round(r#"{"a":1,"a":2}"#), r#"{"a":2}"#);
950 }
951
952 #[test]
953 fn the_parser_refuses_what_is_not_json() {
954 assert!(why("").contains("ends where a value should be"));
955 assert!(why("[1,]").contains("not the start of a value"));
956 assert!(why("[1 2]").contains("`,` or by `]`"));
957 assert!(why("{a:1}").contains("key is a string"));
958 assert!(why(r#"{"a" 1}"#).contains("followed by `:`"));
959 assert!(why(r#"{"a":1,}"#).contains("key is a string"));
960 assert!(why("'a'").contains("not the start of a value"));
961 assert!(why("01").contains("more text after the value"));
962 assert!(why("+1").contains("not the start of a value"));
963 assert!(why("1.").contains("no digits after it"));
964 assert!(why(".5").contains("not the start of a value"));
965 assert!(why("1e").contains("exponent with no digits"));
966 assert!(why("NaN").contains("not the start of a value"));
967 assert!(why("Infinity").contains("not the start of a value"));
968 assert!(why("nul").contains("not the start of a value"));
969 assert!(why("1 2").contains("more text after the value"));
970 assert!(why("// a comment\n1").contains("not the start of a value"));
971 assert!(why("\"a\nb\"").contains("control byte inside a string"));
972 assert!(why(r#""a"#).contains("ends inside a string"));
973 assert!(why(r#""\x""#).contains("not an escape JSON has"));
974 assert!(why(r#""\u00"#).contains("fewer than four hex digits"));
975 assert!(why(r#""\uzzzz""#).contains("not a hex digit"));
976 assert!(why(r#""\ud83d""#).contains("no low surrogate after it"));
977 assert!(why(r#""\ude00""#).contains("no high surrogate before it"));
978 assert!(why(r#""\ud83da""#).contains("no low surrogate after it"));
979 assert!(why(r#""\ud83d\u0041""#).contains("something that is not a low one"));
980 assert!(why("[").contains("ends where a value should be"));
981 assert!(why("{").contains("key is a string"));
982 }
983
984 #[test]
985 fn an_error_says_where_it_was() {
986 assert!(why("[1, 2, x]").contains("at byte 7"));
987 }
988
989 #[test]
1000 fn a_document_survives_being_written_out_and_read_back() {
1001 let mut rng = Rng::new(0x0d0c);
1002 let rounds = if cfg!(miri) { 60 } else { 500 };
1006 for _ in 0..rounds {
1007 let mut b = Builder::new();
1008 grow(&mut b, &mut rng, 0);
1009 let first = b.finish().expect("finished").to_vec();
1010
1011 let v = Value::new(&first).expect("readable");
1012 let text = v.to_json().expect("writable");
1013 let again = from_json(&text)
1014 .unwrap_or_else(|e| panic!("{}: {}", String::from_utf8_lossy(&text), e.message()));
1015 assert_eq!(
1016 first,
1017 again,
1018 "{} did not come back as itself",
1019 String::from_utf8_lossy(&text)
1020 );
1021 }
1022 }
1023
1024 fn grow(b: &mut Builder, rng: &mut Rng, depth: usize) {
1032 const CHARS: [char; 12] = [
1033 'a',
1034 'z',
1035 '"',
1036 '\\',
1037 '\n',
1038 '\t',
1039 '\u{0}',
1040 '\u{1f}',
1041 '/',
1042 '\u{e9}',
1043 '\u{4e2d}',
1044 '\u{1f600}',
1045 ];
1046 let pick = rng.next_u64() % if depth >= 4 { 6 } else { 8 };
1047 match pick {
1048 0 => b.null().expect("value"),
1049 1 => b.bool(rng.next_u64() & 1 == 0).expect("value"),
1050 2 => b.int(rng.next_u64() as i64).expect("value"),
1051 3 => b
1052 .float(f64::from_bits(rng.next_u64()).clamp(-1e300, 1e300))
1053 .expect("value"),
1054 4 => b.int(i64::from(rng.next_u64() as u8) - 128).expect("value"),
1055 5 => {
1056 let n = rng.next_u64() as usize % 8;
1057 let s: String = (0..n)
1058 .map(|_| CHARS[rng.next_u64() as usize % CHARS.len()])
1059 .collect();
1060 b.text(&s).expect("value");
1061 }
1062 6 => {
1063 b.begin_array().expect("open");
1064 for _ in 0..rng.next_u64() % 4 {
1065 grow(b, rng, depth + 1);
1066 }
1067 b.end_array().expect("close");
1068 }
1069 _ => {
1070 b.begin_object().expect("open");
1071 for i in 0..rng.next_u64() % 4 {
1072 let key = "k".repeat(1 + i as usize % 3) + &i.to_string();
1075 b.key(key.as_bytes()).expect("key");
1076 grow(b, rng, depth + 1);
1077 }
1078 b.end_object().expect("close");
1079 }
1080 }
1081 }
1082
1083 #[test]
1084 fn text_that_is_not_utf8_is_refused_before_anything_is_parsed() {
1085 let e = from_json(&[b'"', 0xff, b'"']).expect_err("not UTF-8");
1086 assert!(e.message().contains("not UTF-8"));
1087 }
1088
1089 #[test]
1095 #[cfg_attr(miri, ignore = "the depth limit is the claim and it is 128 levels")]
1096 fn a_document_deeper_than_the_limit_is_refused_rather_than_recursed_into() {
1097 let deep = format!("{}1{}", "[".repeat(200), "]".repeat(200));
1098 assert!(why(&deep).contains("nests at most"));
1099 let ok = format!("{}1{}", "[".repeat(DEPTH_MAX), "]".repeat(DEPTH_MAX));
1102 assert_eq!(round(&ok), ok);
1103 }
1104
1105 #[test]
1106 fn json_writes_a_value_where_a_value_goes_and_not_only_at_the_root() {
1107 let mut b = Builder::new();
1108 b.begin_object().expect("open");
1109 b.key(b"meta").expect("key");
1110 b.json(br#"{"seen":2,"tags":["a"]}"#).expect("parses");
1111 b.key(b"id").expect("key");
1112 b.int(7).expect("value");
1113 b.end_object().expect("close");
1114 let bytes = b.finish().expect("finished").to_vec();
1115 let v = Value::new(&bytes).expect("readable");
1116 assert_eq!(
1117 v.to_json().expect("writable"),
1118 br#"{"id":7,"meta":{"seen":2,"tags":["a"]}}"#
1119 );
1120 }
1121
1122 #[test]
1123 fn a_float_that_json_cannot_write_says_so_rather_than_writing_something_else() {
1124 let mut b = Builder::new();
1125 b.float(f64::INFINITY).expect("value");
1126 let bytes = b.finish().expect("finished").to_vec();
1127 let v = Value::new(&bytes).expect("readable");
1128 let e = v.to_json().expect_err("infinity is not JSON");
1129 assert!(e.message().contains("infinity or a NaN"));
1130 }
1131
1132 #[test]
1133 fn an_interned_object_needs_the_key_table_and_says_so() {
1134 let mut b = Builder::new();
1135 b.begin_object_interned().expect("open");
1136 b.key_id(3).expect("key");
1137 b.int(1).expect("value");
1138 b.end_object().expect("close");
1139 let bytes = b.finish().expect("finished").to_vec();
1140 let v = Value::new(&bytes).expect("readable");
1141 let e = v.to_json().expect_err("there is no table here");
1142 assert!(e.message().contains("key table"));
1143 }
1144
1145 #[test]
1146 fn the_writer_appends_rather_than_replacing_what_is_in_the_buffer() {
1147 let bytes = from_json(b"[1,2]").expect("parses");
1148 let mut out = b"before ".to_vec();
1149 Value::new(&bytes)
1150 .expect("readable")
1151 .write_json(&mut out)
1152 .expect("writable");
1153 assert_eq!(out, b"before [1,2]");
1154 }
1155}