use crate::{
error::{Result, SframeError},
header,
};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Tolerance(usize);
impl Tolerance {
pub const MIN: usize = 1;
pub const MAX: u64 = header::Counter::MAX / 2;
pub fn new(tolerance: usize) -> Self {
Self::try_new(tolerance).unwrap()
}
pub fn try_new(tolerance: usize) -> Result<Self> {
let value = tolerance as u64;
if value < Self::MIN as u64 || value > Self::MAX {
return Err(SframeError::OutOfRange {
name: "tolerance",
value,
min: Self::MIN as u64,
max: Self::MAX,
});
}
Ok(Self(tolerance))
}
}
impl From<Tolerance> for usize {
fn from(tolerance: Tolerance) -> Self {
tolerance.0
}
}
#[cfg(test)]
mod test {
use super::Tolerance;
use crate::error::SframeError;
#[test]
fn accepts_a_tolerance_in_range() {
assert_eq!(usize::from(Tolerance::new(128)), 128);
assert_eq!(usize::from(Tolerance::new(Tolerance::MIN)), Tolerance::MIN);
assert_eq!(
usize::from(Tolerance::new(Tolerance::MAX as usize)),
Tolerance::MAX as usize
);
}
#[test]
fn rejects_a_tolerance_of_zero() {
let result = Tolerance::try_new(0);
assert!(matches!(
result,
Err(SframeError::OutOfRange {
value: 0,
min: 1,
..
})
));
}
#[test]
fn rejects_a_tolerance_beyond_half_the_counter_range() {
let too_large = Tolerance::MAX + 1;
let result = Tolerance::try_new(too_large as usize);
assert!(matches!(
result,
Err(SframeError::OutOfRange { value, max, .. })
if value == too_large && max == Tolerance::MAX
));
}
#[test]
#[should_panic(expected = "OutOfRange")]
fn panics_on_zero() {
Tolerance::new(0);
}
}