frequency_unit/
lib.rs

1use core::{
2    fmt::{self, Alignment},
3    ops::{Add, AddAssign, Div, Mul, Sub, SubAssign},
4};
5use num::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: NumCast>(val: T) -> Self {
28        Self {
29            hz: val.to_u64().unwrap(),
30        }
31    }
32
33    pub fn from_mhz<T: NumCast>(val: T) -> Self {
34        Self {
35            hz: (val.to_f64().unwrap() * ONE_MHZ as f64) as u64,
36        }
37    }
38    pub fn from_ghz<T: NumCast>(val: T) -> Self {
39        Self {
40            hz: (val.to_f64().unwrap() * ONE_GHZ as f64) as u64,
41        }
42    }
43    pub fn to_hz<T: NumCast>(&self) -> T {
44        T::from(self.hz).unwrap()
45    }
46
47    pub fn to_mhz<T: NumCast>(&self) -> T {
48        T::from(self.hz as f64 / ONE_MHZ as f64).unwrap()
49    }
50
51    pub fn to_ghz<T: NumCast>(&self) -> T {
52        T::from(self.hz as f64 / ONE_GHZ as f64).unwrap()
53    }
54}
55
56impl Add for Frequency {
57    type Output = Frequency;
58
59    fn add(self, rhs: Self) -> Self::Output {
60        Self {
61            hz: self.hz + rhs.hz,
62        }
63    }
64}
65impl AddAssign for Frequency {
66    fn add_assign(&mut self, rhs: Self) {
67        self.hz += rhs.hz;
68    }
69}
70
71impl Sub for Frequency {
72    type Output = Frequency;
73
74    fn sub(self, rhs: Self) -> Self::Output {
75        Self {
76            hz: self.hz - rhs.hz,
77        }
78    }
79}
80
81impl SubAssign for Frequency {
82    fn sub_assign(&mut self, rhs: Self) {
83        self.hz -= rhs.hz;
84    }
85}
86
87impl<N: NumCast> Mul<N> for Frequency {
88    type Output = Frequency;
89
90    fn mul(self, rhs: N) -> Self::Output {
91        Self {
92            hz: self.hz * rhs.to_u64().unwrap(),
93        }
94    }
95}
96
97impl Div<f32> for Frequency {
98    type Output = Frequency;
99    fn div(self, rhs: f32) -> Self::Output {
100        Self {
101            hz: ((self.hz as f32) / rhs) as u64,
102        }
103    }
104}
105impl Div<f64> for Frequency {
106    type Output = Frequency;
107    fn div(self, rhs: f64) -> Self::Output {
108        Self {
109            hz: ((self.hz as f64) / rhs) as u64,
110        }
111    }
112}
113
114impl<T: NumCast> ToFrequency for T {
115    fn hz(self) -> Frequency {
116        Frequency::from_hz(self.to_u64().unwrap())
117    }
118
119    fn mhz(self) -> Frequency {
120        Frequency::from_mhz(self.to_u64().unwrap())
121    }
122
123    fn ghz(self) -> Frequency {
124        Frequency::from_ghz(self.to_u64().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}