use beamr::term::Term;
use super::error::RuntimeError;
const FNV_OFFSET_BASIS: u64 = 0xcbf2_9ce4_8422_2325;
const FNV_PRIME: u64 = 0x0000_0100_0000_01b3;
pub fn mailbox_integer(bytes: &[u8], reserved_below: i64) -> Result<i64, RuntimeError> {
let max = Term::SMALL_INT_MAX;
let refusal = RuntimeError::MailboxReservedRangeInvalid {
reserved_below,
max,
};
if !(0..=max).contains(&reserved_below) {
return Err(refusal);
}
let mut fold = FNV_OFFSET_BASIS;
for byte in bytes {
fold ^= u64::from(*byte);
fold = fold.wrapping_mul(FNV_PRIME);
}
let Ok(span) = u64::try_from(max - reserved_below) else {
return Err(refusal);
};
let Some(size) = span.checked_add(1) else {
return Err(refusal);
};
let Ok(offset) = i64::try_from(fold % size) else {
return Err(refusal);
};
let Some(value) = reserved_below.checked_add(offset) else {
return Err(refusal);
};
Ok(value)
}
#[cfg(test)]
mod tests {
use super::{FNV_OFFSET_BASIS, FNV_PRIME, mailbox_integer};
use beamr::term::Term;
#[test]
fn empty_input_folds_the_offset_basis_into_the_full_domain()
-> Result<(), Box<dyn std::error::Error>> {
let size = u64::try_from(Term::SMALL_INT_MAX)?
.checked_add(1)
.ok_or("size overflow")?;
assert_eq!(
mailbox_integer(b"", 0)?,
i64::try_from(FNV_OFFSET_BASIS % size)?
);
Ok(())
}
#[test]
fn single_byte_matches_the_fnv1a_step() -> Result<(), Box<dyn std::error::Error>> {
let folded = (FNV_OFFSET_BASIS ^ u64::from(b'x')).wrapping_mul(FNV_PRIME);
let size = u64::try_from(Term::SMALL_INT_MAX)?
.checked_add(1)
.ok_or("size overflow")?;
assert_eq!(mailbox_integer(b"x", 0)?, i64::try_from(folded % size)?);
Ok(())
}
}