use std::f64::consts::{PI, TAU};
use crate::InterferenceError;
fn invalid(name: &'static str, value: f64) -> InterferenceError {
InterferenceError::InvalidQuantity { name, value }
}
fn finite(name: &'static str, value: f64) -> Result<f64, InterferenceError> {
value
.is_finite()
.then_some(canonical_zero(value))
.ok_or_else(|| invalid(name, value))
}
fn positive(name: &'static str, value: f64) -> Result<f64, InterferenceError> {
(value.is_finite() && value > 0.0)
.then_some(value)
.ok_or_else(|| invalid(name, value))
}
fn non_negative(name: &'static str, value: f64) -> Result<f64, InterferenceError> {
(value.is_finite() && value >= 0.0)
.then_some(canonical_zero(value))
.ok_or_else(|| invalid(name, value))
}
fn canonical_zero(value: f64) -> f64 {
if value == 0.0 { 0.0 } else { value }
}
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
pub struct Metres(f64);
impl Metres {
pub const NAME: &'static str = "distance-m";
pub fn new(value: f64) -> Result<Self, InterferenceError> {
finite(Self::NAME, value).map(Self)
}
pub fn get(self) -> f64 {
self.0
}
}
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
pub struct PositiveMetres(f64);
impl PositiveMetres {
pub const NAME: &'static str = "positive-distance-m";
pub fn new(value: f64) -> Result<Self, InterferenceError> {
positive(Self::NAME, value).map(Self)
}
pub fn get(self) -> f64 {
self.0
}
}
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
pub struct Hertz(f64);
impl Hertz {
pub const NAME: &'static str = "frequency-hz";
pub fn new(value: f64) -> Result<Self, InterferenceError> {
positive(Self::NAME, value).map(Self)
}
pub fn get(self) -> f64 {
self.0
}
}
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
pub struct MetresPerSecond(f64);
impl MetresPerSecond {
pub const NAME: &'static str = "speed-m-s";
pub fn new(value: f64) -> Result<Self, InterferenceError> {
positive(Self::NAME, value).map(Self)
}
pub fn get(self) -> f64 {
self.0
}
}
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
pub struct NepersPerMetre(f64);
impl NepersPerMetre {
pub const NAME: &'static str = "attenuation-np-m";
pub fn new(value: f64) -> Result<Self, InterferenceError> {
non_negative(Self::NAME, value).map(Self)
}
pub fn get(self) -> f64 {
self.0
}
}
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
pub struct Radians(f64);
impl Radians {
pub const NAME: &'static str = "phase-rad";
pub fn new(value: f64) -> Result<Self, InterferenceError> {
let value = finite(Self::NAME, value)?;
let positive_turn = value.rem_euclid(TAU);
let normalized = if positive_turn >= PI {
positive_turn - TAU
} else {
positive_turn
};
Ok(Self(canonical_zero(normalized)))
}
pub fn get(self) -> f64 {
self.0
}
}
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
pub struct FieldAmplitude(f64);
impl FieldAmplitude {
pub const NAME: &'static str = "field-amplitude";
pub fn new(value: f64) -> Result<Self, InterferenceError> {
non_negative(Self::NAME, value).map(Self)
}
pub fn get(self) -> f64 {
self.0
}
}