use std::cmp::Ordering;
use std::marker::PhantomData;
use crate::Error;
use crate::optimised::indexed::seq_walk::FLAG_INDEXED;
use crate::optimised::validation::{validate_key_region_ascending, validate_map_prologue};
#[derive(Debug)]
pub struct IndexedMapWalker<'p, K, V> {
body: &'p [u8],
prologue: Option<MapPrologue<'p>>,
len: usize,
_marker: PhantomData<fn() -> (K, V)>,
}
#[derive(Debug, Clone, Copy)]
pub struct HintedLookup<'p> {
pub value: Option<&'p [u8]>,
pub hint: Option<u32>,
}
#[derive(Debug)]
struct MapPrologue<'p> {
offset_table: &'p [u8],
keys_region: &'p [u8],
vals_region: &'p [u8],
}
impl<'p> MapPrologue<'p> {
#[inline]
fn key_off(&self, index: usize) -> u32 {
crate::optimised::validation::decode_u32_le_at(self.offset_table, index * 8)
}
#[inline]
fn val_off(&self, index: usize) -> u32 {
crate::optimised::validation::decode_u32_le_at(self.offset_table, index * 8 + 4)
}
#[inline]
fn entry_ranges(
&self,
n: usize,
index: usize,
) -> Option<(std::ops::Range<usize>, std::ops::Range<usize>)> {
if index >= n {
return None;
}
let k_start = self.key_off(index) as usize;
let v_start = self.val_off(index) as usize;
let (k_end, v_end) = if index + 1 < n {
(self.key_off(index + 1) as usize, self.val_off(index + 1) as usize)
} else {
(self.keys_region.len(), self.vals_region.len())
};
Some((k_start..k_end, v_start..v_end))
}
}
impl<'p, K, V> IndexedMapWalker<'p, K, V> {
pub fn from_payload(payload: &'p [u8]) -> Result<Self, Error> {
Self::from_payload_inner(payload, true)
}
pub fn from_payload_unvalidated(payload: &'p [u8]) -> Result<Self, Error> {
Self::from_payload_inner(payload, false)
}
fn from_payload_inner(payload: &'p [u8], validate: bool) -> Result<Self, Error> {
if payload.is_empty() {
return Err(Error::OptimisedSubReaderOverrun);
}
let flags = payload[0];
let mut cursor = 1usize;
let (len, varint_bytes) = read_varint(&payload[cursor..])?;
cursor += varint_bytes;
let indexed = (flags & FLAG_INDEXED) != 0;
if !indexed {
return Ok(Self {
body: &payload[cursor..],
prologue: None,
len,
_marker: PhantomData,
});
}
let table_bytes = len
.checked_mul(8)
.ok_or_else(|| Error::Deserialize("indexed-map offset table size overflow".into()))?;
if payload.len() < cursor + table_bytes {
return Err(Error::OptimisedSubReaderOverrun);
}
let offset_table = &payload[cursor..cursor + table_bytes];
cursor += table_bytes;
if payload.len() < cursor + 8 {
return Err(Error::OptimisedSubReaderOverrun);
}
let keys_region_len =
u32::from_le_bytes(payload[cursor..cursor + 4].try_into().unwrap()) as usize;
cursor += 4;
let vals_region_len =
u32::from_le_bytes(payload[cursor..cursor + 4].try_into().unwrap()) as usize;
cursor += 4;
if payload.len() < cursor + keys_region_len + vals_region_len {
return Err(Error::OptimisedSubReaderOverrun);
}
let keys_region = &payload[cursor..cursor + keys_region_len];
cursor += keys_region_len;
let vals_region = &payload[cursor..cursor + vals_region_len];
if validate {
validate_map_prologue(
offset_table,
len,
keys_region_len as u32,
vals_region_len as u32,
)?;
validate_key_region_ascending(keys_region, offset_table, len)?;
}
Ok(Self {
body: &payload[1 + varint_bytes..],
prologue: Some(MapPrologue {
offset_table,
keys_region,
vals_region,
}),
len,
_marker: PhantomData,
})
}
#[inline]
pub fn len(&self) -> usize {
self.len
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}
#[inline]
pub fn is_indexed(&self) -> bool {
self.prologue.is_some()
}
pub fn entries(&self) -> Option<impl Iterator<Item = (&'p [u8], &'p [u8])> + '_> {
let p = self.prologue.as_ref()?;
let keys = p.keys_region;
let vals = p.vals_region;
let n = self.len;
let (mut k_start, mut v_start) = if n > 0 {
(p.key_off(0) as usize, p.val_off(0) as usize)
} else {
(0, 0)
};
Some((0..n).map(move |i| {
let (k_end, v_end) = if i + 1 < n {
(p.key_off(i + 1) as usize, p.val_off(i + 1) as usize)
} else {
(keys.len(), vals.len())
};
let entry = (
keys.get(k_start..k_end).unwrap_or_default(),
vals.get(v_start..v_end).unwrap_or_default(),
);
k_start = k_end;
v_start = v_end;
entry
}))
}
pub fn find_value_bytes<F>(&self, predicate: F) -> Result<Option<&'p [u8]>, Error>
where
F: FnMut(&[u8]) -> Ordering,
{
let Some(p) = &self.prologue else {
return Err(Error::Deserialize("find_value_bytes called on non-indexed map".into()));
};
Ok(Self::binary_search_entry(p, self.len, predicate)?.map(|(value, _index)| value))
}
pub fn find_value_bytes_with_hint<F>(
&self,
hint: Option<u32>,
mut predicate: F,
) -> Result<HintedLookup<'p>, Error>
where
F: FnMut(&[u8]) -> Ordering,
{
let Some(p) = &self.prologue else {
return Err(Error::Deserialize(
"find_value_bytes_with_hint called on non-indexed map".into(),
));
};
let n = self.len;
if let Some(h) = hint
&& let Some((k_range, v_range)) = p.entry_ranges(n, h as usize)
&& let Some(key_bytes) = p.keys_region.get(k_range)
&& predicate(key_bytes) == Ordering::Equal
&& let Some(value_bytes) = p.vals_region.get(v_range)
{
return Ok(HintedLookup {
value: Some(value_bytes),
hint: Some(h),
});
}
Ok(match Self::binary_search_entry(p, n, predicate)? {
Some((value, index)) => HintedLookup {
value: Some(value),
hint: Some(index),
},
None => HintedLookup {
value: None,
hint,
},
})
}
fn binary_search_entry<F>(
p: &MapPrologue<'p>,
n: usize,
mut predicate: F,
) -> Result<Option<(&'p [u8], u32)>, Error>
where
F: FnMut(&[u8]) -> Ordering,
{
let mut lo = 0usize;
let mut hi = n;
while lo < hi {
let mid = lo + (hi - lo) / 2;
let (k_range, v_range) =
p.entry_ranges(n, mid).expect("mid is within [0, n) by loop invariant");
let Some(key_bytes) = p.keys_region.get(k_range.clone()) else {
return Err(Error::OptimisedOffsetOutOfRange {
offset: k_range.end as u32,
payload_len: p.keys_region.len() as u32,
});
};
match predicate(key_bytes) {
Ordering::Equal => {
let Some(value_bytes) = p.vals_region.get(v_range.clone()) else {
return Err(Error::OptimisedOffsetOutOfRange {
offset: v_range.end as u32,
payload_len: p.vals_region.len() as u32,
});
};
return Ok(Some((value_bytes, mid as u32)));
}
Ordering::Less => lo = mid + 1,
Ordering::Greater => hi = mid,
}
}
Ok(None)
}
#[inline]
pub fn legacy_body(&self) -> Option<&'p [u8]> {
if self.prologue.is_some() {
None
} else {
Some(self.body)
}
}
}
fn read_varint(bytes: &[u8]) -> Result<(usize, usize), Error> {
if bytes.is_empty() {
return Err(Error::OptimisedSubReaderOverrun);
}
let tag = bytes[0];
match tag {
0..=250 => Ok((tag as usize, 1)),
251 => {
if bytes.len() < 3 {
return Err(Error::OptimisedSubReaderOverrun);
}
Ok((u16::from_le_bytes([bytes[1], bytes[2]]) as usize, 3))
}
252 => {
if bytes.len() < 5 {
return Err(Error::OptimisedSubReaderOverrun);
}
Ok((u32::from_le_bytes(bytes[1..5].try_into().unwrap()) as usize, 5))
}
253 => {
if bytes.len() < 9 {
return Err(Error::OptimisedSubReaderOverrun);
}
let v = u64::from_le_bytes(bytes[1..9].try_into().unwrap());
let v: usize = v.try_into().map_err(|_| Error::IntegerOverflow)?;
Ok((v, 9))
}
_ => Err(Error::InvalidIntegerEncoding),
}
}
#[cfg(test)]
mod tests {
use super::*;
fn varint(v: usize) -> Vec<u8> {
match v {
0..=250 => vec![v as u8],
251..=65535 => {
let mut out = vec![251u8];
out.extend_from_slice(&(v as u16).to_le_bytes());
out
}
_ => {
let mut out = vec![252u8];
out.extend_from_slice(&(v as u32).to_le_bytes());
out
}
}
}
fn build_indexed_map(entries: &[(&[u8], &[u8])]) -> Vec<u8> {
let mut sorted: Vec<(&[u8], &[u8])> = entries.to_vec();
sorted.sort_by(|a, b| a.0.cmp(b.0));
let n = sorted.len();
let mut out = Vec::new();
out.push(FLAG_INDEXED);
out.extend_from_slice(&varint(n));
let mut k_off = 0u32;
let mut v_off = 0u32;
let mut k_offsets = Vec::with_capacity(n);
let mut v_offsets = Vec::with_capacity(n);
for (k, v) in &sorted {
k_offsets.push(k_off);
v_offsets.push(v_off);
k_off += k.len() as u32;
v_off += v.len() as u32;
}
for i in 0..n {
out.extend_from_slice(&k_offsets[i].to_le_bytes());
out.extend_from_slice(&v_offsets[i].to_le_bytes());
}
out.extend_from_slice(&k_off.to_le_bytes());
out.extend_from_slice(&v_off.to_le_bytes());
for (k, _) in &sorted {
out.extend_from_slice(k);
}
for (_, v) in &sorted {
out.extend_from_slice(v);
}
out
}
#[test]
fn opens_indexed_map_and_finds_keys() {
let payload = build_indexed_map(&[(b"foo", b"42"), (b"bar", b"7"), (b"baz", b"99")]);
let w: IndexedMapWalker<(), ()> = IndexedMapWalker::from_payload(&payload).unwrap();
assert_eq!(w.len(), 3);
assert!(w.is_indexed());
let found = w.find_value_bytes(|k| k.cmp(b"baz".as_slice())).unwrap().unwrap();
assert_eq!(found, b"99");
let found = w.find_value_bytes(|k| k.cmp(b"foo".as_slice())).unwrap().unwrap();
assert_eq!(found, b"42");
assert!(w.find_value_bytes(|k| k.cmp(b"missing".as_slice())).unwrap().is_none());
}
#[test]
fn iter_returns_pairs_in_sorted_order() {
let payload = build_indexed_map(&[(b"x", b"3"), (b"a", b"1"), (b"m", b"2")]);
let w: IndexedMapWalker<(), ()> = IndexedMapWalker::from_payload(&payload).unwrap();
let collected: Vec<(&[u8], &[u8])> = w.entries().unwrap().collect();
assert_eq!(
collected,
vec![
(b"a".as_slice(), b"1".as_slice()),
(b"m".as_slice(), b"2".as_slice()),
(b"x".as_slice(), b"3".as_slice())
]
);
}
#[test]
fn legacy_map_passes_through() {
let payload = [0u8, 2, 0xAA, 0xBB];
let w: IndexedMapWalker<(), ()> = IndexedMapWalker::from_payload(&payload).unwrap();
assert!(!w.is_indexed());
assert_eq!(w.len(), 2);
assert_eq!(w.legacy_body().unwrap(), &[0xAA, 0xBB]);
assert!(
w.find_value_bytes(|_| Ordering::Equal).is_err(),
"find_value_bytes errors on legacy path"
);
}
fn corrupt_key_off(payload: &mut [u8], entry: usize, value: u32) {
let at = 2 + entry * 8;
payload[at..at + 4].copy_from_slice(&value.to_le_bytes());
}
#[test]
fn validated_rejects_out_of_range_offset_at_construction() {
let mut payload = build_indexed_map(&[(b"bar", b"7"), (b"baz", b"99"), (b"foo", b"42")]);
corrupt_key_off(&mut payload, 1, u32::MAX);
assert!(
IndexedMapWalker::<(), ()>::from_payload(&payload).is_err(),
"validating constructor must reject a key offset past the region"
);
}
#[test]
fn unvalidated_find_value_bytes_errors_instead_of_panicking() {
let mut payload = build_indexed_map(&[(b"bar", b"7"), (b"baz", b"99"), (b"foo", b"42")]);
corrupt_key_off(&mut payload, 1, u32::MAX);
let w: IndexedMapWalker<(), ()> =
IndexedMapWalker::from_payload_unvalidated(&payload).unwrap();
assert!(matches!(
w.find_value_bytes(|k| k.cmp(b"baz".as_slice())),
Err(Error::OptimisedOffsetOutOfRange { .. })
));
}
#[test]
fn unvalidated_entries_clamp_corrupt_offset_without_panicking() {
let mut payload = build_indexed_map(&[(b"bar", b"7"), (b"baz", b"99"), (b"foo", b"42")]);
corrupt_key_off(&mut payload, 1, u32::MAX);
let w: IndexedMapWalker<(), ()> =
IndexedMapWalker::from_payload_unvalidated(&payload).unwrap();
let collected: Vec<(&[u8], &[u8])> = w.entries().unwrap().collect();
assert_eq!(collected.len(), 3);
assert!(collected.iter().any(|(k, _)| k.is_empty()));
}
fn three_entry_map() -> Vec<u8> {
build_indexed_map(&[(b"bar", b"7"), (b"baz", b"99"), (b"foo", b"42")])
}
#[test]
fn hinted_lookup_hits_on_correct_hint() {
let payload = three_entry_map();
let w: IndexedMapWalker<(), ()> = IndexedMapWalker::from_payload(&payload).unwrap();
let first = w.find_value_bytes_with_hint(None, |k| k.cmp(b"baz".as_slice())).unwrap();
assert_eq!(first.value, Some(b"99".as_slice()));
assert_eq!(first.hint, Some(1));
let second =
w.find_value_bytes_with_hint(first.hint, |k| k.cmp(b"baz".as_slice())).unwrap();
assert_eq!(second.value, Some(b"99".as_slice()));
assert_eq!(second.hint, Some(1));
}
#[test]
fn hinted_lookup_self_corrects_on_wrong_hint() {
let payload = three_entry_map();
let w: IndexedMapWalker<(), ()> = IndexedMapWalker::from_payload(&payload).unwrap();
let out = w.find_value_bytes_with_hint(Some(0), |k| k.cmp(b"foo".as_slice())).unwrap();
assert_eq!(out.value, Some(b"42".as_slice()));
assert_eq!(out.hint, Some(2), "a wrong hint must self-correct to the real slot");
}
#[test]
fn hinted_lookup_preserves_prior_hint_on_miss() {
let payload = three_entry_map();
let w: IndexedMapWalker<(), ()> = IndexedMapWalker::from_payload(&payload).unwrap();
let out = w.find_value_bytes_with_hint(Some(1), |k| k.cmp(b"missing".as_slice())).unwrap();
assert_eq!(out.value, None);
assert_eq!(out.hint, Some(1), "a genuine miss must carry the old hint forward unchanged");
}
#[test]
fn hinted_lookup_falls_through_on_out_of_range_hint() {
let payload = three_entry_map();
let w: IndexedMapWalker<(), ()> = IndexedMapWalker::from_payload(&payload).unwrap();
let out = w.find_value_bytes_with_hint(Some(50), |k| k.cmp(b"foo".as_slice())).unwrap();
assert_eq!(out.value, Some(b"42".as_slice()));
assert_eq!(out.hint, Some(2));
}
#[test]
fn hinted_lookup_no_hint_matches_plain_binary_search() {
let payload = three_entry_map();
let w: IndexedMapWalker<(), ()> = IndexedMapWalker::from_payload(&payload).unwrap();
let plain = w.find_value_bytes(|k| k.cmp(b"bar".as_slice())).unwrap();
let hinted = w.find_value_bytes_with_hint(None, |k| k.cmp(b"bar".as_slice())).unwrap();
assert_eq!(hinted.value, plain);
assert_eq!(hinted.hint, Some(0));
}
#[test]
fn hinted_lookup_on_legacy_map_errors() {
let payload = [0u8, 2, 0xAA, 0xBB];
let w: IndexedMapWalker<(), ()> = IndexedMapWalker::from_payload(&payload).unwrap();
assert!(w.find_value_bytes_with_hint(None, |_| Ordering::Equal).is_err());
}
#[test]
fn hinted_lookup_on_unvalidated_map_ignores_corrupt_key_at_hinted_slot() {
let mut payload = three_entry_map();
corrupt_key_off(&mut payload, 1, u32::MAX);
let w: IndexedMapWalker<(), ()> =
IndexedMapWalker::from_payload_unvalidated(&payload).unwrap();
assert!(matches!(
w.find_value_bytes_with_hint(Some(1), |k| k.cmp(b"foo".as_slice())),
Err(Error::OptimisedOffsetOutOfRange { .. })
));
}
#[test]
fn hinted_lookup_on_unvalidated_map_recovers_via_hint_when_search_would_hit_corruption() {
let mut payload = three_entry_map();
corrupt_key_off(&mut payload, 1, u32::MAX);
let w: IndexedMapWalker<(), ()> =
IndexedMapWalker::from_payload_unvalidated(&payload).unwrap();
let out = w.find_value_bytes_with_hint(Some(2), |k| k.cmp(b"foo".as_slice())).unwrap();
assert_eq!(out.value, Some(b"42".as_slice()));
assert_eq!(out.hint, Some(2));
}
}