use std::fmt::Debug;
use std::ops::{Add, Div, Mul, Sub};
use uom::si::{
f32, f64,
frequency::{gigahertz, hertz, kilohertz, megahertz},
u64,
};
#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Frequency {
freq: u64::Frequency,
}
impl Frequency {
const HZ_PER_KHZ: f64 = 1_000.;
const HZ_PER_MHZ: f64 = 1_000_000.;
const HZ_PER_GHZ: f64 = 1_000_000_000.;
pub fn from_hz(hz: u64) -> Frequency {
Frequency {
freq: u64::Frequency::new::<hertz>(hz),
}
}
pub fn from_khz(khz: u64) -> Frequency {
Frequency {
freq: u64::Frequency::new::<kilohertz>(khz),
}
}
pub fn from_khz_f32(khz: f32) -> Frequency {
Self::from_khz_f64(f64::from(khz))
}
pub fn from_khz_f64(khz: f64) -> Frequency {
Self::from_float_hz(khz * Self::HZ_PER_KHZ)
}
pub fn from_mhz(mhz: u64) -> Frequency {
Frequency {
freq: u64::Frequency::new::<megahertz>(mhz),
}
}
pub fn from_mhz_f32(mhz: f32) -> Frequency {
Self::from_mhz_f64(f64::from(mhz))
}
pub fn from_mhz_f64(mhz: f64) -> Frequency {
Self::from_float_hz(mhz * Self::HZ_PER_MHZ)
}
pub fn from_ghz(ghz: u64) -> Frequency {
Frequency {
freq: u64::Frequency::new::<gigahertz>(ghz),
}
}
pub fn from_ghz_f32(ghz: f32) -> Frequency {
Self::from_ghz_f64(f64::from(ghz))
}
pub fn from_ghz_f64(ghz: f64) -> Frequency {
Self::from_float_hz(ghz * Self::HZ_PER_GHZ)
}
pub fn as_hz(&self) -> u64 {
self.freq.get::<hertz>()
}
pub fn as_hz_f32(&self) -> f32 {
self.freq.get::<hertz>() as f32
}
pub fn as_hz_f64(&self) -> f64 {
self.freq.get::<hertz>() as f64
}
pub fn as_khz(&self) -> u64 {
self.freq.get::<kilohertz>()
}
pub fn as_khz_f32(&self) -> f32 {
f32::Frequency::new::<hertz>(self.freq.get::<hertz>() as f32).get::<kilohertz>()
}
pub fn as_khz_f64(&self) -> f64 {
f64::Frequency::new::<hertz>(self.freq.get::<hertz>() as f64).get::<kilohertz>()
}
pub fn as_mhz(&self) -> u64 {
self.freq.get::<megahertz>()
}
pub fn as_mhz_f32(&self) -> f32 {
f32::Frequency::new::<hertz>(self.freq.get::<hertz>() as f32).get::<megahertz>()
}
pub fn as_mhz_f64(&self) -> f64 {
f64::Frequency::new::<hertz>(self.freq.get::<hertz>() as f64).get::<megahertz>()
}
pub fn as_ghz(&self) -> u64 {
self.freq.get::<gigahertz>()
}
pub fn as_ghz_f32(&self) -> f32 {
f32::Frequency::new::<hertz>(self.freq.get::<hertz>() as f32).get::<gigahertz>()
}
pub fn as_ghz_f64(&self) -> f64 {
f64::Frequency::new::<hertz>(self.freq.get::<hertz>() as f64).get::<gigahertz>()
}
pub fn abs_diff(self, other: Frequency) -> Frequency {
Frequency::from_hz(self.as_hz().abs_diff(other.as_hz()))
}
fn from_float_hz(hz: f64) -> Frequency {
if !hz.is_finite() || hz.is_sign_negative() || hz > u64::MAX as f64 {
return Frequency::default();
}
Frequency::from_hz(hz as u64)
}
}
impl Add for Frequency {
type Output = Frequency;
fn add(self, rhs: Frequency) -> Self::Output {
Frequency {
freq: self.freq + rhs.freq,
}
}
}
impl Sub for Frequency {
type Output = Frequency;
fn sub(self, rhs: Frequency) -> Self::Output {
if self < rhs {
panic!("Cannot subtract a larger frequency from a smaller frequency");
}
Frequency {
freq: self.freq - rhs.freq,
}
}
}
impl Mul<u64> for Frequency {
type Output = Frequency;
fn mul(self, rhs: u64) -> Self::Output {
Frequency {
freq: self.freq * rhs,
}
}
}
impl Div<u64> for Frequency {
type Output = Frequency;
fn div(self, rhs: u64) -> Self::Output {
if rhs == 0 {
panic!("Cannot divide a frequency by zero.");
}
Frequency {
freq: self.freq / rhs,
}
}
}
impl Div<Frequency> for Frequency {
type Output = u64;
fn div(self, rhs: Frequency) -> Self::Output {
if rhs.as_hz() == 0 {
panic!("Cannot divide a frequency by zero.")
}
self.as_hz() / rhs.as_hz()
}
}
impl From<u64> for Frequency {
fn from(freq_hz: u64) -> Self {
Frequency::from_hz(freq_hz)
}
}
impl Debug for Frequency {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Frequency")
.field("hz", &self.as_hz())
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn frequency_to_hz() {
let frequency = Frequency::from_hz(1_000_000_000);
assert_eq!(frequency.as_hz(), 1_000_000_000);
let frequency = Frequency::from_khz(1_000_000);
assert_eq!(frequency.as_hz(), 1_000_000_000);
let frequency = Frequency::from_khz_f32(1_000_000.);
assert_eq!(frequency.as_hz(), 1_000_000_000);
let frequency = Frequency::from_khz_f64(1_000_000.);
assert_eq!(frequency.as_hz(), 1_000_000_000);
let frequency = Frequency::from_mhz(1_000);
assert_eq!(frequency.as_hz(), 1_000_000_000);
let frequency = Frequency::from_mhz_f32(1_000.);
assert_eq!(frequency.as_hz(), 1_000_000_000);
let frequency = Frequency::from_mhz_f64(1_000.);
assert_eq!(frequency.as_hz(), 1_000_000_000);
let frequency = Frequency::from_ghz(1);
assert_eq!(frequency.as_hz(), 1_000_000_000);
let frequency = Frequency::from_ghz_f32(1.);
assert_eq!(frequency.as_hz(), 1_000_000_000);
let frequency = Frequency::from_ghz_f64(1.);
assert_eq!(frequency.as_hz(), 1_000_000_000);
}
#[test]
fn frequency_to_khz() {
let frequency = Frequency::from_hz(1_000_000_000);
assert_eq!(frequency.as_khz(), 1_000_000);
assert_eq!(frequency.as_khz_f32(), 1_000_000.);
assert_eq!(frequency.as_khz_f64(), 1_000_000.);
let frequency = Frequency::from_khz(1_000_000);
assert_eq!(frequency.as_khz(), 1_000_000);
assert_eq!(frequency.as_khz_f32(), 1_000_000.);
assert_eq!(frequency.as_khz_f64(), 1_000_000.);
let frequency = Frequency::from_khz_f32(1_000_000.);
assert_eq!(frequency.as_khz(), 1_000_000);
assert_eq!(frequency.as_khz_f32(), 1_000_000.);
assert_eq!(frequency.as_khz_f64(), 1_000_000.);
let frequency = Frequency::from_khz_f64(1_000_000.);
assert_eq!(frequency.as_khz(), 1_000_000);
assert_eq!(frequency.as_khz_f32(), 1_000_000.);
assert_eq!(frequency.as_khz_f64(), 1_000_000.);
let frequency = Frequency::from_mhz(1_000);
assert_eq!(frequency.as_khz(), 1_000_000);
assert_eq!(frequency.as_khz_f32(), 1_000_000.);
assert_eq!(frequency.as_khz_f64(), 1_000_000.);
let frequency = Frequency::from_mhz_f32(1_000.);
assert_eq!(frequency.as_khz(), 1_000_000);
assert_eq!(frequency.as_khz_f32(), 1_000_000.);
assert_eq!(frequency.as_khz_f64(), 1_000_000.);
let frequency = Frequency::from_mhz_f64(1_000.);
assert_eq!(frequency.as_khz(), 1_000_000);
assert_eq!(frequency.as_khz_f32(), 1_000_000.);
assert_eq!(frequency.as_khz_f64(), 1_000_000.);
let frequency = Frequency::from_ghz(1);
assert_eq!(frequency.as_khz(), 1_000_000);
assert_eq!(frequency.as_khz_f32(), 1_000_000.);
assert_eq!(frequency.as_khz_f64(), 1_000_000.);
let frequency = Frequency::from_ghz_f32(1.);
assert_eq!(frequency.as_khz(), 1_000_000);
assert_eq!(frequency.as_khz_f32(), 1_000_000.);
assert_eq!(frequency.as_khz_f64(), 1_000_000.);
let frequency = Frequency::from_ghz_f64(1.);
assert_eq!(frequency.as_khz(), 1_000_000);
assert_eq!(frequency.as_khz_f32(), 1_000_000.);
assert_eq!(frequency.as_khz_f64(), 1_000_000.);
}
#[test]
fn frequency_to_mhz() {
let frequency = Frequency::from_hz(1_000_000_000);
assert_eq!(frequency.as_mhz(), 1_000);
assert_eq!(frequency.as_mhz_f32(), 1_000.);
assert_eq!(frequency.as_mhz_f64(), 1_000.);
let frequency = Frequency::from_khz(1_000_000);
assert_eq!(frequency.as_mhz(), 1_000);
assert_eq!(frequency.as_mhz_f32(), 1_000.);
assert_eq!(frequency.as_mhz_f64(), 1_000.);
let frequency = Frequency::from_khz_f32(1_000_000.);
assert_eq!(frequency.as_mhz(), 1_000);
assert_eq!(frequency.as_mhz_f32(), 1_000.);
assert_eq!(frequency.as_mhz_f64(), 1_000.);
let frequency = Frequency::from_khz_f64(1_000_000.);
assert_eq!(frequency.as_mhz(), 1_000);
assert_eq!(frequency.as_mhz_f32(), 1_000.);
assert_eq!(frequency.as_mhz_f64(), 1_000.);
let frequency = Frequency::from_mhz(1_000);
assert_eq!(frequency.as_mhz(), 1_000);
assert_eq!(frequency.as_mhz_f32(), 1_000.);
assert_eq!(frequency.as_mhz_f64(), 1_000.);
let frequency = Frequency::from_mhz_f32(1_000.);
assert_eq!(frequency.as_mhz(), 1_000);
assert_eq!(frequency.as_mhz_f32(), 1_000.);
assert_eq!(frequency.as_mhz_f64(), 1_000.);
let frequency = Frequency::from_mhz_f64(1_000.);
assert_eq!(frequency.as_mhz(), 1_000);
assert_eq!(frequency.as_mhz_f32(), 1_000.);
assert_eq!(frequency.as_mhz_f64(), 1_000.);
let frequency = Frequency::from_ghz(1);
assert_eq!(frequency.as_mhz(), 1_000);
assert_eq!(frequency.as_mhz_f32(), 1_000.);
assert_eq!(frequency.as_mhz_f64(), 1_000.);
let frequency = Frequency::from_ghz_f32(1.);
assert_eq!(frequency.as_mhz(), 1_000);
assert_eq!(frequency.as_mhz_f32(), 1_000.);
assert_eq!(frequency.as_mhz_f64(), 1_000.);
let frequency = Frequency::from_ghz_f64(1.);
assert_eq!(frequency.as_mhz(), 1_000);
assert_eq!(frequency.as_mhz_f32(), 1_000.);
assert_eq!(frequency.as_mhz_f64(), 1_000.);
}
#[test]
fn frequency_to_ghz() {
let frequency = Frequency::from_hz(1_000_000_000);
assert_eq!(frequency.as_ghz(), 1);
assert_eq!(frequency.as_ghz_f32(), 1.);
assert_eq!(frequency.as_ghz_f64(), 1.);
let frequency = Frequency::from_khz(1_000_000);
assert_eq!(frequency.as_ghz(), 1);
assert_eq!(frequency.as_ghz_f32(), 1.);
assert_eq!(frequency.as_ghz_f64(), 1.);
let frequency = Frequency::from_khz_f32(1_000_000.);
assert_eq!(frequency.as_ghz(), 1);
assert_eq!(frequency.as_ghz_f32(), 1.);
assert_eq!(frequency.as_ghz_f64(), 1.);
let frequency = Frequency::from_khz_f64(1_000_000.);
assert_eq!(frequency.as_ghz(), 1);
assert_eq!(frequency.as_ghz_f32(), 1.);
assert_eq!(frequency.as_ghz_f64(), 1.);
let frequency = Frequency::from_mhz(1_000);
assert_eq!(frequency.as_ghz(), 1);
assert_eq!(frequency.as_ghz_f32(), 1.);
assert_eq!(frequency.as_ghz_f64(), 1.);
let frequency = Frequency::from_mhz_f32(1_000.);
assert_eq!(frequency.as_ghz(), 1);
assert_eq!(frequency.as_ghz_f32(), 1.);
assert_eq!(frequency.as_ghz_f64(), 1.);
let frequency = Frequency::from_mhz_f64(1_000.);
assert_eq!(frequency.as_ghz(), 1);
assert_eq!(frequency.as_ghz_f32(), 1.);
assert_eq!(frequency.as_ghz_f64(), 1.);
let frequency = Frequency::from_ghz(1);
assert_eq!(frequency.as_ghz(), 1);
assert_eq!(frequency.as_ghz_f32(), 1.);
assert_eq!(frequency.as_ghz_f64(), 1.);
let frequency = Frequency::from_ghz_f32(1.);
assert_eq!(frequency.as_ghz(), 1);
assert_eq!(frequency.as_ghz_f32(), 1.);
assert_eq!(frequency.as_ghz_f64(), 1.);
let frequency = Frequency::from_ghz_f64(1.);
assert_eq!(frequency.as_ghz(), 1);
assert_eq!(frequency.as_ghz_f32(), 1.);
assert_eq!(frequency.as_ghz_f64(), 1.);
}
#[test]
fn float_frequency_constructors_reject_invalid_values() {
assert_eq!(Frequency::from_khz_f64(-1.), Frequency::default());
assert_eq!(Frequency::from_khz_f64(f64::NAN), Frequency::default());
assert_eq!(Frequency::from_khz_f64(f64::INFINITY), Frequency::default());
assert_eq!(Frequency::from_khz_f32(f32::NAN), Frequency::default());
assert_eq!(Frequency::from_khz_f32(f32::INFINITY), Frequency::default());
}
#[test]
fn float_frequency_constructors_reject_overflowing_values() {
assert_eq!(
Frequency::from_khz_f64((u64::MAX as f64 / Frequency::HZ_PER_KHZ) * 2.),
Frequency::default()
);
assert_eq!(
Frequency::from_mhz_f64((u64::MAX as f64 / Frequency::HZ_PER_MHZ) * 2.),
Frequency::default()
);
assert_eq!(
Frequency::from_ghz_f64((u64::MAX as f64 / Frequency::HZ_PER_GHZ) * 2.),
Frequency::default()
);
}
#[test]
fn float_frequency_constructors_truncate_fractional_hz() {
assert_eq!(Frequency::from_khz_f64(1.234_567).as_hz(), 1_234);
assert_eq!(Frequency::from_mhz_f64(1.234_567).as_hz(), 1_234_567);
assert_eq!(Frequency::from_ghz_f64(1.234_567).as_hz(), 1_234_567_000);
}
#[test]
fn add() {
let freq = Frequency::from_hz(1) + Frequency::from_hz(1);
assert_eq!(freq.as_hz(), 2);
let freq = Frequency::from_hz(1_000) + Frequency::from_khz(1);
assert_eq!(freq.as_khz(), 2);
let freq = Frequency::from_hz(1_000_000) + Frequency::from_mhz(1);
assert_eq!(freq.as_mhz(), 2);
let freq = Frequency::from_hz(1_000_000_000) + Frequency::from_ghz(1);
assert_eq!(freq.as_ghz(), 2);
}
#[test]
fn subtract() {
let freq = Frequency::from_hz(3) - Frequency::from_hz(1);
assert_eq!(freq.as_hz(), 2);
let freq = Frequency::from_hz(3_000) - Frequency::from_khz(1);
assert_eq!(freq.as_khz(), 2);
let freq = Frequency::from_hz(3_000_000) - Frequency::from_mhz(1);
assert_eq!(freq.as_mhz(), 2);
let freq = Frequency::from_hz(3_000_000_000) - Frequency::from_ghz(1);
assert_eq!(freq.as_ghz(), 2);
}
#[test]
#[should_panic]
fn subtract_larger_frequency() {
let _ = Frequency::from_hz(1) - Frequency::from_ghz(1);
}
#[test]
fn multiply() {
let freq = Frequency::from_hz(1) * 2;
assert_eq!(freq.as_hz(), 2);
let freq = Frequency::from_khz(1) * 2;
assert_eq!(freq.as_khz(), 2);
let freq = Frequency::from_mhz(1) * 2;
assert_eq!(freq.as_mhz(), 2);
let freq = Frequency::from_ghz(1) * 2;
assert_eq!(freq.as_ghz(), 2);
}
#[test]
fn divide() {
let freq = Frequency::from_hz(4) / 2;
assert_eq!(freq.as_hz(), 2);
let freq = Frequency::from_khz(4) / 2;
assert_eq!(freq.as_khz(), 2);
let freq = Frequency::from_mhz(4) / 2;
assert_eq!(freq.as_mhz(), 2);
let freq = Frequency::from_ghz(4) / 2;
assert_eq!(freq.as_ghz(), 2);
}
#[test]
#[should_panic]
fn divide_by_zero() {
let _ = Frequency::from_hz(1) / 0;
}
}