use std::{fmt, ops};
use crate::Factor;
pub trait FrequencyUnits {
fn millihertz(self) -> Frequency;
fn hertz(self) -> Frequency;
fn megahertz(self) -> Frequency;
fn gigahertz(self) -> Frequency;
fn terahertz(self) -> Frequency;
}
impl FrequencyUnits for u64 {
fn millihertz(self) -> Frequency {
Frequency::from_millihertz(self)
}
fn hertz(self) -> Frequency {
Frequency::from_hertz(self as _)
}
fn megahertz(self) -> Frequency {
Frequency::from_megahertz(self as _)
}
fn gigahertz(self) -> Frequency {
Frequency::from_gigahertz(self as _)
}
fn terahertz(self) -> Frequency {
Frequency::from_terahertz(self as _)
}
}
impl FrequencyUnits for f64 {
fn millihertz(self) -> Frequency {
Frequency::from_millihertz(self.round() as _)
}
fn hertz(self) -> Frequency {
Frequency::from_hertz(self)
}
fn megahertz(self) -> Frequency {
Frequency::from_megahertz(self)
}
fn gigahertz(self) -> Frequency {
Frequency::from_gigahertz(self)
}
fn terahertz(self) -> Frequency {
Frequency::from_terahertz(self)
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, serde::Serialize, serde::Deserialize)]
#[serde(transparent)]
pub struct Frequency(u64);
impl ops::Add for Frequency {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(self.0 + rhs.0)
}
}
impl ops::AddAssign for Frequency {
fn add_assign(&mut self, rhs: Self) {
self.0 += rhs.0;
}
}
impl ops::Sub for Frequency {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self(self.0 - rhs.0)
}
}
impl ops::SubAssign for Frequency {
fn sub_assign(&mut self, rhs: Self) {
self.0 -= rhs.0;
}
}
impl ops::Mul<Factor> for Frequency {
type Output = Frequency;
fn mul(mut self, rhs: Factor) -> Self::Output {
self.0 *= rhs;
self
}
}
impl ops::Div<Factor> for Frequency {
type Output = Frequency;
fn div(mut self, rhs: Factor) -> Self::Output {
self.0 /= rhs;
self
}
}
impl ops::MulAssign<Factor> for Frequency {
fn mul_assign(&mut self, rhs: Factor) {
self.0 *= rhs;
}
}
impl ops::DivAssign<Factor> for Frequency {
fn div_assign(&mut self, rhs: Factor) {
self.0 /= rhs;
}
}
impl Frequency {
pub const fn millihertz(&self) -> u64 {
self.0
}
pub const fn hertz(&self) -> f64 {
self.0 as f64 / 1000.0
}
pub const fn kilohertz(&self) -> f64 {
self.hertz() / 1000.0
}
pub const fn megahertz(&self) -> f64 {
self.kilohertz() / 1000.0
}
pub const fn gigahertz(&self) -> f64 {
self.megahertz() / 1000.0
}
pub const fn terahertz(&self) -> f64 {
self.gigahertz() / 1000.0
}
pub const fn period(&self) -> std::time::Duration {
if self.0 == 0 {
return std::time::Duration::MAX;
}
let nanos = (1_000_000_000_000u128 / self.0 as u128) as u64;
std::time::Duration::from_nanos(nanos)
}
}
impl Frequency {
pub const fn from_millihertz(z: u64) -> Self {
Self(z)
}
pub const fn from_hertz(z: f64) -> Self {
Self::from_millihertz((z * 1000.0).round() as _)
}
pub const fn from_kilohertz(z: f64) -> Self {
Self::from_hertz(z * 1000.0)
}
pub const fn from_megahertz(z: f64) -> Self {
Self::from_kilohertz(z * 1000.0)
}
pub const fn from_gigahertz(z: f64) -> Self {
Self::from_megahertz(z * 1000.0)
}
pub const fn from_terahertz(z: f64) -> Self {
Self::from_gigahertz(z * 1000.0)
}
pub const fn from_period(p: std::time::Duration) -> Self {
let nanos = p.as_nanos();
if nanos == 0 {
return Self(0);
}
let mhz = 1_000_000_000_000u128 / nanos;
Self(mhz as u64)
}
}
impl fmt::Display for Frequency {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let z = self.0;
if z >= 1_000_000_000_000_000 {
write!(f, "{:.2}THz", self.terahertz())
} else if z >= 1_000_000_000_000 {
write!(f, "{:.2}GHz", self.gigahertz())
} else if z >= 1_000_000_000 {
write!(f, "{:.2}MHz", self.megahertz())
} else if z >= 1_000_000 {
write!(f, "{:.2}kHz", self.kilohertz())
} else if z >= 1_000 {
write!(f, "{:.2}Hz", self.hertz())
} else {
write!(f, "{z}mHz")
}
}
}
impl fmt::Debug for Frequency {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
f.debug_tuple("Frequency").field(&self.0).finish()
} else {
write!(f, "Frequency({self})")
}
}
}