use crate::NonNegF32;
use core::error::Error;
use core::fmt::{Display, Formatter};
#[derive(Debug, Copy, Clone)]
pub enum FrequencyLimit {
All,
Min(NonNegF32),
Max(NonNegF32),
Range(NonNegF32, NonNegF32),
}
impl FrequencyLimit {
#[inline]
#[must_use]
pub fn min(min: impl Into<NonNegF32>) -> Self {
Self::Min(min.into())
}
#[inline]
#[must_use]
pub fn max(max: impl Into<NonNegF32>) -> Self {
Self::Max(max.into())
}
#[inline]
#[must_use]
pub fn range(min: impl Into<NonNegF32>, max: impl Into<NonNegF32>) -> Self {
let min = min.into();
let max = max.into();
assert!(min <= max, "min should not be bigger than max");
Self::Range(min, max)
}
#[inline]
#[must_use]
pub const fn maybe_min(&self) -> Option<NonNegF32> {
match self {
Self::Min(min) => Some(*min),
Self::Range(min, _) => Some(*min),
_ => None,
}
}
#[inline]
#[must_use]
pub const fn maybe_max(&self) -> Option<NonNegF32> {
match self {
Self::Max(max) => Some(*max),
Self::Range(_, max) => Some(*max),
_ => None,
}
}
pub fn verify(&self, max_detectable_frequency: f32) -> Result<(), FrequencyLimitError> {
match self {
Self::All => Ok(()),
Self::Min(x) | Self::Max(x) => {
if *x > max_detectable_frequency {
Err(FrequencyLimitError::ValueAboveNyquist(*x))
} else {
Ok(())
}
}
Self::Range(min, max) => {
Self::Min(*min).verify(max_detectable_frequency)?;
Self::Max(*max).verify(max_detectable_frequency)?;
if min > max {
Err(FrequencyLimitError::InvalidRange(*min, *max))
} else {
Ok(())
}
}
}
}
}
#[derive(Debug)]
pub enum FrequencyLimitError {
ValueAboveNyquist(NonNegF32),
InvalidRange(NonNegF32, NonNegF32),
}
impl Display for FrequencyLimitError {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
match self {
Self::ValueAboveNyquist(x) => write!(f, "Value above Nyquist: {x}"),
Self::InvalidRange(min, max) => write!(f, "Invalid range: {min} <= x <= {max}"),
}
}
}
impl Error for FrequencyLimitError {}
#[cfg(test)]
mod tests {
use crate::limit::FrequencyLimitError;
use crate::{FrequencyLimit, NonNegF32};
#[test]
#[should_panic(expected = "value should be finite and not negative")]
fn test_construction_rejects_not_a_number() {
let _ = FrequencyLimit::min(f32::NAN);
}
#[test]
#[should_panic(expected = "value should be finite and not negative")]
fn test_construction_rejects_negative() {
let _ = FrequencyLimit::max(-1.0);
}
#[test]
fn test_min_above_nyquist() {
let _ = FrequencyLimit::min(1.0).verify(0.0).unwrap_err();
}
#[test]
fn test_max_above_nyquist() {
let _ = FrequencyLimit::max(1.0).verify(0.0).unwrap_err();
}
#[test]
fn test_range_above_nyquist() {
let _ = FrequencyLimit::range(0.0, 1.0).verify(0.0).unwrap_err();
}
#[test]
#[should_panic(expected = "min should not be bigger than max")]
fn test_range_rejects_wrong_order() {
let _ = FrequencyLimit::range(1.0, 0.0);
}
#[test]
fn test_range_allows_equal_bounds() {
let limit = FrequencyLimit::range(50.0, 50.0);
assert_eq!(50.0, limit.maybe_min().unwrap());
assert_eq!(50.0, limit.maybe_max().unwrap());
}
#[test]
fn test_verify_catches_a_wrong_range() {
let limit = FrequencyLimit::Range(NonNegF32::from(1.0), NonNegF32::from(0.0));
assert!(matches!(
limit.verify(1.0),
Err(FrequencyLimitError::InvalidRange(_, _))
));
}
#[test]
fn test_constructors_fill_the_right_bound() {
let min = FrequencyLimit::min(50.0);
assert_eq!(50.0, min.maybe_min().unwrap());
assert_eq!(None, min.maybe_max());
let max = FrequencyLimit::max(70.0);
assert_eq!(None, max.maybe_min());
assert_eq!(70.0, max.maybe_max().unwrap());
let range = FrequencyLimit::range(50.0, 70.0);
assert_eq!(50.0, range.maybe_min().unwrap());
assert_eq!(70.0, range.maybe_max().unwrap());
assert_eq!(None, FrequencyLimit::All.maybe_min());
assert_eq!(None, FrequencyLimit::All.maybe_max());
}
#[test]
fn test_ok() {
FrequencyLimit::min(50.0).verify(100.0).unwrap();
FrequencyLimit::max(50.0).verify(100.0).unwrap();
FrequencyLimit::range(50.0, 50.0).verify(100.0).unwrap();
FrequencyLimit::range(50.0, 70.0).verify(100.0).unwrap();
}
}