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