1use std::borrow::Cow;
14
15use crate::error::{Code, Issue, Path, ValidationError};
16use crate::input::{Input, Kind};
17use crate::limits::Limits;
18use crate::value::{Int, Slot};
19
20#[derive(Debug, Clone, PartialEq, Eq)]
21pub struct JsonError {
22 pub line: usize,
23 pub column: usize,
24 pub message: String,
25 pub code: Option<Code>,
34}
35
36impl JsonError {
37 pub fn as_validation(&self) -> Option<ValidationError> {
38 self.code.map(|code| ValidationError {
39 issues: vec![Issue { path: Path(Vec::new()), code, message: self.message.clone() }],
40 })
41 }
42}
43
44impl std::fmt::Display for JsonError {
45 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46 write!(f, "{}:{}: {}", self.line, self.column, self.message)
47 }
48}
49
50impl std::error::Error for JsonError {}
51
52#[derive(Debug, Clone, Copy)]
53struct Span {
54 start: u32,
55 len: u32,
56 escaped: bool,
57}
58
59#[derive(Debug, Clone, Copy)]
60struct Member {
61 key: Span,
62 node: u32,
63}
64
65#[derive(Debug, Clone, Copy)]
66enum Node {
67 Null,
68 Bool(bool),
69 Int(Int),
70 IntTooWide,
71 Float(f64),
72 Str(Span),
73 Array { first: u32, len: u32 },
74 Object { first: u32, len: u32 },
75}
76
77#[derive(Debug)]
79pub struct Document<'a> {
80 src: &'a [u8],
81 nodes: Vec<Node>,
82 items: Vec<u32>,
83 members: Vec<Member>,
84 root: u32,
85}
86
87impl<'a> Document<'a> {
88 pub fn parse(input: &'a [u8], limits: Limits) -> Result<Self, JsonError> {
90 let limits = limits.clamped();
93 if u32::try_from(input.len()).is_err() {
94 return Err(JsonError {
95 line: 1,
96 column: 1,
97 message: "document larger than 4 GiB".to_string(),
98 code: Some(Code::SizeExceeded),
101 });
102 }
103 if std::str::from_utf8(input).is_err() {
104 return Err(JsonError {
105 line: 1,
106 column: 1,
107 message: "input is not valid UTF-8".to_string(),
108 code: None,
110 });
111 }
112
113 let mut p = Parser {
114 src: input,
115 pos: 0,
116 limits,
117 nodes: Vec::new(),
118 items: Vec::new(),
119 members: Vec::new(),
120 };
121 p.skip_ws();
122 let root = p.value(0)?;
123 p.skip_ws();
124 if p.pos < p.src.len() {
125 return Err(p.error("trailing characters after the document"));
126 }
127 Ok(Document {
128 src: input,
129 nodes: p.nodes,
130 items: p.items,
131 members: p.members,
132 root,
133 })
134 }
135
136 #[must_use]
138 pub fn root(&self) -> Ref<'a, '_> {
139 Ref { doc: self, node: self.root }
140 }
141
142 fn bytes(&self, span: Span) -> &'a [u8] {
143 let end = (span.start + span.len) as usize;
144 self.src.get(span.start as usize..end).unwrap_or(&[])
145 }
146
147 fn text(&self, span: Span) -> Cow<'a, str> {
148 let raw = std::str::from_utf8(self.bytes(span)).unwrap_or("");
150 if span.escaped {
151 Cow::Owned(unescape(raw))
152 } else {
153 Cow::Borrowed(raw)
154 }
155 }
156}
157
158#[derive(Clone, Copy)]
160pub struct Ref<'a, 'd> {
161 doc: &'d Document<'a>,
162 node: u32,
163}
164
165impl<'a, 'd> Ref<'a, 'd> {
166 fn node(&self) -> Node {
167 self.doc
168 .nodes
169 .get(self.node as usize)
170 .copied()
171 .unwrap_or(Node::Null)
172 }
173
174 fn at(&self, node: u32) -> Ref<'a, 'd> {
175 Ref { doc: self.doc, node }
176 }
177
178 fn members(&self) -> &'d [Member] {
179 match self.node() {
180 Node::Object { first, len } => self
181 .doc
182 .members
183 .get(first as usize..(first + len) as usize)
184 .unwrap_or(&[]),
185 _ => &[],
186 }
187 }
188
189 #[must_use]
191 pub fn text(&self) -> Option<Cow<'a, str>> {
192 match self.node() {
193 Node::Str(span) => Some(self.doc.text(span)),
194 _ => None,
195 }
196 }
197
198 pub fn entries(&self) -> impl Iterator<Item = (Cow<'a, str>, Ref<'a, 'd>)> + '_ {
200 self.members()
201 .iter()
202 .map(move |m| (self.doc.text(m.key), self.at(m.node)))
203 }
204
205 pub fn elements(&self) -> impl Iterator<Item = Ref<'a, 'd>> + '_ {
207 let items = match self.node() {
208 Node::Array { first, len } => self
209 .doc
210 .items
211 .get(first as usize..(first + len) as usize)
212 .unwrap_or(&[]),
213 _ => &[],
214 };
215 items.iter().map(move |&n| self.at(n))
216 }
217}
218
219impl Input for Ref<'_, '_> {
220 type Child<'x>
221 = Self
222 where
223 Self: 'x;
224
225 fn kind(&self) -> Kind {
226 match self.node() {
227 Node::Null => Kind::Null,
228 Node::Bool(_) => Kind::Bool,
229 Node::Int(_) => Kind::Int,
230 Node::IntTooWide => Kind::IntegerTooWide,
231 Node::Float(_) => Kind::Float,
232 Node::Str(_) => Kind::String,
233 Node::Array { .. } => Kind::Array,
234 Node::Object { .. } => Kind::Object,
235 }
236 }
237
238 fn as_bool(&self) -> Option<bool> {
239 match self.node() {
240 Node::Bool(b) => Some(b),
241 _ => None,
242 }
243 }
244
245 fn as_int(&self) -> Option<Int> {
246 match self.node() {
247 Node::Int(n) => Some(n),
248 _ => None,
249 }
250 }
251
252 fn as_f64(&self) -> Option<f64> {
253 match self.node() {
254 Node::Float(f) => Some(f),
255 Node::Int(n) => Some(n.as_i128() as f64),
256 _ => None,
257 }
258 }
259
260 fn as_str(&self) -> Option<Cow<'_, str>> {
261 self.text()
262 }
263
264 fn len(&self) -> usize {
265 match self.node() {
266 Node::Array { len, .. } | Node::Object { len, .. } => len as usize,
267 _ => 0,
268 }
269 }
270
271 fn item(&self, index: usize) -> Option<Self::Child<'_>> {
272 let Node::Array { first, len } = self.node() else {
273 return None;
274 };
275 if index >= len as usize {
276 return None;
277 }
278 self.doc
279 .items
280 .get(first as usize + index)
281 .map(|&n| self.at(n))
282 }
283
284 fn slot(&self, key: &str) -> Slot<Self::Child<'_>> {
285 for m in self.members() {
288 let matches = if m.key.escaped {
289 self.doc.text(m.key) == key
290 } else {
291 self.doc.bytes(m.key) == key.as_bytes()
292 };
293 if matches {
294 let child = self.at(m.node);
295 return match child.node() {
296 Node::Null => Slot::Null,
297 _ => Slot::Present(child),
298 };
299 }
300 }
301 Slot::Absent
302 }
303
304 fn each_key(&self, f: &mut dyn FnMut(&str)) {
305 for m in self.members() {
306 f(&self.doc.text(m.key));
307 }
308 }
309}
310
311fn unescape(raw: &str) -> String {
312 let mut out = String::with_capacity(raw.len());
313 let mut chars = raw.chars();
314 while let Some(c) = chars.next() {
315 if c != '\\' {
316 out.push(c);
317 continue;
318 }
319 match chars.next() {
320 Some('"') => out.push('"'),
321 Some('\\') => out.push('\\'),
322 Some('/') => out.push('/'),
323 Some('b') => out.push('\u{0008}'),
324 Some('f') => out.push('\u{000C}'),
325 Some('n') => out.push('\n'),
326 Some('r') => out.push('\r'),
327 Some('t') => out.push('\t'),
328 Some('u') => {
329 let first = hex4(&mut chars);
330 let scalar = if (0xD800..=0xDBFF).contains(&first) {
331 chars.next();
333 chars.next();
334 let second = hex4(&mut chars);
335 0x10000 + ((first - 0xD800) << 10) + (second - 0xDC00)
336 } else {
337 first
338 };
339 out.push(char::from_u32(scalar).unwrap_or('\u{FFFD}'));
340 }
341 _ => {}
342 }
343 }
344 out
345}
346
347fn hex4(chars: &mut std::str::Chars<'_>) -> u32 {
348 let mut n = 0;
349 for _ in 0..4 {
350 n = n * 16 + chars.next().and_then(|c| c.to_digit(16)).unwrap_or(0);
351 }
352 n
353}
354
355struct Parser<'a> {
356 src: &'a [u8],
357 pos: usize,
358 limits: Limits,
359 nodes: Vec<Node>,
360 items: Vec<u32>,
361 members: Vec<Member>,
362}
363
364impl Parser<'_> {
365 fn error(&self, message: impl Into<String>) -> JsonError {
366 let mut line = 1;
367 let mut column = 1;
368 for &b in self.src.iter().take(self.pos) {
369 if b == b'\n' {
370 line += 1;
371 column = 1;
372 } else {
373 column += 1;
374 }
375 }
376 JsonError { line, column, message: message.into(), code: None }
377 }
378
379 fn exceeded(&self, code: Code, message: impl Into<String>) -> JsonError {
381 JsonError { code: Some(code), ..self.error(message) }
382 }
383
384 fn push(&mut self, node: Node) -> u32 {
385 self.nodes.push(node);
386 (self.nodes.len() - 1) as u32
387 }
388
389 fn peek(&self) -> Option<u8> {
390 self.src.get(self.pos).copied()
391 }
392
393 fn bump(&mut self) -> Option<u8> {
394 let b = self.peek()?;
395 self.pos += 1;
396 Some(b)
397 }
398
399 fn skip_ws(&mut self) {
400 while matches!(self.peek(), Some(b' ' | b'\t' | b'\n' | b'\r')) {
401 self.pos += 1;
402 }
403 }
404
405 fn expect(&mut self, byte: u8) -> Result<(), JsonError> {
406 if self.peek() == Some(byte) {
407 self.pos += 1;
408 Ok(())
409 } else {
410 Err(self.error(format!("expected `{}`", byte as char)))
411 }
412 }
413
414 fn value(&mut self, depth: usize) -> Result<u32, JsonError> {
415 if depth > self.limits.max_depth {
416 return Err(self.exceeded(
417 Code::DepthExceeded,
418 format!("nesting deeper than the limit of {}", self.limits.max_depth),
419 ));
420 }
421 match self.peek() {
422 Some(b'{') => self.object(depth),
423 Some(b'[') => self.array(depth),
424 Some(b'"') => {
425 let span = self.string()?;
426 Ok(self.push(Node::Str(span)))
427 }
428 Some(b't') => self.literal("true", Node::Bool(true)),
429 Some(b'f') => self.literal("false", Node::Bool(false)),
430 Some(b'n') => self.literal("null", Node::Null),
431 Some(b'-' | b'0'..=b'9') => self.number(),
432 Some(b) => Err(self.error(format!("unexpected `{}`", b as char))),
433 None => Err(self.error("unexpected end of input")),
434 }
435 }
436
437 fn literal(&mut self, word: &str, node: Node) -> Result<u32, JsonError> {
438 if self.src[self.pos..].starts_with(word.as_bytes()) {
439 self.pos += word.len();
440 Ok(self.push(node))
441 } else {
442 Err(self.error(format!("expected `{word}`")))
443 }
444 }
445
446 fn object(&mut self, depth: usize) -> Result<u32, JsonError> {
447 self.expect(b'{')?;
448 self.skip_ws();
449 if self.peek() == Some(b'}') {
450 self.pos += 1;
451 return Ok(self.push(Node::Object { first: 0, len: 0 }));
452 }
453 let mut found: Vec<Member> = Vec::new();
454 loop {
455 self.skip_ws();
456 let key = self.string()?;
457 self.skip_ws();
458 self.expect(b':')?;
459 self.skip_ws();
460 let node = self.value(depth + 1)?;
461
462 let existing = found.iter().position(|m| {
464 let a = self
465 .src
466 .get(m.key.start as usize..(m.key.start + m.key.len) as usize);
467 let b = self
468 .src
469 .get(key.start as usize..(key.start + key.len) as usize);
470 a == b
471 });
472 match existing {
473 Some(i) => found[i].node = node,
474 None => found.push(Member { key, node }),
475 }
476 if found.len() > self.limits.max_object_keys {
477 return Err(self.exceeded(
478 Code::SizeExceeded,
479 format!(
480 "more than {} keys in one object",
481 self.limits.max_object_keys
482 ),
483 ));
484 }
485
486 self.skip_ws();
487 match self.bump() {
488 Some(b',') => {}
489 Some(b'}') => {
490 let first = self.members.len() as u32;
491 let len = found.len() as u32;
492 self.members.extend_from_slice(&found);
493 return Ok(self.push(Node::Object { first, len }));
494 }
495 _ => return Err(self.error("expected `,` or `}`")),
496 }
497 }
498 }
499
500 fn array(&mut self, depth: usize) -> Result<u32, JsonError> {
501 self.expect(b'[')?;
502 self.skip_ws();
503 if self.peek() == Some(b']') {
504 self.pos += 1;
505 return Ok(self.push(Node::Array { first: 0, len: 0 }));
506 }
507 let mut found: Vec<u32> = Vec::new();
508 loop {
509 self.skip_ws();
510 found.push(self.value(depth + 1)?);
511 if found.len() > self.limits.max_items {
512 return Err(self.exceeded(
513 Code::SizeExceeded,
514 format!("more than {} items in one array", self.limits.max_items),
515 ));
516 }
517 self.skip_ws();
518 match self.bump() {
519 Some(b',') => {}
520 Some(b']') => {
521 let first = self.items.len() as u32;
522 let len = found.len() as u32;
523 self.items.extend_from_slice(&found);
524 return Ok(self.push(Node::Array { first, len }));
525 }
526 _ => return Err(self.error("expected `,` or `]`")),
527 }
528 }
529 }
530
531 fn string(&mut self) -> Result<Span, JsonError> {
533 self.expect(b'"')?;
534 let start = self.pos;
535 let mut escaped = false;
536 loop {
537 match self.bump() {
538 Some(b'"') => {
539 let len = (self.pos - 1 - start) as u32;
540 if len as usize > self.limits.max_string_bytes {
541 return Err(self.exceeded(
542 Code::SizeExceeded,
543 format!("string longer than {} bytes", self.limits.max_string_bytes),
544 ));
545 }
546 return Ok(Span { start: start as u32, len, escaped });
547 }
548 Some(b'\\') => {
549 escaped = true;
550 self.check_escape()?;
551 }
552 Some(_) => {}
553 None => return Err(self.error("unterminated string")),
554 }
555 }
556 }
557
558 fn check_escape(&mut self) -> Result<(), JsonError> {
559 match self.bump() {
560 Some(b'"' | b'\\' | b'/' | b'b' | b'f' | b'n' | b'r' | b't') => Ok(()),
561 Some(b'u') => match self.hex4()? {
562 0xD800..=0xDBFF => {
563 if self.bump() != Some(b'\\') || self.bump() != Some(b'u') {
564 return Err(self.error("lone high surrogate"));
565 }
566 if !(0xDC00..=0xDFFF).contains(&self.hex4()?) {
567 return Err(self.error("high surrogate not followed by a low one"));
568 }
569 Ok(())
570 }
571 0xDC00..=0xDFFF => Err(self.error("lone low surrogate")),
572 _ => Ok(()),
573 },
574 _ => Err(self.error("unknown escape")),
575 }
576 }
577
578 fn hex4(&mut self) -> Result<u32, JsonError> {
579 let mut n = 0;
580 for _ in 0..4 {
581 let d = match self.bump() {
582 Some(b @ b'0'..=b'9') => u32::from(b - b'0'),
583 Some(b @ b'a'..=b'f') => u32::from(b - b'a') + 10,
584 Some(b @ b'A'..=b'F') => u32::from(b - b'A') + 10,
585 _ => return Err(self.error("expected four hex digits")),
586 };
587 n = n * 16 + d;
588 }
589 Ok(n)
590 }
591
592 fn number(&mut self) -> Result<u32, JsonError> {
593 let start = self.pos;
594 if self.peek() == Some(b'-') {
595 self.pos += 1;
596 }
597 match self.peek() {
598 Some(b'0') => self.pos += 1,
600 Some(b'1'..=b'9') => {
601 while matches!(self.peek(), Some(b'0'..=b'9')) {
602 self.pos += 1;
603 }
604 }
605 _ => return Err(self.error("expected a digit")),
606 }
607
608 let mut fractional = false;
609 if self.peek() == Some(b'.') {
610 fractional = true;
611 self.pos += 1;
612 if !matches!(self.peek(), Some(b'0'..=b'9')) {
613 return Err(self.error("expected a digit after `.`"));
614 }
615 while matches!(self.peek(), Some(b'0'..=b'9')) {
616 self.pos += 1;
617 }
618 }
619 if matches!(self.peek(), Some(b'e' | b'E')) {
620 fractional = true;
621 self.pos += 1;
622 if matches!(self.peek(), Some(b'+' | b'-')) {
623 self.pos += 1;
624 }
625 if !matches!(self.peek(), Some(b'0'..=b'9')) {
626 return Err(self.error("expected a digit in the exponent"));
627 }
628 while matches!(self.peek(), Some(b'0'..=b'9')) {
629 self.pos += 1;
630 }
631 }
632
633 let text = std::str::from_utf8(&self.src[start..self.pos]).unwrap_or("");
634 if fractional {
635 return match text.parse::<f64>() {
636 Ok(f) => Ok(self.push(Node::Float(f))),
637 Err(_) => Err(self.error("number does not fit an f64")),
638 };
639 }
640 if let Ok(n) = text.parse::<i64>() {
643 return Ok(self.push(Node::Int(Int::Signed(n))));
644 }
645 if let Ok(n) = text.parse::<u64>() {
646 return Ok(self.push(Node::Int(Int::Unsigned(n))));
647 }
648 Ok(self.push(Node::IntTooWide))
649 }
650}
651
652#[cfg(test)]
653mod tests {
654 use super::*;
655
656 fn doc(src: &str) -> Document<'_> {
657 Document::parse(src.as_bytes(), Limits::PERMISSIVE).expect("should parse")
658 }
659
660 fn err(src: &str) -> JsonError {
661 Document::parse(src.as_bytes(), Limits::PERMISSIVE).expect_err("should not parse")
662 }
663
664 fn present<'a, 'd>(r: &Ref<'a, 'd>, key: &str) -> Ref<'a, 'd> {
665 match r.slot(key) {
666 Slot::Present(v) => v,
667 _ => panic!("expected a value at `{key}`"),
668 }
669 }
670
671 #[test]
672 fn the_boundary_integer_survives() {
673 assert_eq!(
675 doc("9007199254740993").root().as_int(),
676 Some(Int::Signed(9_007_199_254_740_993))
677 );
678 assert_eq!(
679 doc("18446744073709551615").root().as_int(),
680 Some(Int::Unsigned(u64::MAX))
681 );
682 assert_eq!(
683 doc("-9223372036854775808").root().as_int(),
684 Some(Int::Signed(i64::MIN))
685 );
686 }
687
688 #[test]
689 fn an_integer_past_64_bits_is_a_kind_not_a_number() {
690 assert_eq!(
691 doc("18446744073709551616").root().kind(),
692 Kind::IntegerTooWide
693 );
694 assert_eq!(
695 doc("-9223372036854775809").root().kind(),
696 Kind::IntegerTooWide
697 );
698 }
699
700 #[test]
701 fn a_plain_string_is_borrowed_not_copied() {
702 let d = doc(r#""hello""#);
703 assert!(matches!(d.root().text(), Some(Cow::Borrowed("hello"))));
704 }
705
706 #[test]
707 fn an_escaped_string_is_decoded_on_demand() {
708 assert_eq!(doc(r#""a\"b""#).root().text().as_deref(), Some("a\"b"));
709 assert_eq!(doc(r#""a\tb""#).root().text().as_deref(), Some("a\tb"));
710 assert_eq!(doc(r#""ñ""#).root().text().as_deref(), Some("ñ"));
711 assert_eq!(doc(r#""😀""#).root().text().as_deref(), Some("😀"));
712 }
713
714 #[test]
715 fn utf8_passes_through_untouched() {
716 assert_eq!(doc(r#""ñ😀""#).root().text().as_deref(), Some("ñ😀"));
717 }
718
719 #[test]
720 fn objects_and_arrays_are_walkable() {
721 let d = doc(r#"{"a": [1, null], "b": true}"#);
722 let root = d.root();
723 assert_eq!(root.kind(), Kind::Object);
724 assert_eq!(root.len(), 2);
725
726 let a = present(&root, "a");
727 assert_eq!(a.kind(), Kind::Array);
728 assert_eq!(a.len(), 2);
729 assert_eq!(a.item(0).and_then(|v| v.as_int()), Some(Int::Signed(1)));
730 assert_eq!(a.item(1).map(|v| v.kind()), Some(Kind::Null));
731 assert!(a.item(2).is_none());
732
733 assert_eq!(present(&root, "b").as_bool(), Some(true));
734 assert!(matches!(root.slot("missing"), Slot::Absent));
735 }
736
737 #[test]
738 fn a_null_member_is_null_and_a_missing_one_is_absent() {
739 let d = doc(r#"{"n": null}"#);
740 assert!(matches!(d.root().slot("n"), Slot::Null));
741 assert!(matches!(d.root().slot("gone"), Slot::Absent));
742 }
743
744 #[test]
745 fn keys_are_visited_in_order() {
746 let d = doc(r#"{"b": 1, "a": 2, "c": 3}"#);
747 let mut seen = Vec::new();
748 d.root().each_key(&mut |k| seen.push(k.to_string()));
749 assert_eq!(seen, ["b", "a", "c"]);
750 }
751
752 #[test]
753 fn a_duplicated_key_keeps_the_last() {
754 let d = doc(r#"{"a": 1, "a": 2}"#);
755 assert_eq!(d.root().len(), 1);
756 assert_eq!(present(&d.root(), "a").as_int(), Some(Int::Signed(2)));
757 }
758
759 #[test]
760 fn an_escaped_key_still_matches() {
761 let d = doc(r#"{"abc": 1}"#);
762 assert_eq!(present(&d.root(), "abc").as_int(), Some(Int::Signed(1)));
763 }
764
765 #[test]
766 fn nesting_is_walkable() {
767 let d = doc(r#"{"a": {"b": {"c": 7}}}"#);
768 let mut here = d.root();
769 for key in ["a", "b", "c"] {
770 here = present(&here, key);
771 }
772 assert_eq!(here.as_int(), Some(Int::Signed(7)));
773 }
774
775 #[test]
776 fn floats_stay_floats() {
777 assert_eq!(doc("1.5").root().as_f64(), Some(1.5));
778 assert_eq!(doc("1e3").root().as_f64(), Some(1000.0));
779 assert_eq!(doc("1").root().as_f64(), Some(1.0));
780 }
781
782 #[test]
783 fn malformed_input_is_rejected() {
784 assert!(err("01").message.contains("trailing"));
785 assert!(err("+1").message.contains("unexpected"));
786 assert!(err(".5").message.contains("unexpected"));
787 assert!(err("5.").message.contains("after `.`"));
788 assert!(err("1e").message.contains("exponent"));
789 assert!(err(r#"{"a":1,}"#).message.contains("expected"));
790 assert!(err("[1,]").message.contains("unexpected"));
791 assert!(err(r#""unterminated"#).message.contains("unterminated"));
792 assert!(err(r#""\ud800""#).message.contains("surrogate"));
793 assert!(err(r#""\q""#).message.contains("escape"));
794 assert!(err("{} {}").message.contains("trailing"));
795 assert!(err("").message.contains("end of input"));
796 }
797
798 #[test]
799 fn invalid_utf8_is_rejected() {
800 let e = Document::parse(&[b'"', 0xFF, b'"'], Limits::PERMISSIVE).expect_err("should fail");
801 assert!(e.message.contains("UTF-8"));
802 }
803
804 #[test]
805 fn errors_carry_a_position() {
806 let e = err("{\n \"a\": xyz\n}");
807 assert_eq!((e.line, e.column), (2, 8));
808 }
809
810 #[test]
811 fn limits_are_enforced_while_reading() {
812 let deep = "[".repeat(40) + &"]".repeat(40);
813 let limits = Limits { max_depth: 8, ..Limits::DEFAULT };
814 assert!(Document::parse(deep.as_bytes(), limits)
815 .expect_err("should fail")
816 .message
817 .contains("nesting"));
818
819 let limits = Limits { max_items: 2, ..Limits::DEFAULT };
820 assert!(Document::parse(b"[1,2,3]", limits)
821 .expect_err("should fail")
822 .message
823 .contains("items"));
824
825 let limits = Limits { max_string_bytes: 3, ..Limits::DEFAULT };
826 assert!(Document::parse(br#""abcd""#, limits)
827 .expect_err("should fail")
828 .message
829 .contains("longer than"));
830 }
831
832 #[test]
833 fn a_hostile_document_does_not_exhaust_the_stack() {
834 let deep = "[".repeat(100_000);
835 assert!(Document::parse(deep.as_bytes(), Limits::DEFAULT).is_err());
836 }
837}