frequency_unit/
lib.rs

1use core::{
2    fmt::{self, Alignment},
3    ops::{Add, AddAssign, Div, Mul, Sub, SubAssign},
4};
5use num::{cast::AsPrimitive, NumCast};
6
7const ONE_MHZ: u64 = 1_000_000;
8const ONE_GHZ: u64 = ONE_MHZ * 1000;
9
10pub trait ToFrequency {
11    fn hz(self) -> Frequency;
12    fn mhz(self) -> Frequency;
13    fn ghz(self) -> Frequency;
14}
15
16#[repr(transparent)]
17#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
18pub struct Frequency {
19    hz: u64,
20}
21
22impl Frequency {
23    pub const fn new(hz: u64) -> Self {
24        Self { hz }
25    }
26
27    pub fn from_hz<T: AsPrimitive<u64>>(val: T) -> Self {
28        Self { hz: val.as_() }
29    }
30
31    pub fn from_mhz<T: AsPrimitive<f64>>(val: T) -> Self {
32        Self {
33            hz: (val.as_() * ONE_MHZ as f64) as u64,
34        }
35    }
36    pub fn from_ghz<T: AsPrimitive<f64>>(val: T) -> Self {
37        Self {
38            hz: (val.as_() * ONE_GHZ as f64) as u64,
39        }
40    }
41    pub fn to_hz<T: NumCast>(&self) -> T {
42        T::from(self.hz).unwrap()
43    }
44
45    pub fn to_mhz<T: NumCast>(&self) -> T {
46        T::from(self.hz as f64 / ONE_MHZ as f64).unwrap()
47    }
48
49    pub fn to_ghz<T: NumCast>(&self) -> T {
50        T::from(self.hz as f64 / ONE_GHZ as f64).unwrap()
51    }
52}
53
54impl Add for Frequency {
55    type Output = Frequency;
56
57    fn add(self, rhs: Self) -> Self::Output {
58        Self {
59            hz: self.hz + rhs.hz,
60        }
61    }
62}
63impl AddAssign for Frequency {
64    fn add_assign(&mut self, rhs: Self) {
65        self.hz += rhs.hz;
66    }
67}
68
69impl Sub for Frequency {
70    type Output = Frequency;
71
72    fn sub(self, rhs: Self) -> Self::Output {
73        Self {
74            hz: self.hz - rhs.hz,
75        }
76    }
77}
78
79impl SubAssign for Frequency {
80    fn sub_assign(&mut self, rhs: Self) {
81        self.hz -= rhs.hz;
82    }
83}
84
85impl<N: NumCast> Mul<N> for Frequency {
86    type Output = Frequency;
87
88    fn mul(self, rhs: N) -> Self::Output {
89        Self {
90            hz: self.hz * rhs.to_u64().unwrap(),
91        }
92    }
93}
94
95impl Div<f32> for Frequency {
96    type Output = Frequency;
97    fn div(self, rhs: f32) -> Self::Output {
98        Self {
99            hz: ((self.hz as f32) / rhs) as u64,
100        }
101    }
102}
103impl Div<f64> for Frequency {
104    type Output = Frequency;
105    fn div(self, rhs: f64) -> Self::Output {
106        Self {
107            hz: ((self.hz as f64) / rhs) as u64,
108        }
109    }
110}
111
112impl<T: NumCast> ToFrequency for T {
113    fn hz(self) -> Frequency {
114        Frequency {
115            hz: self.to_u64().unwrap(),
116        }
117    }
118
119    fn mhz(self) -> Frequency {
120        Frequency::from_mhz(self.to_f64().unwrap())
121    }
122
123    fn ghz(self) -> Frequency {
124        Frequency::from_ghz(self.to_f64().unwrap())
125    }
126}
127
128macro_rules! impl_div_num {
129    ($T: ty) => {
130        impl Div<$T> for Frequency {
131            type Output = Frequency;
132            fn div(self, rhs: $T) -> Self::Output {
133                Self {
134                    hz: self.hz / rhs as u64,
135                }
136            }
137        }
138    };
139}
140
141impl_div_num!(u8);
142impl_div_num!(i8);
143impl_div_num!(u16);
144impl_div_num!(i16);
145impl_div_num!(u32);
146impl_div_num!(i32);
147impl_div_num!(usize);
148impl_div_num!(isize);
149impl_div_num!(u64);
150impl_div_num!(i64);
151
152impl Div<Frequency> for Frequency {
153    type Output = f64;
154
155    fn div(self, rhs: Frequency) -> Self::Output {
156        self.hz as f64 / rhs.hz as f64
157    }
158}
159
160impl core::fmt::Debug for Frequency {
161    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162        write!(f, "Frequency Hz ({})", self.hz)
163    }
164}
165impl std::fmt::Display for Frequency {
166    /// Formats the value using the given formatter.
167    ///
168    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
169        let mut value = self.hz as f64;
170        let mut unit = " Hz";
171        let mut precision = f.precision().unwrap_or(3);
172
173        if self.hz >= ONE_GHZ {
174            value /= ONE_GHZ as f64;
175            unit = "GHz";
176        } else if self.hz >= ONE_MHZ {
177            value /= ONE_MHZ as f64;
178            unit = "MHz";
179        } else {
180            precision = 0;
181        }
182
183        if let Some(width) = f.width() {
184            if f.align().unwrap_or(Alignment::Left) == Alignment::Left {
185                write!(f, "{:<width$.precision$}", value)?;
186            } else {
187                write!(f, "{:>width$.precision$}", value)?;
188            }
189        } else {
190            f.write_fmt(format_args!("{:.precision$}", value))?;
191        }
192
193        f.write_str(unit)
194    }
195}
196
197#[cfg(test)]
198mod test {
199    use super::*;
200
201    #[test]
202    fn test_freq() {
203        let freq = Frequency::from_mhz(1.0);
204        let a: f64 = freq.to_mhz();
205        let b: i32 = freq.to_hz();
206
207        assert_eq!(a, 1.0);
208        assert_eq!(b, 1_000_000);
209
210        println!("{}", freq);
211    }
212
213    #[test]
214    fn test_freq_add() {
215        let freq = Frequency::from_mhz(1.0);
216        let freq2 = Frequency::from_mhz(2.0);
217        let freq3 = freq + freq2;
218
219        let a: f64 = freq3.to_mhz();
220
221        assert_eq!(a, 3.0);
222    }
223
224    #[test]
225    fn test_freq_div() {
226        let freq = Frequency::from_mhz(1.0);
227        let freq2 = Frequency::from_mhz(2.0);
228        let p = freq / freq2;
229
230        assert_eq!(p, 0.5);
231
232        let freq = Frequency::from_mhz(3.0);
233        let b = 2isize;
234        let p = freq / b;
235        let want = Frequency::from_mhz(1.5);
236
237        assert_eq!(p, want);
238
239        let freq = Frequency::from_mhz(1.0);
240        let b = 0.5f32;
241        let p = freq / b;
242        let want = Frequency::from_mhz(2);
243
244        assert_eq!(p, want);
245    }
246    #[test]
247    fn test_print() {
248        let freq = Frequency::from_mhz(12.3456789);
249
250        assert_eq!(format!("{:<10.2}", freq), "12.35     MHz");
251
252        let freq = Frequency::from_hz(12);
253
254        println!("{:<10.2}", freq);
255    }
256
257    #[test]
258    fn test_to_freq() {
259        let freq = 1.hz();
260        let freq2 = 1.mhz();
261        let freq3 = 1.0.ghz();
262
263        assert_eq!(freq.to_hz::<u64>(), 1);
264        assert_eq!(freq2.to_hz::<u64>(), 1_000_000);
265        assert_eq!(freq3.to_hz::<u64>(), 1_000_000_000);
266
267        assert_eq!(1.1.mhz().to_hz::<u64>(), 1_100_000);
268    }
269}