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