use crate::error::{LaurusError, Result};
pub(crate) fn checked_capacity(
count: usize,
min_stride: u64,
available: u64,
what: &str,
) -> Result<usize> {
let stride = min_stride.max(1);
let max_elements = available / stride;
if count as u64 > max_elements {
return Err(LaurusError::index(format!(
"{what}: header declares {count} elements but at most {max_elements} can fit in the \
{available} bytes left in the file — vector segment is corrupted"
)));
}
Ok(count)
}
pub(crate) fn checked_len(len: usize, available: u64, what: &str) -> Result<usize> {
if len as u64 > available {
return Err(LaurusError::index(format!(
"{what}: header declares {len} bytes but only {available} bytes are left in the file \
— vector segment is corrupted"
)));
}
Ok(len)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn checked_capacity_accepts_a_count_that_fits() {
assert_eq!(checked_capacity(10, 4, 40, "n").unwrap(), 10);
}
#[test]
fn checked_capacity_accepts_exact_fit() {
assert_eq!(checked_capacity(5, 8, 40, "n").unwrap(), 5);
}
#[test]
fn checked_capacity_rejects_a_count_that_overflows_the_file() {
let err = checked_capacity(1usize << 40, 8, 64, "num_vectors").unwrap_err();
match err {
LaurusError::Index(msg) => {
assert!(msg.contains("num_vectors"), "message should name the count");
assert!(msg.contains("corrupted"), "message should flag corruption");
}
other => panic!("expected Index error, got {other:?}"),
}
}
#[test]
fn checked_capacity_treats_zero_stride_as_one() {
assert!(checked_capacity(64, 0, 64, "n").is_ok());
assert!(checked_capacity(65, 0, 64, "n").is_err());
}
#[test]
fn checked_len_accepts_a_length_that_fits() {
assert_eq!(checked_len(16, 16, "field_name_len").unwrap(), 16);
assert_eq!(checked_len(0, 16, "field_name_len").unwrap(), 0);
}
#[test]
fn checked_len_rejects_a_length_beyond_the_file() {
let err = checked_len(1usize << 31, 16, "field_name_len").unwrap_err();
match err {
LaurusError::Index(msg) => {
assert!(msg.contains("field_name_len"));
assert!(msg.contains("corrupted"));
}
other => panic!("expected Index error, got {other:?}"),
}
}
}