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