1use alloc::borrow::Cow;
12
13use facet_reflect::Span;
14
15use crate::scanner::{self, ParsedNumber, ScanError, ScanErrorKind, Scanner, Token as ScanToken};
16
17#[derive(Debug, Clone, PartialEq)]
19pub enum Token<'input> {
20 ObjectStart,
22 ObjectEnd,
24 ArrayStart,
26 ArrayEnd,
28 Colon,
30 Comma,
32 Null,
34 True,
36 False,
38 String(Cow<'input, str>),
40 U64(u64),
42 I64(i64),
44 U128(u128),
46 I128(i128),
48 F64(f64),
50 Eof,
52}
53
54#[derive(Debug, Clone)]
56pub struct SpannedAdapterToken<'input> {
57 pub token: Token<'input>,
59 pub span: Span,
61}
62
63#[derive(Debug, Clone)]
65pub struct AdapterError {
66 pub kind: AdapterErrorKind,
68 pub span: Span,
70}
71
72#[derive(Debug, Clone)]
74pub enum AdapterErrorKind {
75 Scan(ScanErrorKind),
77 NeedMore,
79}
80
81impl From<ScanError> for AdapterError {
82 fn from(e: ScanError) -> Self {
83 AdapterError {
84 kind: AdapterErrorKind::Scan(e.kind),
85 span: e.span,
86 }
87 }
88}
89
90pub const DEFAULT_CHUNK_SIZE: usize = 4;
92
93pub struct SliceAdapter<'input, const BORROW: bool> {
105 input: &'input [u8],
107 window_start: usize,
109 window_end: usize,
111 chunk_size: usize,
113 scanner: Scanner,
115}
116
117impl<'input, const BORROW: bool> SliceAdapter<'input, BORROW> {
118 pub fn new(input: &'input [u8]) -> Self {
120 Self::with_chunk_size(input, DEFAULT_CHUNK_SIZE)
121 }
122
123 pub fn with_chunk_size(input: &'input [u8], chunk_size: usize) -> Self {
125 let initial_end = chunk_size.min(input.len());
126 Self {
127 input,
128 window_start: 0,
129 window_end: initial_end,
130 chunk_size,
131 scanner: Scanner::new(),
132 }
133 }
134
135 #[inline]
137 fn current_window(&self) -> &'input [u8] {
138 &self.input[self.window_start..self.window_end]
139 }
140
141 #[inline]
143 fn grow_window(&mut self) {
144 self.window_end = (self.window_end + self.chunk_size).min(self.input.len());
145 }
146
147 #[inline]
149 fn slide_window(&mut self, consumed_in_window: usize) {
150 self.window_start += consumed_in_window;
151 self.window_end = (self.window_start + self.chunk_size).min(self.input.len());
152 self.scanner.set_pos(0);
153 }
154
155 #[inline]
157 fn at_end_of_input(&self) -> bool {
158 self.window_end >= self.input.len()
159 }
160
161 pub fn next_token(&mut self) -> Result<SpannedAdapterToken<'input>, AdapterError> {
169 loop {
170 let window = self.current_window();
171 let spanned = match self.scanner.next_token(window) {
172 Ok(s) => s,
173 Err(e) => {
174 return Err(AdapterError {
176 kind: AdapterErrorKind::Scan(e.kind),
177 span: Span::new(self.window_start + e.span.offset, e.span.len),
178 });
179 }
180 };
181
182 match spanned.token {
183 ScanToken::NeedMore { .. } => {
184 if self.at_end_of_input() {
186 let window = self.current_window();
188 let finalized = match self.scanner.finalize_at_eof(window) {
189 Ok(f) => f,
190 Err(e) => {
191 return Err(AdapterError {
192 kind: AdapterErrorKind::Scan(e.kind),
193 span: Span::new(self.window_start + e.span.offset, e.span.len),
194 });
195 }
196 };
197
198 let consumed = self.scanner.pos();
200 let absolute_span = Span::new(
201 self.window_start + finalized.span.offset,
202 finalized.span.len,
203 );
204
205 let token = self.materialize_token(&finalized)?;
206 self.slide_window(consumed);
207
208 return Ok(SpannedAdapterToken {
209 token,
210 span: absolute_span,
211 });
212 }
213 self.grow_window();
214 continue;
215 }
216 ScanToken::Eof => {
217 if self.at_end_of_input() {
219 return Ok(SpannedAdapterToken {
221 token: Token::Eof,
222 span: Span::new(self.window_start + spanned.span.offset, 0),
223 });
224 }
225 self.slide_window(self.scanner.pos());
227 continue;
228 }
229 _ => {
230 let consumed = self.scanner.pos();
232 let absolute_span =
233 Span::new(self.window_start + spanned.span.offset, spanned.span.len);
234
235 let token = self.materialize_token(&spanned)?;
236
237 self.slide_window(consumed);
239
240 return Ok(SpannedAdapterToken {
241 token,
242 span: absolute_span,
243 });
244 }
245 }
246 }
247 }
248
249 fn materialize_token(
254 &self,
255 spanned: &scanner::SpannedToken,
256 ) -> Result<Token<'input>, AdapterError> {
257 match &spanned.token {
258 ScanToken::ObjectStart => Ok(Token::ObjectStart),
259 ScanToken::ObjectEnd => Ok(Token::ObjectEnd),
260 ScanToken::ArrayStart => Ok(Token::ArrayStart),
261 ScanToken::ArrayEnd => Ok(Token::ArrayEnd),
262 ScanToken::Colon => Ok(Token::Colon),
263 ScanToken::Comma => Ok(Token::Comma),
264 ScanToken::Null => Ok(Token::Null),
265 ScanToken::True => Ok(Token::True),
266 ScanToken::False => Ok(Token::False),
267 ScanToken::String {
268 start,
269 end,
270 has_escapes,
271 } => {
272 let abs_start = self.window_start + start;
274 let abs_end = self.window_start + end;
275
276 let s = if BORROW && !*has_escapes {
277 scanner::decode_string(self.input, abs_start, abs_end, false)?
279 } else {
280 Cow::Owned(scanner::decode_string_owned(
282 self.input, abs_start, abs_end,
283 )?)
284 };
285 Ok(Token::String(s))
286 }
287 ScanToken::Number { start, end, hint } => {
288 let abs_start = self.window_start + start;
290 let abs_end = self.window_start + end;
291
292 let parsed = scanner::parse_number(self.input, abs_start, abs_end, *hint)?;
293 Ok(match parsed {
294 ParsedNumber::U64(n) => Token::U64(n),
295 ParsedNumber::I64(n) => Token::I64(n),
296 ParsedNumber::U128(n) => Token::U128(n),
297 ParsedNumber::I128(n) => Token::I128(n),
298 ParsedNumber::F64(n) => Token::F64(n),
299 })
300 }
301 ScanToken::Eof | ScanToken::NeedMore { .. } => {
302 unreachable!("Eof and NeedMore handled in next_token loop")
303 }
304 }
305 }
306
307 pub fn skip(&mut self) -> Result<Span, AdapterError> {
312 let first_token = self.next_token_for_skip()?;
314 let abs_start = first_token.span.offset;
315
316 match first_token.token {
317 SkipToken::ObjectStart => {
318 let mut depth = 1;
320 let mut abs_end = first_token.span.offset + first_token.span.len;
321 while depth > 0 {
322 let t = self.next_token_for_skip()?;
323 abs_end = t.span.offset + t.span.len;
324 match t.token {
325 SkipToken::ObjectStart => depth += 1,
326 SkipToken::ObjectEnd => depth -= 1,
327 _ => {}
328 }
329 }
330 Ok(Span::new(abs_start, abs_end - abs_start))
331 }
332 SkipToken::ArrayStart => {
333 let mut depth = 1;
335 let mut abs_end = first_token.span.offset + first_token.span.len;
336 while depth > 0 {
337 let t = self.next_token_for_skip()?;
338 abs_end = t.span.offset + t.span.len;
339 match t.token {
340 SkipToken::ArrayStart => depth += 1,
341 SkipToken::ArrayEnd => depth -= 1,
342 _ => {}
343 }
344 }
345 Ok(Span::new(abs_start, abs_end - abs_start))
346 }
347 SkipToken::Scalar => Ok(first_token.span),
349 SkipToken::Eof => Err(AdapterError {
350 kind: AdapterErrorKind::Scan(ScanErrorKind::UnexpectedEof("expected value")),
351 span: first_token.span,
352 }),
353 SkipToken::ObjectEnd | SkipToken::ArrayEnd => Err(AdapterError {
355 kind: AdapterErrorKind::Scan(ScanErrorKind::UnexpectedChar('}')),
356 span: first_token.span,
357 }),
358 }
359 }
360
361 fn next_token_for_skip(&mut self) -> Result<SpannedSkipToken, AdapterError> {
363 loop {
364 let window = self.current_window();
365 let spanned = match self.scanner.next_token(window) {
366 Ok(s) => s,
367 Err(e) => {
368 return Err(AdapterError {
369 kind: AdapterErrorKind::Scan(e.kind),
370 span: Span::new(self.window_start + e.span.offset, e.span.len),
371 });
372 }
373 };
374
375 match spanned.token {
376 ScanToken::NeedMore { .. } => {
377 if self.at_end_of_input() {
378 let window = self.current_window();
380 let finalized = match self.scanner.finalize_at_eof(window) {
381 Ok(f) => f,
382 Err(e) => {
383 return Err(AdapterError {
384 kind: AdapterErrorKind::Scan(e.kind),
385 span: Span::new(self.window_start + e.span.offset, e.span.len),
386 });
387 }
388 };
389
390 let consumed = self.scanner.pos();
391 let abs_span = Span::new(
392 self.window_start + finalized.span.offset,
393 finalized.span.len,
394 );
395
396 let skip_token = match finalized.token {
397 ScanToken::ObjectStart => SkipToken::ObjectStart,
398 ScanToken::ObjectEnd => SkipToken::ObjectEnd,
399 ScanToken::ArrayStart => SkipToken::ArrayStart,
400 ScanToken::ArrayEnd => SkipToken::ArrayEnd,
401 ScanToken::String { .. }
402 | ScanToken::Number { .. }
403 | ScanToken::True
404 | ScanToken::False
405 | ScanToken::Null
406 | ScanToken::Colon
407 | ScanToken::Comma => SkipToken::Scalar,
408 ScanToken::Eof => SkipToken::Eof,
409 ScanToken::NeedMore { .. } => unreachable!(),
410 };
411
412 self.slide_window(consumed);
413 return Ok(SpannedSkipToken {
414 token: skip_token,
415 span: abs_span,
416 });
417 }
418 self.grow_window();
419 continue;
420 }
421 ScanToken::Eof => {
422 if self.at_end_of_input() {
423 return Ok(SpannedSkipToken {
424 token: SkipToken::Eof,
425 span: Span::new(self.window_start + spanned.span.offset, 0),
426 });
427 }
428 self.slide_window(self.scanner.pos());
429 continue;
430 }
431 _ => {
432 let consumed = self.scanner.pos();
433 let abs_span =
434 Span::new(self.window_start + spanned.span.offset, spanned.span.len);
435
436 let skip_token = match spanned.token {
437 ScanToken::ObjectStart => SkipToken::ObjectStart,
438 ScanToken::ObjectEnd => SkipToken::ObjectEnd,
439 ScanToken::ArrayStart => SkipToken::ArrayStart,
440 ScanToken::ArrayEnd => SkipToken::ArrayEnd,
441 ScanToken::String { .. }
442 | ScanToken::Number { .. }
443 | ScanToken::True
444 | ScanToken::False
445 | ScanToken::Null
446 | ScanToken::Colon
447 | ScanToken::Comma => SkipToken::Scalar,
448 ScanToken::Eof | ScanToken::NeedMore { .. } => unreachable!(),
449 };
450
451 self.slide_window(consumed);
452 return Ok(SpannedSkipToken {
453 token: skip_token,
454 span: abs_span,
455 });
456 }
457 }
458 }
459 }
460
461 pub fn position(&self) -> usize {
463 self.window_start + self.scanner.pos()
464 }
465
466 pub fn input(&self) -> &'input [u8] {
468 self.input
469 }
470}
471
472#[derive(Debug, Clone, Copy)]
474enum SkipToken {
475 ObjectStart,
476 ObjectEnd,
477 ArrayStart,
478 ArrayEnd,
479 Scalar, Eof,
481}
482
483#[derive(Debug)]
485struct SpannedSkipToken {
486 token: SkipToken,
487 span: Span,
488}
489
490use crate::{JsonError, JsonErrorKind};
495
496pub trait TokenSource<'input> {
505 fn next_token(&mut self) -> Result<SpannedAdapterToken<'input>, JsonError>;
507
508 fn skip(&mut self) -> Result<Span, JsonError>;
511
512 fn input_bytes(&self) -> Option<&'input [u8]> {
517 None
518 }
519
520 fn at_offset(&self, offset: usize) -> Option<Self>
525 where
526 Self: Sized,
527 {
528 let _ = offset;
529 None
530 }
531}
532
533impl<'input, const BORROW: bool> TokenSource<'input> for SliceAdapter<'input, BORROW> {
534 fn next_token(&mut self) -> Result<SpannedAdapterToken<'input>, JsonError> {
535 SliceAdapter::next_token(self).map_err(|e| JsonError {
536 kind: JsonErrorKind::Scan(match e.kind {
537 AdapterErrorKind::Scan(s) => s,
538 AdapterErrorKind::NeedMore => {
539 crate::scanner::ScanErrorKind::UnexpectedEof("need more data")
540 }
541 }),
542 span: Some(e.span),
543 source_code: None,
544 })
545 }
546
547 fn skip(&mut self) -> Result<Span, JsonError> {
548 SliceAdapter::skip(self).map_err(|e| JsonError {
549 kind: JsonErrorKind::Scan(match e.kind {
550 AdapterErrorKind::Scan(s) => s,
551 AdapterErrorKind::NeedMore => {
552 crate::scanner::ScanErrorKind::UnexpectedEof("need more data")
553 }
554 }),
555 span: Some(e.span),
556 source_code: None,
557 })
558 }
559
560 fn input_bytes(&self) -> Option<&'input [u8]> {
561 Some(self.input)
562 }
563
564 fn at_offset(&self, offset: usize) -> Option<Self> {
565 Some(SliceAdapter::new(&self.input[offset..]))
566 }
567}
568
569#[cfg(test)]
570mod tests {
571 use super::*;
572
573 #[test]
574 fn test_next_simple() {
575 let json = br#"{"name": "test", "value": 42}"#;
576 let mut adapter = SliceAdapter::<true>::new(json);
577
578 let t = adapter.next_token().unwrap();
580 assert!(matches!(t.token, Token::ObjectStart));
581
582 let t = adapter.next_token().unwrap();
584 assert_eq!(t.token, Token::String(Cow::Borrowed("name")));
585
586 let t = adapter.next_token().unwrap();
588 assert!(matches!(t.token, Token::Colon));
589
590 let t = adapter.next_token().unwrap();
592 assert_eq!(t.token, Token::String(Cow::Borrowed("test")));
593
594 let t = adapter.next_token().unwrap();
596 assert!(matches!(t.token, Token::Comma));
597
598 let t = adapter.next_token().unwrap();
600 assert_eq!(t.token, Token::String(Cow::Borrowed("value")));
601
602 let t = adapter.next_token().unwrap();
604 assert!(matches!(t.token, Token::Colon));
605
606 let t = adapter.next_token().unwrap();
608 assert_eq!(t.token, Token::U64(42));
609
610 let t = adapter.next_token().unwrap();
612 assert!(matches!(t.token, Token::ObjectEnd));
613
614 let t = adapter.next_token().unwrap();
616 assert!(matches!(t.token, Token::Eof));
617 }
618
619 #[test]
620 fn test_next_with_escapes() {
621 let json = br#""hello\nworld""#;
622 let mut adapter = SliceAdapter::<true>::new(json);
623
624 let t = adapter.next_token().unwrap();
625 assert_eq!(
627 t.token,
628 Token::String(Cow::Owned("hello\nworld".to_string()))
629 );
630 }
631
632 #[test]
633 fn test_skip_scalar() {
634 let json = br#"{"skip": 12345, "keep": "value"}"#;
635 let mut adapter = SliceAdapter::<true>::new(json);
636
637 adapter.next_token().unwrap();
639 adapter.next_token().unwrap();
641 adapter.next_token().unwrap();
643
644 let span = adapter.skip().unwrap();
646 assert_eq!(&json[span.offset..span.offset + span.len], b"12345");
647
648 let t = adapter.next_token().unwrap();
650 assert!(matches!(t.token, Token::Comma));
651
652 let t = adapter.next_token().unwrap();
654 assert_eq!(t.token, Token::String(Cow::Borrowed("keep")));
655 }
656
657 #[test]
658 fn test_skip_object() {
659 let json = br#"{"skip": {"nested": {"deep": true}}, "keep": 1}"#;
660 let mut adapter = SliceAdapter::<true>::new(json);
661
662 adapter.next_token().unwrap();
664 adapter.next_token().unwrap();
666 adapter.next_token().unwrap();
668
669 let span = adapter.skip().unwrap();
671 assert_eq!(
672 &json[span.offset..span.offset + span.len],
673 br#"{"nested": {"deep": true}}"#
674 );
675
676 let t = adapter.next_token().unwrap();
678 assert!(matches!(t.token, Token::Comma));
679
680 let t = adapter.next_token().unwrap();
682 assert_eq!(t.token, Token::String(Cow::Borrowed("keep")));
683 }
684
685 #[test]
686 fn test_skip_array() {
687 let json = br#"{"skip": [1, [2, 3], 4], "keep": true}"#;
688 let mut adapter = SliceAdapter::<true>::new(json);
689
690 adapter.next_token().unwrap();
692 adapter.next_token().unwrap();
694 adapter.next_token().unwrap();
696
697 let span = adapter.skip().unwrap();
699 assert_eq!(
700 &json[span.offset..span.offset + span.len],
701 br#"[1, [2, 3], 4]"#
702 );
703
704 adapter.next_token().unwrap();
706
707 let t = adapter.next_token().unwrap();
709 assert_eq!(t.token, Token::String(Cow::Borrowed("keep")));
710
711 adapter.next_token().unwrap();
713
714 let t = adapter.next_token().unwrap();
716 assert!(matches!(t.token, Token::True));
717 }
718
719 #[test]
720 fn test_skip_string_no_allocation() {
721 let json = br#"{"skip": "hello\nworld\twith\rescapes", "keep": 1}"#;
723 let mut adapter = SliceAdapter::<true>::new(json);
724
725 adapter.next_token().unwrap();
727 adapter.next_token().unwrap();
729 adapter.next_token().unwrap();
731
732 let span = adapter.skip().unwrap();
734 assert_eq!(
735 &json[span.offset..span.offset + span.len],
736 br#""hello\nworld\twith\rescapes""#
737 );
738 }
739
740 #[test]
741 fn test_borrow_false_always_owned() {
742 let json = br#""no escapes here""#;
743 let mut adapter = SliceAdapter::<false>::new(json);
744
745 let t = adapter.next_token().unwrap();
746 assert!(matches!(t.token, Token::String(Cow::Owned(_))));
748 }
749
750 #[test]
751 fn test_borrow_true_borrows_when_possible() {
752 let json = br#""no escapes here""#;
753 let mut adapter = SliceAdapter::<true>::new(json);
754
755 let t = adapter.next_token().unwrap();
756 assert!(matches!(t.token, Token::String(Cow::Borrowed(_))));
758 }
759
760 #[test]
761 fn test_windowed_parsing_long_string() {
762 let json = br#""hello world""#; let mut adapter = SliceAdapter::<true>::new(json);
766
767 let t = adapter.next_token().unwrap();
768 assert_eq!(t.token, Token::String(Cow::Borrowed("hello world")));
769 assert_eq!(t.span.offset, 0);
771 assert_eq!(t.span.len, 13);
772 }
773
774 #[test]
775 fn test_windowed_parsing_number_at_eof() {
776 let json = b"-123"; let mut adapter = SliceAdapter::<true>::new(json);
779
780 let t = adapter.next_token().unwrap();
781 assert_eq!(t.token, Token::I64(-123));
782 }
783
784 #[test]
785 fn test_windowed_parsing_complex_object() {
786 let json = br#"{"name": "hello world", "value": 12345, "nested": {"a": 1}}"#;
788 let mut adapter = SliceAdapter::<true>::new(json);
789
790 assert!(matches!(
792 adapter.next_token().unwrap().token,
793 Token::ObjectStart
794 ));
795 assert_eq!(
797 adapter.next_token().unwrap().token,
798 Token::String(Cow::Borrowed("name"))
799 );
800 assert!(matches!(adapter.next_token().unwrap().token, Token::Colon));
802 assert_eq!(
804 adapter.next_token().unwrap().token,
805 Token::String(Cow::Borrowed("hello world"))
806 );
807 assert!(matches!(adapter.next_token().unwrap().token, Token::Comma));
809 assert_eq!(
811 adapter.next_token().unwrap().token,
812 Token::String(Cow::Borrowed("value"))
813 );
814 assert!(matches!(adapter.next_token().unwrap().token, Token::Colon));
816 assert_eq!(adapter.next_token().unwrap().token, Token::U64(12345));
818 assert!(matches!(adapter.next_token().unwrap().token, Token::Comma));
820 assert_eq!(
822 adapter.next_token().unwrap().token,
823 Token::String(Cow::Borrowed("nested"))
824 );
825 assert!(matches!(adapter.next_token().unwrap().token, Token::Colon));
827 assert!(matches!(
829 adapter.next_token().unwrap().token,
830 Token::ObjectStart
831 ));
832 assert_eq!(
834 adapter.next_token().unwrap().token,
835 Token::String(Cow::Borrowed("a"))
836 );
837 assert!(matches!(adapter.next_token().unwrap().token, Token::Colon));
839 assert_eq!(adapter.next_token().unwrap().token, Token::U64(1));
841 assert!(matches!(
843 adapter.next_token().unwrap().token,
844 Token::ObjectEnd
845 ));
846 assert!(matches!(
848 adapter.next_token().unwrap().token,
849 Token::ObjectEnd
850 ));
851 assert!(matches!(adapter.next_token().unwrap().token, Token::Eof));
853 }
854}
855
856#[cfg(all(test, feature = "bolero-inline-tests"))]
857#[allow(clippy::while_let_loop, clippy::same_item_push)]
858mod fuzz_tests {
859 use super::*;
860 use bolero::check;
861
862 #[test]
864 fn fuzz_adapter_arbitrary_bytes() {
865 check!().for_each(|input: &[u8]| {
866 let mut adapter = SliceAdapter::<true>::new(input);
867 loop {
868 match adapter.next_token() {
869 Ok(spanned) => {
870 if matches!(spanned.token, Token::Eof) {
871 break;
872 }
873 }
874 Err(_) => break,
875 }
876 }
877 });
878 }
879
880 #[test]
882 fn fuzz_adapter_skip() {
883 check!().for_each(|input: &[u8]| {
884 let mut adapter = SliceAdapter::<true>::new(input);
885 let _ = adapter.skip();
887 });
888 }
889
890 #[test]
892 fn fuzz_adapter_next_skip_alternating() {
893 check!().for_each(|input: &[u8]| {
894 let mut adapter = SliceAdapter::<true>::new(input);
895 let mut use_skip = false;
896 loop {
897 let result = if use_skip {
898 adapter.skip().map(|_| ())
899 } else {
900 adapter
901 .next_token()
902 .map(|t| if matches!(t.token, Token::Eof) {})
903 };
904 match result {
905 Ok(()) => {}
906 Err(_) => break,
907 }
908 use_skip = !use_skip;
909
910 let mut peek_adapter = SliceAdapter::<true>::new(&input[adapter.position()..]);
912 if matches!(peek_adapter.next_token(), Ok(t) if matches!(t.token, Token::Eof)) {
913 break;
914 }
915 }
916 });
917 }
918
919 #[test]
921 fn fuzz_adapter_no_borrow() {
922 check!().for_each(|input: &[u8]| {
923 let mut adapter = SliceAdapter::<false>::new(input);
924 loop {
925 match adapter.next_token() {
926 Ok(spanned) => {
927 if let Token::String(cow) = &spanned.token {
929 assert!(matches!(cow, Cow::Owned(_)));
930 }
931 if matches!(spanned.token, Token::Eof) {
932 break;
933 }
934 }
935 Err(_) => break,
936 }
937 }
938 });
939 }
940
941 #[test]
943 fn fuzz_adapter_string_escapes() {
944 check!().for_each(|content: &[u8]| {
945 let mut input = Vec::new();
947 input.extend_from_slice(br#"{"k":""#);
948 input.extend_from_slice(content);
949 input.extend_from_slice(br#""}"#);
950
951 let mut adapter = SliceAdapter::<true>::new(&input);
952 loop {
953 match adapter.next_token() {
954 Ok(t) if matches!(t.token, Token::Eof) => break,
955 Ok(_) => {}
956 Err(_) => break,
957 }
958 }
959 });
960 }
961
962 #[test]
964 fn fuzz_adapter_skip_nested() {
965 check!().for_each(|input: &[u8]| {
966 let depth = (input.first().copied().unwrap_or(1) as usize % 50) + 1;
968
969 let mut nested = Vec::new();
971 for _ in 0..depth {
972 nested.push(b'[');
973 }
974 nested.extend_from_slice(b"null");
975 for _ in 0..depth {
976 nested.push(b']');
977 }
978
979 let mut adapter = SliceAdapter::<true>::new(&nested);
980 let result = adapter.skip();
981 assert!(result.is_ok());
982 let span = result.unwrap();
983 assert_eq!(span.len, nested.len());
984 });
985 }
986}