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 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}