pub fn check_msgpack_structure(
bytes: &[u8],
max_depth: usize,
) -> Result<(), MsgpackStructureError>Expand description
Checks that bytes hold one MessagePack document whose declared structure
the input can actually back, before any decoder sees them.
A header-only walk: str/bin/ext payloads are skipped by offset, never read,
and nothing is decoded. It keeps one u64 per open non-empty collection, so
at most min(max_depth, bytes.len()) of them (8 KiB at a depth of 1024), and
allocates nothing proportional to any declared length.
Trailing bytes after the root element are left to the decoder.
max_depth is the caller’s bound. The protocol (spec/interop-mode.md →
Decode bounds) requires one in 32..=1024; this function does not enforce
that range and applies whatever value it is given.
§Errors
Returns a MsgpackStructureError naming the violated bound. It rejects:
- nesting deeper than
max_depth, counting every array or map header on the path (an empty one included); - a header declaring more payload bytes than the input holds;
- more pending elements (across every open collection) than the remaining
bytes can back. Every element costs at least one byte, so a decoder’s
total container pre-allocation is bounded by the input length rather
than by
depth × declared length; - the reserved marker
0xc1, and input that ends mid-document.
§Examples
use cachekit_core::check_msgpack_structure;
// [[[]]]: three levels, because the empty innermost array counts as one.
let doc = [0x91, 0x91, 0x90];
assert_eq!(check_msgpack_structure(&doc, 3), Ok(()));
assert_eq!(
check_msgpack_structure(&doc, 2).unwrap_err().to_string(),
"nests deeper than 2 levels"
);
// An array32 header claiming 2^32 - 1 elements, in five bytes.
assert_eq!(
check_msgpack_structure(&[0xdd, 0xff, 0xff, 0xff, 0xff], 100)
.unwrap_err()
.to_string(),
"declares more elements than the input can back"
);