1use std::str;
9
10const NIL: u8 = 0xc0;
13const FALSE: u8 = 0xc2;
14const TRUE: u8 = 0xc3;
15const BIN8: u8 = 0xc4;
16const BIN16: u8 = 0xc5;
17const BIN32: u8 = 0xc6;
18const EXT8: u8 = 0xc7;
19const EXT16: u8 = 0xc8;
20const EXT32: u8 = 0xc9;
21const FLOAT32: u8 = 0xca;
22const FLOAT64: u8 = 0xcb;
23const UINT8: u8 = 0xcc;
24const UINT16: u8 = 0xcd;
25const UINT32: u8 = 0xce;
26const UINT64: u8 = 0xcf;
27const INT8: u8 = 0xd0;
28const INT16: u8 = 0xd1;
29const INT32: u8 = 0xd2;
30const INT64: u8 = 0xd3;
31const FIXEXT1: u8 = 0xd4;
32const FIXEXT2: u8 = 0xd5;
33const FIXEXT4: u8 = 0xd6;
34const FIXEXT8: u8 = 0xd7;
35const FIXEXT16: u8 = 0xd8;
36const STR8: u8 = 0xd9;
37const STR16: u8 = 0xda;
38const STR32: u8 = 0xdb;
39const ARRAY16: u8 = 0xdc;
40const ARRAY32: u8 = 0xdd;
41const MAP16: u8 = 0xde;
42const MAP32: u8 = 0xdf;
43
44const MAX_DEPTH: u16 = 128;
46
47#[inline(always)]
50fn get(buf: &[u8], pos: usize) -> Option<u8> {
51 buf.get(pos).copied()
52}
53
54#[inline(always)]
55fn read_u16_be(buf: &[u8], pos: usize) -> Option<u16> {
56 let bytes = buf.get(pos..pos + 2)?;
57 Some(u16::from_be_bytes([bytes[0], bytes[1]]))
58}
59
60#[inline(always)]
61fn read_u32_be(buf: &[u8], pos: usize) -> Option<u32> {
62 let bytes = buf.get(pos..pos + 4)?;
63 Some(u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
64}
65
66#[inline(always)]
67fn read_u64_be(buf: &[u8], pos: usize) -> Option<u64> {
68 let bytes = buf.get(pos..pos + 8)?;
69 Some(u64::from_be_bytes([
70 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
71 ]))
72}
73
74#[inline(always)]
76fn checked_advance(buf: &[u8], offset: usize, size: usize) -> Option<usize> {
77 let end = offset + size;
78 if end <= buf.len() { Some(end) } else { None }
79}
80
81pub fn skip_value(buf: &[u8], offset: usize) -> Option<usize> {
89 skip_value_depth(buf, offset, 0)
90}
91
92fn skip_value_depth(buf: &[u8], offset: usize, depth: u16) -> Option<usize> {
93 if depth > MAX_DEPTH {
94 return None;
95 }
96 let tag = get(buf, offset)?;
97 match tag {
98 0x00..=0x7f => Some(offset + 1),
100 0xe0..=0xff => Some(offset + 1),
102 NIL | FALSE | TRUE => Some(offset + 1),
104
105 0x80..=0x8f => {
107 let count = (tag & 0x0f) as usize;
108 skip_n_pairs(buf, offset + 1, count, depth)
109 }
110 MAP16 => {
111 let count = read_u16_be(buf, offset + 1)? as usize;
112 skip_n_pairs(buf, offset + 3, count, depth)
113 }
114 MAP32 => {
115 let count = read_u32_be(buf, offset + 1)? as usize;
116 skip_n_pairs(buf, offset + 5, count, depth)
117 }
118
119 0x90..=0x9f => {
121 let count = (tag & 0x0f) as usize;
122 skip_n_values(buf, offset + 1, count, depth)
123 }
124 ARRAY16 => {
125 let count = read_u16_be(buf, offset + 1)? as usize;
126 skip_n_values(buf, offset + 3, count, depth)
127 }
128 ARRAY32 => {
129 let count = read_u32_be(buf, offset + 1)? as usize;
130 skip_n_values(buf, offset + 5, count, depth)
131 }
132
133 0xa0..=0xbf => {
135 let len = (tag & 0x1f) as usize;
136 checked_advance(buf, offset, 1 + len)
137 }
138 STR8 => {
139 let len = get(buf, offset + 1)? as usize;
140 checked_advance(buf, offset, 2 + len)
141 }
142 STR16 => {
143 let len = read_u16_be(buf, offset + 1)? as usize;
144 checked_advance(buf, offset, 3 + len)
145 }
146 STR32 => {
147 let len = read_u32_be(buf, offset + 1)? as usize;
148 checked_advance(buf, offset, 5 + len)
149 }
150
151 BIN8 => {
153 let len = get(buf, offset + 1)? as usize;
154 checked_advance(buf, offset, 2 + len)
155 }
156 BIN16 => {
157 let len = read_u16_be(buf, offset + 1)? as usize;
158 checked_advance(buf, offset, 3 + len)
159 }
160 BIN32 => {
161 let len = read_u32_be(buf, offset + 1)? as usize;
162 checked_advance(buf, offset, 5 + len)
163 }
164
165 FLOAT32 => checked_advance(buf, offset, 5),
167 FLOAT64 => checked_advance(buf, offset, 9),
168 UINT8 | INT8 => checked_advance(buf, offset, 2),
169 UINT16 | INT16 => checked_advance(buf, offset, 3),
170 UINT32 | INT32 => checked_advance(buf, offset, 5),
171 UINT64 | INT64 => checked_advance(buf, offset, 9),
172
173 FIXEXT1 => checked_advance(buf, offset, 3),
175 FIXEXT2 => checked_advance(buf, offset, 4),
176 FIXEXT4 => checked_advance(buf, offset, 6),
177 FIXEXT8 => checked_advance(buf, offset, 10),
178 FIXEXT16 => checked_advance(buf, offset, 18),
179 EXT8 => {
180 let len = get(buf, offset + 1)? as usize;
181 checked_advance(buf, offset, 3 + len)
182 }
183 EXT16 => {
184 let len = read_u16_be(buf, offset + 1)? as usize;
185 checked_advance(buf, offset, 4 + len)
186 }
187 EXT32 => {
188 let len = read_u32_be(buf, offset + 1)? as usize;
189 checked_advance(buf, offset, 6 + len)
190 }
191
192 _ => None,
194 }
195}
196
197fn skip_n_values(buf: &[u8], mut pos: usize, count: usize, depth: u16) -> Option<usize> {
198 for _ in 0..count {
199 pos = skip_value_depth(buf, pos, depth + 1)?;
200 }
201 Some(pos)
202}
203
204fn skip_n_pairs(buf: &[u8], mut pos: usize, count: usize, depth: u16) -> Option<usize> {
205 for _ in 0..count {
206 pos = skip_value_depth(buf, pos, depth + 1)?; pos = skip_value_depth(buf, pos, depth + 1)?; }
209 Some(pos)
210}
211
212pub fn read_f64(buf: &[u8], offset: usize) -> Option<f64> {
217 let tag = get(buf, offset)?;
218 match tag {
219 0x00..=0x7f => Some(tag as f64),
221 0xe0..=0xff => Some((tag as i8) as f64),
223 FLOAT64 => {
224 let bits = read_u64_be(buf, offset + 1)?;
225 Some(f64::from_bits(bits))
226 }
227 FLOAT32 => {
228 let bits = read_u32_be(buf, offset + 1)?;
229 Some(f32::from_bits(bits) as f64)
230 }
231 UINT8 => Some(get(buf, offset + 1)? as f64),
232 UINT16 => Some(read_u16_be(buf, offset + 1)? as f64),
233 UINT32 => Some(read_u32_be(buf, offset + 1)? as f64),
234 UINT64 => Some(read_u64_be(buf, offset + 1)? as f64),
235 INT8 => Some(get(buf, offset + 1)? as i8 as f64),
236 INT16 => Some(read_u16_be(buf, offset + 1)? as i16 as f64),
237 INT32 => Some(read_u32_be(buf, offset + 1)? as i32 as f64),
238 INT64 => Some(read_u64_be(buf, offset + 1)? as i64 as f64),
239 _ => None,
240 }
241}
242
243pub fn read_i64(buf: &[u8], offset: usize) -> Option<i64> {
246 let tag = get(buf, offset)?;
247 match tag {
248 0x00..=0x7f => Some(tag as i64),
249 0xe0..=0xff => Some((tag as i8) as i64),
250 UINT8 => Some(get(buf, offset + 1)? as i64),
251 UINT16 => Some(read_u16_be(buf, offset + 1)? as i64),
252 UINT32 => Some(read_u32_be(buf, offset + 1)? as i64),
253 UINT64 => {
254 let v = read_u64_be(buf, offset + 1)?;
255 Some(v as i64)
256 }
257 INT8 => Some(get(buf, offset + 1)? as i8 as i64),
258 INT16 => Some(read_u16_be(buf, offset + 1)? as i16 as i64),
259 INT32 => Some(read_u32_be(buf, offset + 1)? as i32 as i64),
260 INT64 => {
261 let v = read_u64_be(buf, offset + 1)?;
262 Some(v as i64)
263 }
264 _ => None,
265 }
266}
267
268pub fn read_str(buf: &[u8], offset: usize) -> Option<&str> {
272 let (start, len) = str_bounds(buf, offset)?;
273 let bytes = buf.get(start..start + len)?;
274 str::from_utf8(bytes).ok()
275}
276
277pub fn read_str_advance<'a>(buf: &'a [u8], off: &mut usize) -> Option<&'a str> {
280 let (start, len) = str_bounds(buf, *off)?;
281 let bytes = buf.get(start..start + len)?;
282 let s = str::from_utf8(bytes).ok()?;
283 *off = start + len;
284 Some(s)
285}
286
287pub fn read_bin_advance<'a>(buf: &'a [u8], off: &mut usize) -> Option<&'a [u8]> {
291 let tag = get(buf, *off)?;
292 let (len, header) = match tag {
293 BIN8 => (get(buf, *off + 1)? as usize, 2),
294 BIN16 => (read_u16_be(buf, *off + 1)? as usize, 3),
295 BIN32 => (read_u32_be(buf, *off + 1)? as usize, 5),
296 _ => return None,
297 };
298 let start = *off + header;
299 let end = start + len;
300 let data = buf.get(start..end)?;
301 *off = end;
302 Some(data)
303}
304
305pub fn read_u32_advance(buf: &[u8], off: &mut usize) -> Option<u32> {
309 let tag = get(buf, *off)?;
310 match tag {
311 0x00..=0x7f => {
312 *off += 1;
313 Some(tag as u32)
314 }
315 UINT8 => {
316 let v = get(buf, *off + 1)? as u32;
317 *off += 2;
318 Some(v)
319 }
320 UINT16 => {
321 let v = read_u16_be(buf, *off + 1)? as u32;
322 *off += 3;
323 Some(v)
324 }
325 UINT32 => {
326 let v = read_u32_be(buf, *off + 1)?;
327 *off += 5;
328 Some(v)
329 }
330 _ => None,
331 }
332}
333
334pub(crate) fn str_bounds(buf: &[u8], offset: usize) -> Option<(usize, usize)> {
337 let tag = get(buf, offset)?;
338 match tag {
339 0xa0..=0xbf => {
340 let len = (tag & 0x1f) as usize;
341 Some((offset + 1, len))
342 }
343 STR8 => {
344 let len = get(buf, offset + 1)? as usize;
345 Some((offset + 2, len))
346 }
347 STR16 => {
348 let len = read_u16_be(buf, offset + 1)? as usize;
349 Some((offset + 3, len))
350 }
351 STR32 => {
352 let len = read_u32_be(buf, offset + 1)? as usize;
353 Some((offset + 5, len))
354 }
355 _ => None,
356 }
357}
358
359pub fn read_bool(buf: &[u8], offset: usize) -> Option<bool> {
361 match get(buf, offset)? {
362 TRUE => Some(true),
363 FALSE => Some(false),
364 _ => None,
365 }
366}
367
368pub fn read_null(buf: &[u8], offset: usize) -> bool {
370 get(buf, offset) == Some(NIL)
371}
372
373pub fn read_value(buf: &[u8], offset: usize) -> Option<nodedb_types::Value> {
379 let tag = get(buf, offset)?;
380 match tag {
381 NIL => Some(nodedb_types::Value::Null),
382 TRUE => Some(nodedb_types::Value::Bool(true)),
383 FALSE => Some(nodedb_types::Value::Bool(false)),
384 0x00..=0x7f => Some(nodedb_types::Value::Integer(tag as i64)),
386 0xe0..=0xff => Some(nodedb_types::Value::Integer((tag as i8) as i64)),
387 UINT8 => Some(nodedb_types::Value::Integer(get(buf, offset + 1)? as i64)),
388 UINT16 => Some(nodedb_types::Value::Integer(
389 read_u16_be(buf, offset + 1)? as i64
390 )),
391 UINT32 => Some(nodedb_types::Value::Integer(
392 read_u32_be(buf, offset + 1)? as i64
393 )),
394 UINT64 => Some(nodedb_types::Value::Integer(
395 read_u64_be(buf, offset + 1)? as i64
396 )),
397 INT8 => Some(nodedb_types::Value::Integer(
398 get(buf, offset + 1)? as i8 as i64
399 )),
400 INT16 => Some(nodedb_types::Value::Integer(
401 read_u16_be(buf, offset + 1)? as i16 as i64,
402 )),
403 INT32 => Some(nodedb_types::Value::Integer(
404 read_u32_be(buf, offset + 1)? as i32 as i64,
405 )),
406 INT64 => Some(nodedb_types::Value::Integer(
407 read_u64_be(buf, offset + 1)? as i64
408 )),
409 FLOAT32 => {
411 let bits = read_u32_be(buf, offset + 1)?;
412 Some(nodedb_types::Value::Float(f32::from_bits(bits) as f64))
413 }
414 FLOAT64 => {
415 let bits = read_u64_be(buf, offset + 1)?;
416 Some(nodedb_types::Value::Float(f64::from_bits(bits)))
417 }
418 0xa0..=0xbf | STR8 | STR16 | STR32 => {
420 read_str(buf, offset).map(|s| nodedb_types::Value::String(s.to_string()))
421 }
422 _ => None,
423 }
424}
425
426pub fn map_header(buf: &[u8], offset: usize) -> Option<(usize, usize)> {
429 let tag = get(buf, offset)?;
430 match tag {
431 0x80..=0x8f => Some(((tag & 0x0f) as usize, offset + 1)),
432 MAP16 => Some((read_u16_be(buf, offset + 1)? as usize, offset + 3)),
433 MAP32 => Some((read_u32_be(buf, offset + 1)? as usize, offset + 5)),
434 _ => None,
435 }
436}
437
438pub fn array_header(buf: &[u8], offset: usize) -> Option<(usize, usize)> {
441 let tag = get(buf, offset)?;
442 match tag {
443 0x90..=0x9f => Some(((tag & 0x0f) as usize, offset + 1)),
444 ARRAY16 => Some((read_u16_be(buf, offset + 1)? as usize, offset + 3)),
445 ARRAY32 => Some((read_u32_be(buf, offset + 1)? as usize, offset + 5)),
446 _ => None,
447 }
448}
449
450#[cfg(test)]
451mod tests {
452 use super::*;
453
454 use serde_json::json;
455
456 fn encode(v: &serde_json::Value) -> Vec<u8> {
458 nodedb_types::json_msgpack::json_to_msgpack(v).expect("encode")
459 }
460
461 #[test]
462 fn skip_positive_fixint() {
463 let buf = [0x05, 0xff];
464 assert_eq!(skip_value(&buf, 0), Some(1));
465 }
466
467 #[test]
468 fn skip_negative_fixint() {
469 let buf = [0xe0, 0x00];
470 assert_eq!(skip_value(&buf, 0), Some(1));
471 }
472
473 #[test]
474 fn skip_nil_bool() {
475 assert_eq!(skip_value(&[NIL], 0), Some(1));
476 assert_eq!(skip_value(&[TRUE], 0), Some(1));
477 assert_eq!(skip_value(&[FALSE], 0), Some(1));
478 }
479
480 #[test]
481 fn skip_float64() {
482 let buf = encode(&json!(9.81));
483 assert_eq!(skip_value(&buf, 0), Some(buf.len()));
484 }
485
486 #[test]
487 fn skip_string() {
488 let buf = encode(&json!("hello"));
489 assert_eq!(skip_value(&buf, 0), Some(buf.len()));
490 }
491
492 #[test]
493 fn skip_map() {
494 let buf = encode(&json!({"a": 1, "b": 2}));
495 assert_eq!(skip_value(&buf, 0), Some(buf.len()));
496 }
497
498 #[test]
499 fn skip_nested_array() {
500 let buf = encode(&json!([[1, 2], [3, 4, 5]]));
501 assert_eq!(skip_value(&buf, 0), Some(buf.len()));
502 }
503
504 #[test]
505 fn skip_truncated_returns_none() {
506 let buf = [FLOAT64, 0x40]; assert_eq!(skip_value(&buf, 0), None);
508 }
509
510 #[test]
511 fn read_f64_fixint() {
512 assert_eq!(read_f64(&[42u8], 0), Some(42.0));
513 }
514
515 #[test]
516 fn read_f64_negative_fixint() {
517 assert_eq!(read_f64(&[0xffu8], 0), Some(-1.0));
518 }
519
520 #[test]
521 fn read_f64_float64() {
522 let buf = encode(&json!(std::f64::consts::PI));
523 assert_eq!(read_f64(&buf, 0), Some(std::f64::consts::PI));
524 }
525
526 #[test]
527 fn read_f64_uint16() {
528 let buf = encode(&json!(1000));
529 assert_eq!(read_f64(&buf, 0), Some(1000.0));
530 }
531
532 #[test]
533 fn read_i64_values() {
534 assert_eq!(read_i64(&[42u8], 0), Some(42));
535 assert_eq!(read_i64(&[0xffu8], 0), Some(-1));
536
537 let buf = encode(&json!(300));
538 assert_eq!(read_i64(&buf, 0), Some(300));
539
540 let buf = encode(&json!(-500));
541 assert_eq!(read_i64(&buf, 0), Some(-500));
542 }
543
544 #[test]
545 fn read_str_fixstr() {
546 let buf = encode(&json!("hi"));
547 assert_eq!(read_str(&buf, 0), Some("hi"));
548 }
549
550 #[test]
551 fn read_str_str8() {
552 let long = "a".repeat(40);
553 let buf = encode(&json!(long));
554 assert_eq!(read_str(&buf, 0), Some(long.as_str()));
555 }
556
557 #[test]
558 fn read_bool_values() {
559 assert_eq!(read_bool(&[TRUE], 0), Some(true));
560 assert_eq!(read_bool(&[FALSE], 0), Some(false));
561 assert_eq!(read_bool(&[NIL], 0), None);
562 }
563
564 #[test]
565 fn read_null_check() {
566 assert!(read_null(&[NIL], 0));
567 assert!(!read_null(&[TRUE], 0));
568 }
569
570 #[test]
571 fn map_header_fixmap() {
572 let buf = encode(&json!({"x": 1}));
573 let (count, _data_offset) = map_header(&buf, 0).unwrap();
574 assert_eq!(count, 1);
575 }
576
577 #[test]
578 fn skip_bin() {
579 let buf = [BIN8, 3, 0xde, 0xad, 0xbe, 0xff];
581 assert_eq!(skip_value(&buf, 0), Some(5));
582 }
583
584 #[test]
585 fn skip_ext() {
586 let buf = [FIXEXT1, 0x01, 0xab, 0xff];
588 assert_eq!(skip_value(&buf, 0), Some(3));
589 }
590
591 #[test]
592 fn read_f64_float32() {
593 let buf = [0xca, 0x3f, 0xc0, 0x00, 0x00];
596 let val = read_f64(&buf, 0).unwrap();
597 assert!((val - 1.5).abs() < 1e-6);
598 }
599
600 #[test]
601 fn skip_empty_containers() {
602 assert_eq!(skip_value(&[0x80], 0), Some(1));
604 assert_eq!(skip_value(&[0x90], 0), Some(1));
606 }
607
608 #[test]
609 fn array_header_fixarray() {
610 let buf = encode(&json!([10, 20, 30]));
611 let (count, data_offset) = array_header(&buf, 0).unwrap();
612 assert_eq!(count, 3);
613 assert_eq!(read_i64(&buf, data_offset), Some(10));
614 }
615
616 #[test]
619 fn canonical_integer_smallest_representation() {
620 let buf = encode(&json!(42));
622 assert_eq!(buf.len(), 1);
623 assert_eq!(buf[0], 42);
624
625 let buf = encode(&json!(0));
627 assert_eq!(buf.len(), 1);
628 assert_eq!(buf[0], 0);
629
630 let buf = encode(&json!(127));
632 assert_eq!(buf.len(), 1);
633 assert_eq!(buf[0], 127);
634
635 let buf = encode(&json!(128));
638 assert_eq!(buf[0], 0xd1); assert_eq!(buf.len(), 3); let buf = encode(&json!(-1));
643 assert_eq!(buf.len(), 1);
644 assert_eq!(buf[0], 0xff); let buf = encode(&json!(-32));
647 assert_eq!(buf.len(), 1);
648 assert_eq!(buf[0], 0xe0); }
650
651 #[test]
652 fn canonical_map_keys_sorted() {
653 let buf = encode(&json!({"z": 1, "a": 2, "m": 3}));
656
657 let (count, mut pos) = map_header(&buf, 0).unwrap();
659 assert_eq!(count, 3);
660
661 let mut keys = Vec::new();
662 for _ in 0..count {
663 let key = read_str(&buf, pos).unwrap();
664 keys.push(key.to_string());
665 pos = skip_value(&buf, pos).unwrap(); pos = skip_value(&buf, pos).unwrap(); }
668 assert_eq!(keys, vec!["a", "m", "z"]);
669 }
670
671 #[test]
672 fn canonical_deterministic_bytes() {
673 let doc1 = encode(&json!({"name": "alice", "age": 30, "active": true}));
675 let doc2 = encode(&json!({"age": 30, "active": true, "name": "alice"}));
676 assert_eq!(
677 doc1, doc2,
678 "same logical doc must produce identical msgpack bytes"
679 );
680 }
681
682 #[test]
683 fn canonical_nested_map_keys_sorted() {
684 let buf = encode(&json!({"outer": {"z": 1, "a": 2}}));
685 let (start, _end) = crate::msgpack_scan::field::extract_field(&buf, 0, "outer").unwrap();
687
688 let (count, mut pos) = map_header(&buf, start).unwrap();
689 assert_eq!(count, 2);
690
691 let key1 = read_str(&buf, pos).unwrap();
692 pos = skip_value(&buf, pos).unwrap();
693 pos = skip_value(&buf, pos).unwrap();
694 let key2 = read_str(&buf, pos).unwrap();
695
696 assert_eq!(key1, "a");
697 assert_eq!(key2, "z");
698 }
699
700 #[test]
705 fn fuzz_all_single_byte_sequences() {
706 for byte in 0u8..=255 {
707 let buf = [byte];
708 let _ = skip_value(&buf, 0);
710 let _ = read_f64(&buf, 0);
711 let _ = read_i64(&buf, 0);
712 let _ = read_str(&buf, 0);
713 let _ = read_bool(&buf, 0);
714 let _ = read_null(&buf, 0);
715 let _ = map_header(&buf, 0);
716 let _ = array_header(&buf, 0);
717 let _ = read_value(&buf, 0);
718 }
719 }
720
721 #[test]
723 fn fuzz_two_byte_patterns() {
724 let tags_need_extra: &[u8] = &[
726 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xc4, 0xc5, 0xc6, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, ];
752 for &tag in tags_need_extra {
753 let buf = [tag];
755 let _ = skip_value(&buf, 0);
756 let _ = read_f64(&buf, 0);
757 let _ = read_i64(&buf, 0);
758 let _ = read_value(&buf, 0);
759
760 for second in [0x00u8, 0x01, 0x7f, 0x80, 0xff] {
762 let buf = [tag, second];
763 let _ = skip_value(&buf, 0);
764 let _ = read_f64(&buf, 0);
765 let _ = read_i64(&buf, 0);
766 let _ = read_value(&buf, 0);
767 }
768 }
769 }
770
771 #[test]
773 fn fuzz_deterministic_random_payloads() {
774 let mut state: u64 = 0xdeadbeef_cafebabe;
777 let next = |s: &mut u64| -> u8 {
778 *s = s
779 .wrapping_mul(6364136223846793005)
780 .wrapping_add(1442695040888963407);
781 (*s >> 33) as u8
782 };
783
784 let mut buf = vec![0u8; 256];
785 for _ in 0..2000 {
786 let len = (next(&mut state) as usize % 256) + 1;
788 for b in buf[..len].iter_mut() {
789 *b = next(&mut state);
790 }
791 let slice = &buf[..len];
792
793 for offset in [0, 1, len / 2, len.saturating_sub(1)] {
795 let _ = skip_value(slice, offset);
796 let _ = read_f64(slice, offset);
797 let _ = read_i64(slice, offset);
798 let _ = read_str(slice, offset);
799 let _ = read_bool(slice, offset);
800 let _ = read_null(slice, offset);
801 let _ = map_header(slice, offset);
802 let _ = array_header(slice, offset);
803 let _ = read_value(slice, offset);
804 }
805 }
806 }
807
808 #[test]
811 fn fuzz_truncated_valid_payloads() {
812 let docs = [
813 json!({"key": "value", "num": 42, "flag": true}),
814 json!({"nested": {"a": 1, "b": [1, 2, 3]}}),
815 json!([1, "two", 3.0, null, false]),
816 json!({"large": 9999999999_i64}),
817 json!({"float": 1.23456789}),
818 ];
819
820 for doc in &docs {
821 let full = encode(doc);
822 for truncate_at in 0..full.len() {
824 let slice = &full[..truncate_at];
825 let _ = skip_value(slice, 0);
827 let _ = read_f64(slice, 0);
828 let _ = read_i64(slice, 0);
829 let _ = read_str(slice, 0);
830 let _ = read_bool(slice, 0);
831 let _ = map_header(slice, 0);
832 let _ = array_header(slice, 0);
833 let _ = read_value(slice, 0);
834 }
835 }
836 }
837
838 #[test]
840 fn fuzz_never_used_tag_c1() {
841 let buf = [0xc1u8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
843 assert_eq!(
844 skip_value(&buf, 0),
845 None,
846 "0xc1 must return None from skip_value"
847 );
848 assert_eq!(read_f64(&buf, 0), None);
849 assert_eq!(read_i64(&buf, 0), None);
850 assert_eq!(read_str(&buf, 0), None);
851 assert_eq!(read_bool(&buf, 0), None);
852 assert_eq!(map_header(&buf, 0), None);
853 assert_eq!(array_header(&buf, 0), None);
854 assert_eq!(read_value(&buf, 0), None);
855 }
856
857 #[test]
859 fn fuzz_tag_boundaries() {
860 let boundary_tags: &[(u8, bool)] = &[
864 (0x00, true), (0x7f, true), (0x80, true), (0x8f, false), (0x90, true), (0x9f, false), (0xa0, true), (0xbf, false), (0xc0, true), (0xc1, false), (0xc2, true), (0xc3, true), (0xe0, true), (0xff, true), ];
879 for &(tag, self_contained) in boundary_tags {
880 let buf = [tag; 64]; let result = skip_value(&buf, 0);
882 if self_contained {
883 assert!(result.is_some(), "tag 0x{tag:02x} should skip OK");
884 } else if tag == 0xc1 {
885 assert_eq!(result, None, "0xc1 must always return None");
886 }
887 }
889 }
890
891 #[test]
893 fn fuzz_adversarial_length_fields() {
894 let buf = [0xdbu8, 0xff, 0xff, 0xff, 0xff, b'x', b'y'];
896 assert_eq!(skip_value(&buf, 0), None);
897 assert_eq!(read_str(&buf, 0), None);
898
899 let buf = [0xdau8, 0xff, 0xff, b'x'];
901 assert_eq!(skip_value(&buf, 0), None);
902
903 let buf = [0xddu8, 0xff, 0xff, 0xff, 0xff];
905 assert_eq!(skip_value(&buf, 0), None);
906
907 let buf = [0xdfu8, 0xff, 0xff, 0xff, 0xff];
909 assert_eq!(skip_value(&buf, 0), None);
910
911 let buf = [0xdcu8, 0xff, 0xff];
913 assert_eq!(skip_value(&buf, 0), None);
914
915 let buf = [0xdeu8, 0xff, 0xff];
917 assert_eq!(skip_value(&buf, 0), None);
918
919 let buf = [0xc6u8, 0xff, 0xff, 0xff, 0xff, 0x00];
921 assert_eq!(skip_value(&buf, 0), None);
922
923 let buf = [0xc9u8, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00];
925 assert_eq!(skip_value(&buf, 0), None);
926 }
927
928 #[test]
931 fn fuzz_malicious_nesting_depth() {
932 let depth = 200usize;
935 let mut buf = vec![0x91u8; depth]; buf.push(0xc0u8); assert_eq!(
940 skip_value(&buf, 0),
941 None,
942 "deeply nested arrays must return None to guard against stack overflow"
943 );
944
945 let mut map_buf: Vec<u8> = Vec::new();
948 for i in 0..(depth as u8) {
949 map_buf.push(0x81); map_buf.push(0xa1); map_buf.push(b'a'.wrapping_add(i % 26));
952 }
954 map_buf.push(0xc0); assert_eq!(
957 skip_value(&map_buf, 0),
958 None,
959 "deeply nested maps must return None"
960 );
961 }
962
963 #[test]
966 fn fuzz_fixed_width_numeric_skip_offsets() {
967 let cases: &[(u8, usize)] = &[
969 (0xca, 5), (0xcb, 9), (0xcc, 2), (0xcd, 3), (0xce, 5), (0xcf, 9), (0xd0, 2), (0xd1, 3), (0xd2, 5), (0xd3, 9), ];
980 for &(tag, size) in cases {
981 let mut buf = vec![0u8; size + 4]; buf[0] = tag;
983 let result = skip_value(&buf, 0);
984 assert_eq!(
985 result,
986 Some(size),
987 "tag 0x{tag:02x} should advance by {size} bytes"
988 );
989 }
990 }
991
992 #[test]
994 fn fuzz_fixext_skip_offsets() {
995 let cases: &[(u8, usize)] = &[
997 (0xd4, 3), (0xd5, 4), (0xd6, 6), (0xd7, 10), (0xd8, 18), ];
1003 for &(tag, size) in cases {
1004 let mut buf = vec![0u8; size + 4];
1005 buf[0] = tag;
1006 let result = skip_value(&buf, 0);
1007 assert_eq!(
1008 result,
1009 Some(size),
1010 "fixext tag 0x{tag:02x} should advance by {size} bytes"
1011 );
1012 }
1013 }
1014
1015 #[test]
1017 fn fuzz_out_of_bounds_offset() {
1018 let buf = encode(&json!({"x": 1}));
1019 let way_out = buf.len() + 1000;
1020 assert_eq!(skip_value(&buf, way_out), None);
1021 assert_eq!(read_f64(&buf, way_out), None);
1022 assert_eq!(read_i64(&buf, way_out), None);
1023 assert_eq!(read_str(&buf, way_out), None);
1024 assert_eq!(read_bool(&buf, way_out), None);
1025 assert_eq!(map_header(&buf, way_out), None);
1026 assert_eq!(array_header(&buf, way_out), None);
1027 assert_eq!(read_value(&buf, way_out), None);
1028 }
1029
1030 #[test]
1031 fn read_bin_advance_all_widths() {
1032 let mut off = 0;
1034 let buf = [BIN8, 3, 0xde, 0xad, 0xbe, 0xff];
1035 assert_eq!(
1036 read_bin_advance(&buf, &mut off),
1037 Some(&[0xde, 0xad, 0xbe][..])
1038 );
1039 assert_eq!(off, 5);
1040
1041 let mut off = 0;
1043 let buf = [BIN16, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04];
1044 assert_eq!(
1045 read_bin_advance(&buf, &mut off),
1046 Some(&[0x01, 0x02, 0x03, 0x04][..])
1047 );
1048 assert_eq!(off, 7);
1049
1050 let mut off = 0;
1052 let buf = [BIN32, 0x00, 0x00, 0x00, 0x02, 0xaa, 0xbb];
1053 assert_eq!(read_bin_advance(&buf, &mut off), Some(&[0xaa, 0xbb][..]));
1054 assert_eq!(off, 7);
1055
1056 let mut off = 0;
1058 let buf = [0xc0u8]; assert_eq!(read_bin_advance(&buf, &mut off), None);
1060 assert_eq!(off, 0);
1061
1062 let mut off = 0;
1064 let buf = [BIN8, 5, 0x01]; assert_eq!(read_bin_advance(&buf, &mut off), None);
1066 }
1067
1068 #[test]
1069 fn read_u32_advance_all_widths() {
1070 let mut off = 0;
1072 assert_eq!(read_u32_advance(&[42u8], &mut off), Some(42));
1073 assert_eq!(off, 1);
1074
1075 let mut off = 0;
1077 assert_eq!(read_u32_advance(&[UINT8, 200], &mut off), Some(200));
1078 assert_eq!(off, 2);
1079
1080 let mut off = 0;
1082 let buf = [UINT16, 0x12, 0x34];
1083 assert_eq!(read_u32_advance(&buf, &mut off), Some(0x1234));
1084 assert_eq!(off, 3);
1085
1086 let mut off = 0;
1088 let buf = [UINT32, 0xde, 0xad, 0xbe, 0xef];
1089 assert_eq!(read_u32_advance(&buf, &mut off), Some(0xdeadbeef));
1090 assert_eq!(off, 5);
1091
1092 let mut off = 0;
1094 assert_eq!(read_u32_advance(&[0xffu8], &mut off), None); assert_eq!(off, 0);
1096 let mut off = 0;
1097 assert_eq!(read_u32_advance(&[INT8, 5], &mut off), None);
1098 let mut off = 0;
1099 assert_eq!(
1100 read_u32_advance(&[UINT64, 0, 0, 0, 0, 0, 0, 0, 1], &mut off),
1101 None
1102 );
1103
1104 let mut off = 0;
1106 assert_eq!(read_u32_advance(&[UINT16, 0x12], &mut off), None);
1107 }
1108
1109 #[test]
1110 fn read_str_advance_basic() {
1111 let mut off = 0;
1113 let buf = encode(&json!("hi"));
1114 assert_eq!(read_str_advance(&buf, &mut off), Some("hi"));
1115 assert_eq!(off, buf.len());
1116
1117 let buf = encode(&json!(["one", "two"]));
1119 let (count, mut off) = array_header(&buf, 0).unwrap();
1120 assert_eq!(count, 2);
1121 assert_eq!(read_str_advance(&buf, &mut off), Some("one"));
1122 assert_eq!(read_str_advance(&buf, &mut off), Some("two"));
1123 assert_eq!(off, buf.len());
1124
1125 let mut off = 0;
1127 assert_eq!(read_str_advance(&[NIL], &mut off), None);
1128 assert_eq!(off, 0);
1129 }
1130
1131 #[test]
1133 fn fuzz_empty_buffer() {
1134 let buf: &[u8] = &[];
1135 assert_eq!(skip_value(buf, 0), None);
1136 assert_eq!(read_f64(buf, 0), None);
1137 assert_eq!(read_i64(buf, 0), None);
1138 assert_eq!(read_str(buf, 0), None);
1139 assert_eq!(read_bool(buf, 0), None);
1140 assert!(!read_null(buf, 0)); assert_eq!(map_header(buf, 0), None);
1142 assert_eq!(array_header(buf, 0), None);
1143 assert_eq!(read_value(buf, 0), None);
1144 }
1145}