use crate::imp::chunker::gear::gear_roll;
use crate::imp::core::ChunkerConfig;
pub fn find_boundary(data: &[u8], start: usize, cfg: &ChunkerConfig) -> usize {
let len = data.len();
debug_assert!(start <= len);
let remaining = len - start;
if remaining <= cfg.min_size {
return len;
}
let max_end = (start + cfg.max_size).min(len);
let min_end = start + cfg.min_size;
let mut hash: u64 = 0;
let mut i = start;
while i < max_end {
hash = gear_roll(hash, data[i]);
i += 1;
if i >= min_end && (hash & cfg.mask) == 0 {
return i;
}
}
max_end
}
#[cfg(all(test, not(target_arch = "wasm32")))]
mod tests {
use super::*;
use crate::imp::core::ChunkerConfig;
fn cfg(min: usize, target: usize, max: usize, mask: u64) -> ChunkerConfig {
ChunkerConfig {
min_size: min,
target_size: target,
max_size: max,
mask,
}
}
#[test]
fn boundary_never_cuts_before_min_size() {
let data = vec![0u8; 1000];
let c = cfg(100, 200, 400, 0);
assert_eq!(find_boundary(&data, 0, &c), 100);
}
#[test]
fn boundary_forces_cut_at_max_size() {
let data = vec![0xAAu8; 1000];
let c = cfg(100, 200, 400, u64::MAX);
assert_eq!(find_boundary(&data, 0, &c), 400);
}
#[test]
fn boundary_respects_start_offset() {
let data = vec![0u8; 1000];
let c = cfg(100, 200, 400, 0);
assert_eq!(find_boundary(&data, 250, &c), 350);
}
#[test]
fn boundary_returns_end_when_remainder_at_or_below_min() {
let data = vec![0u8; 1000];
let c = cfg(100, 200, 400, 0);
assert_eq!(find_boundary(&data, 960, &c), 1000);
}
#[test]
fn boundary_returns_end_for_input_shorter_than_min() {
let data = vec![0u8; 30];
let c = cfg(100, 200, 400, 0);
assert_eq!(find_boundary(&data, 0, &c), 30);
}
#[test]
fn boundary_cuts_within_bounds_on_real_hash_match() {
let data: Vec<u8> = (0..1000u32)
.map(|i| (i.wrapping_mul(31) ^ 7) as u8)
.collect();
let c = cfg(100, 200, 400, 0x1);
let b = find_boundary(&data, 0, &c);
assert!(
(100..=400).contains(&b),
"boundary {b} must be within [min,max]"
);
assert_eq!(b, find_boundary(&data, 0, &c));
}
}