pub fn prefix_upper_bound(prefix: &[u8]) -> Option<Vec<u8>> {
let mut up = prefix.to_vec();
while let Some(&0xFF) = up.last() {
up.pop();
}
if up.is_empty() {
return None;
}
let last = up
.last_mut()
.expect("invariant: non-empty after stripping 0xFF tail");
*last = last
.checked_add(1)
.expect("invariant: last byte is not 0xFF (stripped above)");
Some(up)
}
pub fn prefix_overlaps_range(prefix: &[u8], min_term: &[u8], max_term: &[u8]) -> bool {
if prefix.is_empty() {
return true;
}
if max_term < prefix {
return false;
}
match prefix_upper_bound(prefix) {
None => true,
Some(upper) => min_term < upper.as_slice(),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn upper_bound_of_simple_ascii_prefix() {
assert_eq!(prefix_upper_bound(b"err"), Some(b"ers".to_vec()));
assert_eq!(prefix_upper_bound(b"a"), Some(b"b".to_vec()));
assert_eq!(prefix_upper_bound(b"abc"), Some(b"abd".to_vec()));
}
#[test]
fn upper_bound_increments_last_byte_only() {
assert_eq!(prefix_upper_bound(b"erz"), Some(b"er{".to_vec()));
}
#[test]
fn upper_bound_of_empty_prefix_is_none() {
assert_eq!(prefix_upper_bound(b""), None);
}
#[test]
fn upper_bound_of_all_ff_prefix_is_none() {
assert_eq!(prefix_upper_bound(&[0xFF]), None);
assert_eq!(prefix_upper_bound(&[0xFF, 0xFF, 0xFF]), None);
}
#[test]
fn upper_bound_strips_trailing_ff_then_increments() {
assert_eq!(prefix_upper_bound(&[0xFE, 0xFF, 0xFF]), Some(vec![0xFF]),);
assert_eq!(prefix_upper_bound(&[0x10, 0xFF]), Some(vec![0x11]));
assert_eq!(prefix_upper_bound(&[b'a', 0xFF, 0xFF]), Some(b"b".to_vec()),);
}
#[test]
fn upper_bound_at_byte_boundary() {
assert_eq!(prefix_upper_bound(&[0x7E]), Some(vec![0x7F]));
assert_eq!(prefix_upper_bound(&[0xFE]), Some(vec![0xFF]));
}
#[test]
fn upper_bound_is_strictly_greater_than_prefix() {
let cases: &[&[u8]] = &[
b"a",
b"ab",
b"abc",
b"err",
&[0x00],
&[0x10, 0x20, 0x30],
&[0xFE],
&[0xFE, 0xFF],
&[0x10, 0xFF],
];
for p in cases {
let up = prefix_upper_bound(p)
.unwrap_or_else(|| panic!("{:?} should have an upper bound", p));
assert!(
up.as_slice() > *p,
"upper bound {:?} not > prefix {:?}",
up,
p,
);
}
}
#[test]
fn upper_bound_excludes_strings_starting_with_prefix() {
let p = b"err";
let up = prefix_upper_bound(p).expect("has upper");
let with_prefix: &[&[u8]] = &[
b"err",
b"err\0",
b"errand",
b"erratic",
b"errz",
b"err\xFF",
b"err\xFF\xFF\xFF",
];
for s in with_prefix {
let s_bytes: &[u8] = s;
assert!(
s_bytes < up.as_slice(),
"{:?} (starting with prefix) should be < upper {:?}",
s,
up,
);
}
}
#[test]
fn empty_prefix_overlaps_any_range() {
assert!(prefix_overlaps_range(b"", b"alpha", b"omega"));
assert!(prefix_overlaps_range(b"", b"\x00", b"\xFF"));
assert!(prefix_overlaps_range(b"", b"x", b"x"));
}
#[test]
fn prefix_inside_range_overlaps() {
assert!(prefix_overlaps_range(b"check", b"checkin", b"checkout"));
assert!(prefix_overlaps_range(b"err", b"errand", b"errand"));
}
#[test]
fn prefix_above_max_term_does_not_overlap() {
assert!(!prefix_overlaps_range(b"beta", b"a", b"alpha"));
assert!(!prefix_overlaps_range(b"zzz", b"a", b"y"));
}
#[test]
fn prefix_below_min_term_does_not_overlap() {
assert!(!prefix_overlaps_range(b"a", b"g", b"z"));
assert!(!prefix_overlaps_range(b"abc", b"def", b"xyz"));
}
#[test]
fn prefix_equals_min_term_overlaps() {
assert!(prefix_overlaps_range(b"err", b"err", b"erz"));
}
#[test]
fn prefix_equals_max_term_overlaps() {
assert!(prefix_overlaps_range(b"err", b"a", b"err"));
}
#[test]
fn all_ff_prefix_overlaps_when_max_is_at_least_prefix() {
assert!(prefix_overlaps_range(&[0xFF], &[0xFF], &[0xFF]));
assert!(prefix_overlaps_range(&[0xFF], &[0x80], &[0xFF, 0xFF]));
assert!(!prefix_overlaps_range(&[0xFF], &[0x00], &[0xFE]));
}
#[test]
fn prefix_overlap_property_no_false_negatives() {
let prefix = b"err";
let cases: &[(&[u8], &[u8], &[u8])] = &[
(b"err", b"err", b"err"),
(b"err", b"errand", b"err"),
(b"err", b"errand", b"errand"),
(b"epsilon", b"errand", b"errand"),
(b"epsilon", b"zeta", b"errand"),
(b"era", b"errz", b"errand"),
(b"era", b"err", b"err"),
(b"e", b"f", b"errand"),
];
for (min, max, planted) in cases {
assert!(planted.starts_with(prefix), "test setup broken");
assert!(
min <= planted && planted <= max,
"test setup broken: planted {:?} not in [{:?}, {:?}]",
planted,
min,
max,
);
assert!(
prefix_overlaps_range(prefix, min, max),
"false negative for [{:?}, {:?}], planted {:?}",
min,
max,
planted,
);
}
}
#[test]
fn prefix_overlap_handles_trailing_ff_in_prefix() {
let p = &[0xFE, 0xFF, 0xFF];
assert!(prefix_overlaps_range(
p,
&[0xFE, 0xFF, 0xFF],
&[0xFE, 0xFF, 0xFF],
));
assert!(prefix_overlaps_range(p, &[0xFE, 0x00], &[0xFE, 0xFF, 0xFF]));
assert!(!prefix_overlaps_range(
p,
&[0xFE, 0x00],
&[0xFE, 0xFE, 0xFF]
));
assert!(!prefix_overlaps_range(p, &[0xFF], &[0xFF, 0xFF]));
}
}