fugit/
rate.rs

1use crate::helpers::{self, Helpers};
2use crate::Duration;
3use core::cmp::Ordering;
4use core::convert;
5use core::ops;
6
7/// Represents a frequency.
8///
9/// The generic `T` can either be `u32` or `u64`, and the const generics represent the ratio of the
10/// raw contained within the rate: `rate in Hz = NOM / DENOM * raw`
11#[derive(Clone, Copy, Debug)]
12pub struct Rate<T, const NOM: u32, const DENOM: u32> {
13    pub(crate) raw: T,
14}
15
16macro_rules! impl_rate_for_integer {
17    ($i:ty) => {
18        impl<const NOM: u32, const DENOM: u32> Rate<$i, NOM, DENOM> {
19            /// Create a `Rate` from a raw value.
20            ///
21            /// ```
22            /// # use fugit::*;
23            #[doc = concat!("let _d = Rate::<", stringify!($i), ", 1, 1_000>::from_raw(1);")]
24            /// ```
25            #[inline]
26            pub const fn from_raw(raw: $i) -> Self {
27                helpers::greater_than_0::<NOM>();
28                helpers::greater_than_0::<DENOM>();
29
30                Rate { raw }
31            }
32
33            /// Extract the raw value from a `Rate`.
34            ///
35            /// ```
36            /// # use fugit::*;
37            #[doc = concat!("let d = Rate::<", stringify!($i), ", 1, 1_000>::from_raw(234);")]
38            ///
39            /// assert_eq!(d.raw(), 234);
40            /// ```
41            #[inline]
42            pub const fn raw(&self) -> $i {
43                self.raw
44            }
45
46            /// Add two rates while checking for overflow.
47            ///
48            /// ```
49            /// # use fugit::*;
50            #[doc = concat!("let r1 = Rate::<", stringify!($i), ", 1, 1_000>::from_raw(1);")]
51            #[doc = concat!("let r2 = Rate::<", stringify!($i), ", 1, 1_000>::from_raw(2);")]
52            #[doc = concat!("let r3 = Rate::<", stringify!($i), ", 1, 1_000>::from_raw(", stringify!($i), "::MAX);")]
53            ///
54            /// assert_eq!(r1.checked_add(r2).unwrap().raw(), 3);
55            /// assert_eq!(r1.checked_add(r3), None);
56            /// ```
57            pub const fn checked_add<const O_NOM: u32, const O_DENOM: u32>(
58                self,
59                other: Rate<$i, O_NOM, O_DENOM>,
60            ) -> Option<Self> {
61                if Helpers::<NOM, DENOM, O_NOM, O_DENOM>::SAME_BASE {
62                    if let Some(raw) = self.raw.checked_add(other.raw) {
63                        Some(Rate::<$i, NOM, DENOM>::from_raw(raw))
64                    } else {
65                        None
66                    }
67                } else {
68                    if let Some(lh) = other
69                        .raw
70                        .checked_mul(Helpers::<NOM, DENOM, O_NOM, O_DENOM>::LD_TIMES_RN as $i)
71                    {
72                        let raw = lh / Helpers::<NOM, DENOM, O_NOM, O_DENOM>::RD_TIMES_LN as $i;
73
74                        if let Some(raw) = self.raw.checked_add(raw) {
75                            Some(Rate::<$i, NOM, DENOM>::from_raw(raw))
76                        } else {
77                            None
78                        }
79                    } else {
80                        None
81                    }
82                }
83            }
84
85            /// Subtract two rates while checking for overflow.
86            ///
87            /// ```
88            /// # use fugit::*;
89            #[doc = concat!("let r1 = Rate::<", stringify!($i), ", 1, 1_000>::from_raw(1);")]
90            #[doc = concat!("let r2 = Rate::<", stringify!($i), ", 1, 1_000>::from_raw(2);")]
91            #[doc = concat!("let r3 = Rate::<", stringify!($i), ", 1, 1_000>::from_raw(", stringify!($i), "::MAX);")]
92            ///
93            /// assert_eq!(r2.checked_sub(r1).unwrap().raw(), 1);
94            /// assert_eq!(r1.checked_sub(r3), None);
95            /// ```
96            pub const fn checked_sub<const O_NOM: u32, const O_DENOM: u32>(
97                self,
98                other: Rate<$i, O_NOM, O_DENOM>,
99            ) -> Option<Self> {
100                if Helpers::<NOM, DENOM, O_NOM, O_DENOM>::SAME_BASE {
101                    if let Some(raw) = self.raw.checked_sub(other.raw) {
102                        Some(Rate::<$i, NOM, DENOM>::from_raw(raw))
103                    } else {
104                        None
105                    }
106                } else {
107                    if let Some(lh) = other
108                        .raw
109                        .checked_mul(Helpers::<NOM, DENOM, O_NOM, O_DENOM>::LD_TIMES_RN as $i)
110                    {
111                        let raw = lh / Helpers::<NOM, DENOM, O_NOM, O_DENOM>::RD_TIMES_LN as $i;
112
113                        if let Some(raw) = self.raw.checked_sub(raw) {
114                            Some(Rate::<$i, NOM, DENOM>::from_raw(raw))
115                        } else {
116                            None
117                        }
118                    } else {
119                        None
120                    }
121                }
122            }
123
124            #[doc = concat!("Const `cmp` for ", stringify!($i))]
125            #[inline(always)]
126            const fn _const_cmp(a: $i, b: $i) -> Ordering {
127                if a < b {
128                    Ordering::Less
129                } else if a > b {
130                    Ordering::Greater
131                } else {
132                    Ordering::Equal
133                }
134            }
135
136            /// Const partial comparison.
137            ///
138            /// ```
139            /// # use fugit::*;
140            #[doc = concat!("let r1 = Rate::<", stringify!($i), ", 1, 1_00>::from_raw(1);")]
141            #[doc = concat!("let r2 = Rate::<", stringify!($i), ", 1, 1_000>::from_raw(1);")]
142            ///
143            /// assert_eq!(r1.const_partial_cmp(r2), Some(core::cmp::Ordering::Greater));
144            /// ```
145            #[inline]
146            pub const fn const_partial_cmp<const R_NOM: u32, const R_DENOM: u32>(
147                self,
148                other: Rate<$i, R_NOM, R_DENOM>
149            ) -> Option<Ordering> {
150                if Helpers::<NOM, DENOM, R_NOM, R_DENOM>::SAME_BASE {
151                    // If we are in the same base, comparison in trivial
152                    Some(Self::_const_cmp(self.raw, other.raw))
153                } else {
154                    let lh = self
155                        .raw
156                        .checked_mul(Helpers::<NOM, DENOM, R_NOM, R_DENOM>::RD_TIMES_LN as $i);
157                    let rh = other
158                        .raw
159                        .checked_mul(Helpers::<NOM, DENOM, R_NOM, R_DENOM>::LD_TIMES_RN as $i);
160
161                    if let (Some(lh), Some(rh)) = (lh, rh) {
162                        Some(Self::_const_cmp(lh, rh))
163                    } else {
164                        None
165                    }
166                }
167            }
168
169            /// Const equality check.
170            ///
171            /// ```
172            /// # use fugit::*;
173            #[doc = concat!("let r1 = Rate::<", stringify!($i), ", 1, 1_00>::from_raw(1);")]
174            #[doc = concat!("let r2 = Rate::<", stringify!($i), ", 1, 1_000>::from_raw(10);")]
175            ///
176            /// assert!(r1.const_eq(r2));
177            /// ```
178            #[inline]
179            pub const fn const_eq<const R_NOM: u32, const R_DENOM: u32>(
180                self,
181                other: Rate<$i, R_NOM, R_DENOM>
182            ) -> bool {
183                if Helpers::<NOM, DENOM, R_NOM, R_DENOM>::SAME_BASE {
184                    // If we are in the same base, comparison in trivial
185                    self.raw == other.raw
186                } else {
187                    let lh = self
188                        .raw
189                        .checked_mul(Helpers::<NOM, DENOM, R_NOM, R_DENOM>::RD_TIMES_LN as $i);
190                    let rh = other
191                        .raw
192                        .checked_mul(Helpers::<NOM, DENOM, R_NOM, R_DENOM>::LD_TIMES_RN as $i);
193
194                    if let (Some(lh), Some(rh)) = (lh, rh) {
195                        lh == rh
196                    } else {
197                        false
198                    }
199                }
200            }
201
202            /// Const try from, checking for overflow.
203            ///
204            /// ```
205            /// # use fugit::*;
206            #[doc = concat!("let r1 = Rate::<", stringify!($i), ", 1, 1_00>::from_raw(1);")]
207            #[doc = concat!("let r2 = Rate::<", stringify!($i), ", 1, 1_000>::const_try_from(r1);")]
208            ///
209            /// assert_eq!(r2.unwrap().raw(), 10);
210            /// ```
211            pub const fn const_try_from<const I_NOM: u32, const I_DENOM: u32>(
212                rate: Rate<$i, I_NOM, I_DENOM>,
213            ) -> Option<Self> {
214                if Helpers::<I_NOM, I_DENOM, NOM, DENOM>::SAME_BASE {
215                    Some(Self::from_raw(rate.raw))
216                } else {
217                    if let Some(lh) = (rate.raw as u64)
218                        .checked_mul(Helpers::<I_NOM, I_DENOM, NOM, DENOM>::RD_TIMES_LN)
219                    {
220                        let raw = lh / Helpers::<I_NOM, I_DENOM, NOM, DENOM>::LD_TIMES_RN;
221
222                        if raw <= <$i>::MAX as u64 {
223                            Some(Self::from_raw(raw as $i))
224                        } else {
225                            None
226                        }
227                    } else {
228                        None
229                    }
230                }
231            }
232
233            /// Const try into, checking for overflow.
234            ///
235            /// ```
236            /// # use fugit::*;
237            #[doc = concat!("let r1 = Rate::<", stringify!($i), ", 1, 1_00>::from_raw(1);")]
238            #[doc = concat!("let r2: Option<Rate::<", stringify!($i), ", 1, 1_000>> = r1.const_try_into();")]
239            ///
240            /// assert_eq!(r2.unwrap().raw(), 10);
241            /// ```
242            #[inline]
243            pub const fn const_try_into<const O_NOM: u32, const O_DENOM: u32>(
244                self,
245            ) -> Option<Rate<$i, O_NOM, O_DENOM>> {
246                Rate::<$i, O_NOM, O_DENOM>::const_try_from(self)
247            }
248
249            /// Const try into duration, checking for divide-by-zero.
250            ///
251            /// ```
252            /// # use fugit::*;
253            #[doc = concat!("let r1 = Rate::<", stringify!($i), ", 1, 1>::from_raw(1);")]
254            #[doc = concat!("let d1: Option<Duration::<", stringify!($i), ", 1, 1_000>> = r1.try_into_duration();")]
255            ///
256            /// assert_eq!(d1.unwrap().ticks(), 1_000);
257            /// ```
258            pub const fn try_into_duration<const O_NOM: u32, const O_DENOM: u32>(
259                self,
260            ) -> Option<Duration<$i, O_NOM, O_DENOM>> {
261                Duration::<$i, O_NOM, O_DENOM>::try_from_rate(self)
262            }
263
264            /// Convert from rate to duration.
265            pub const fn into_duration<const O_NOM: u32, const O_DENOM: u32>(
266                self,
267            ) -> Duration<$i, O_NOM, O_DENOM> {
268                if let Some(v) = self.try_into_duration() {
269                    v
270                } else {
271                    panic!("Into duration failed, divide-by-zero!");
272                }
273            }
274
275            /// Const try from duration, checking for divide-by-zero.
276            ///
277            /// ```
278            /// # use fugit::*;
279            #[doc = concat!("let d1 = Duration::<", stringify!($i), ", 1, 1_000>::from_ticks(2);")]
280            #[doc = concat!("let r1 = Rate::<", stringify!($i), ", 1, 1>::try_from_duration(d1);")]
281            ///
282            /// assert_eq!(r1.unwrap().raw(), 500);
283            /// ```
284            #[inline]
285            pub const fn try_from_duration<const I_NOM: u32, const I_DENOM: u32>(
286                duration: Duration<$i, I_NOM, I_DENOM>,
287            ) -> Option<Self> {
288                if duration.ticks > 0 {
289                    Some(Self::from_raw(
290                        Helpers::<I_NOM, I_DENOM, NOM, DENOM>::RATE_TO_DURATION_NUMERATOR as $i
291                        / duration.ticks
292                    ))
293                } else {
294                    None
295                }
296            }
297
298            /// Convert from duration to rate.
299            #[inline]
300            pub const fn from_duration<const I_NOM: u32, const I_DENOM: u32>(
301                duration: Duration<$i, I_NOM, I_DENOM>,
302            ) -> Self {
303                if let Some(v) = Self::try_from_duration(duration) {
304                    v
305                } else {
306                    panic!("From duration failed, divide-by-zero!");
307                }
308            }
309
310            /// Convert between bases for a rate.
311            ///
312            /// Unfortunately not a `From` impl due to collision with the std lib.
313            ///
314            /// ```
315            /// # use fugit::*;
316            #[doc = concat!("let r1 = Rate::<", stringify!($i), ", 1, 100>::from_raw(1);")]
317            #[doc = concat!("let r2: Rate::<", stringify!($i), ", 1, 1_000> = r1.convert();")]
318            ///
319            /// assert_eq!(r2.raw(), 10);
320            /// ```
321            ///
322            /// Can be used in const contexts. Compilation will fail if the conversion causes overflow
323            ///
324            /// ```compile_fail
325            /// # use fugit::*;
326            #[doc = concat!("const RAW: ", stringify!($i), "= ", stringify!($i), "::MAX - 10;")]
327            #[doc = concat!("const R1: Rate::<", stringify!($i), ", 1, 100> = Rate::<", stringify!($i), ", 1, 100>::from_raw(RAW);")]
328            /// // Fails conversion due to overflow
329            #[doc = concat!("const R2: Rate::<", stringify!($i), ", 1, 200> = R1.convert();")]
330            /// ```
331            pub const fn convert<const O_NOM: u32, const O_DENOM: u32>(
332                self,
333            ) -> Rate<$i, O_NOM, O_DENOM> {
334                if let Some(v) = self.const_try_into() {
335                    v
336                } else {
337                    panic!("Convert failed!");
338                }
339            }
340
341            /// Convert the Rate to an interger number of Hz.
342            #[inline]
343            #[allow(non_snake_case)]
344            pub const fn to_Hz(&self) -> $i {
345                    (Helpers::<1, 1, NOM, DENOM>::LD_TIMES_RN as $i * self.raw)
346                        / Helpers::<1, 1, NOM, DENOM>::RD_TIMES_LN as $i
347            }
348
349            /// Convert the Rate to an interger number of kHz.
350            #[inline]
351            #[allow(non_snake_case)]
352            pub const fn to_kHz(&self) -> $i {
353                    (Helpers::<1_000, 1, NOM, DENOM>::LD_TIMES_RN as $i * self.raw)
354                        / Helpers::<1_000, 1, NOM, DENOM>::RD_TIMES_LN as $i
355            }
356
357            /// Convert the Rate to an interger number of MHz.
358            #[inline]
359            #[allow(non_snake_case)]
360            pub const fn to_MHz(&self) -> $i {
361                    (Helpers::<1_000_000, 1, NOM, DENOM>::LD_TIMES_RN as $i * self.raw)
362                        / Helpers::<1_000_000, 1, NOM, DENOM>::RD_TIMES_LN as $i
363            }
364
365            /// Shorthand for creating a rate which represents hertz.
366            #[inline]
367            #[allow(non_snake_case)]
368            pub const fn Hz(val: $i) -> Self {
369                Self::from_raw(
370                    (Helpers::<1, 1, NOM, DENOM>::RD_TIMES_LN as $i * val)
371                        / Helpers::<1, 1, NOM, DENOM>::LD_TIMES_RN as $i,
372                )
373            }
374
375            /// Shorthand for creating a rate which represents kilohertz.
376            #[inline]
377            #[allow(non_snake_case)]
378            pub const fn kHz(val: $i) -> Self {
379                Self::from_raw(
380                    (Helpers::<1_000, 1, NOM, DENOM>::RD_TIMES_LN as $i * val)
381                        / Helpers::<1_000, 1, NOM, DENOM>::LD_TIMES_RN as $i,
382                )
383            }
384
385            /// Shorthand for creating a rate which represents megahertz.
386            #[inline]
387            #[allow(non_snake_case)]
388            pub const fn MHz(val: $i) -> Self {
389                Self::from_raw(
390                    (Helpers::<1_000_000, 1, NOM, DENOM>::RD_TIMES_LN as $i * val)
391                        / Helpers::<1_000_000, 1, NOM, DENOM>::LD_TIMES_RN as $i,
392                )
393            }
394
395            /// Shorthand for creating a rate which represents nanoseconds.
396            #[inline]
397            pub const fn nanos(val: $i) -> Self {
398                Self::from_duration(crate::Duration::<$i, 1, 1_000_000_000>::from_ticks(val))
399            }
400
401            /// Shorthand for creating a rate which represents microseconds.
402            #[inline]
403            pub const fn micros(val: $i) -> Self {
404                Self::from_duration(crate::Duration::<$i, 1, 1_000_000>::from_ticks(val))
405            }
406
407            /// Shorthand for creating a rate which represents milliseconds.
408            #[inline]
409            pub const fn millis(val: $i) -> Self {
410                Self::from_duration(crate::Duration::<$i, 1, 1_000>::from_ticks(val))
411            }
412        }
413
414        impl<const L_NOM: u32, const L_DENOM: u32, const R_NOM: u32, const R_DENOM: u32>
415            PartialOrd<Rate<$i, R_NOM, R_DENOM>> for Rate<$i, L_NOM, L_DENOM>
416        {
417            #[inline]
418            fn partial_cmp(&self, other: &Rate<$i, R_NOM, R_DENOM>) -> Option<Ordering> {
419                self.const_partial_cmp(*other)
420            }
421        }
422
423        impl<const NOM: u32, const DENOM: u32> Ord for Rate<$i, NOM, DENOM> {
424            #[inline]
425            fn cmp(&self, other: &Self) -> Ordering {
426                Self::_const_cmp(self.raw, other.raw)
427            }
428        }
429
430        impl<const L_NOM: u32, const L_DENOM: u32, const R_NOM: u32, const R_DENOM: u32>
431            PartialEq<Rate<$i, R_NOM, R_DENOM>> for Rate<$i, L_NOM, L_DENOM>
432        {
433            #[inline]
434            fn eq(&self, other: &Rate<$i, R_NOM, R_DENOM>) -> bool {
435                self.const_eq(*other)
436            }
437        }
438
439        impl<const NOM: u32, const DENOM: u32> Eq for Rate<$i, NOM, DENOM> {}
440
441        // Rate - Rate = Rate (only same base until const_generics_defaults is
442        // stabilized)
443        impl<const NOM: u32, const DENOM: u32> ops::Sub<Rate<$i, NOM, DENOM>>
444            for Rate<$i, NOM, DENOM>
445        {
446            type Output = Rate<$i, NOM, DENOM>;
447
448            #[inline]
449            fn sub(self, other: Rate<$i, NOM, DENOM>) -> Self::Output {
450                if let Some(v) = self.checked_sub(other) {
451                    v
452                } else {
453                    panic!("Sub failed!");
454                }
455            }
456        }
457
458        // Rate + Rate = Rate (only same base until const_generics_defaults is
459        // stabilized)
460        impl<const NOM: u32, const DENOM: u32> ops::Add<Rate<$i, NOM, DENOM>>
461            for Rate<$i, NOM, DENOM>
462        {
463            type Output = Rate<$i, NOM, DENOM>;
464
465            #[inline]
466            fn add(self, other: Rate<$i, NOM, DENOM>) -> Self::Output {
467                if let Some(v) = self.checked_add(other) {
468                    v
469                } else {
470                    panic!("Add failed!");
471                }
472            }
473        }
474
475        // Rate += Rate
476        impl<const NOM: u32, const DENOM: u32> ops::AddAssign<Rate<$i, NOM, DENOM>>
477            for Rate<$i, NOM, DENOM>
478        {
479            #[inline]
480            fn add_assign(&mut self, other: Self) {
481                *self = *self + other;
482            }
483        }
484
485        // integer * Rate = Rate
486        impl<const NOM: u32, const DENOM: u32> ops::Mul<Rate<$i, NOM, DENOM>> for u32 {
487            type Output = Rate<$i, NOM, DENOM>;
488
489            #[inline]
490            fn mul(self, mut other: Rate<$i, NOM, DENOM>) -> Self::Output {
491                other.raw *= self as $i;
492                other
493            }
494        }
495
496        // Rate * integer = Rate
497        impl<const NOM: u32, const DENOM: u32> ops::Mul<u32> for Rate<$i, NOM, DENOM> {
498            type Output = Rate<$i, NOM, DENOM>;
499
500            #[inline]
501            fn mul(mut self, other: u32) -> Self::Output {
502                self.raw *= other as $i;
503                self
504            }
505        }
506
507        // Rate *= integer
508        impl<const NOM: u32, const DENOM: u32> ops::MulAssign<u32>
509            for Rate<$i, NOM, DENOM>
510        {
511            #[inline]
512            fn mul_assign(&mut self, other: u32) {
513                *self = *self * other;
514            }
515        }
516
517        // Rate / integer = Rate
518        impl<const NOM: u32, const DENOM: u32> ops::Div<u32> for Rate<$i, NOM, DENOM> {
519            type Output = Rate<$i, NOM, DENOM>;
520
521            #[inline]
522            fn div(mut self, other: u32) -> Self::Output {
523                self.raw /= other as $i;
524                self
525            }
526        }
527
528        // Rate / Rate = integer
529        impl<const L_NOM: u32, const L_DENOM: u32, const R_NOM: u32, const R_DENOM: u32> ops::Div<Rate<$i, R_NOM, R_DENOM>>
530            for Rate<$i, L_NOM, L_DENOM>
531        {
532            type Output = $i;
533
534            #[inline]
535            fn div(self, other: Rate<$i, R_NOM, R_DENOM>) -> Self::Output {
536                let conv: Rate<$i, R_NOM, R_DENOM> = self.convert();
537                conv.raw / other.raw
538            }
539        }
540
541        // Rate /= integer
542        impl<const NOM: u32, const DENOM: u32> ops::DivAssign<u32>
543            for Rate<$i, NOM, DENOM>
544        {
545            #[inline]
546            fn div_assign(&mut self, other: u32) {
547                *self = *self / other;
548            }
549        }
550
551        #[cfg(feature = "defmt")]
552        impl<const NOM: u32, const DENOM: u32> defmt::Format for Rate<$i, NOM, DENOM>
553        {
554            fn format(&self, f: defmt::Formatter) {
555                if NOM == 1 && DENOM == 1 {
556                    defmt::write!(f, "{} Hz", self.raw)
557                } else if NOM == 1_000 && DENOM == 1 {
558                    defmt::write!(f, "{} kHz", self.raw)
559                } else if NOM == 1_000_000 && DENOM == 1 {
560                    defmt::write!(f, "{} MHz", self.raw)
561                } else if NOM == 1_000_000_000 && DENOM == 1 {
562                    defmt::write!(f, "{} GHz", self.raw)
563                } else {
564                    defmt::write!(f, "{} raw @ ({}/{})", self.raw, NOM, DENOM)
565                }
566            }
567        }
568
569        impl<const NOM: u32, const DENOM: u32> core::fmt::Display for Rate<$i, NOM, DENOM> {
570            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
571                if NOM == 1 && DENOM == 1 {
572                    write!(f, "{} Hz", self.raw)
573                } else if NOM == 1_000 && DENOM == 1 {
574                    write!(f, "{} kHz", self.raw)
575                } else if NOM == 1_000_000 && DENOM == 1 {
576                    write!(f, "{} MHz", self.raw)
577                } else if NOM == 1_000_000_000 && DENOM == 1 {
578                    write!(f, "{} GHz", self.raw)
579                } else {
580                    write!(f, "{} raw @ ({}/{})", self.raw, NOM, DENOM)
581                }
582            }
583        }
584    };
585}
586
587impl_rate_for_integer!(u32);
588impl_rate_for_integer!(u64);
589
590//
591// Operations between u32 and u64 Rate
592//
593
594impl<const NOM: u32, const DENOM: u32> From<Rate<u32, NOM, DENOM>> for Rate<u64, NOM, DENOM> {
595    #[inline]
596    fn from(val: Rate<u32, NOM, DENOM>) -> Rate<u64, NOM, DENOM> {
597        Rate::<u64, NOM, DENOM>::from_raw(val.raw() as u64)
598    }
599}
600
601impl<const NOM: u32, const DENOM: u32> convert::TryFrom<Rate<u64, NOM, DENOM>>
602    for Rate<u32, NOM, DENOM>
603{
604    type Error = ();
605
606    #[inline]
607    fn try_from(val: Rate<u64, NOM, DENOM>) -> Result<Rate<u32, NOM, DENOM>, ()> {
608        Ok(Rate::<u32, NOM, DENOM>::from_raw(
609            val.raw().try_into().map_err(|_| ())?,
610        ))
611    }
612}
613
614// Rate - Rate = Rate (to make shorthands work, until const_generics_defaults is
615// stabilized)
616impl<const NOM: u32, const DENOM: u32> ops::Sub<Rate<u32, NOM, DENOM>> for Rate<u64, NOM, DENOM> {
617    type Output = Rate<u64, NOM, DENOM>;
618
619    #[inline]
620    fn sub(self, other: Rate<u32, NOM, DENOM>) -> Self::Output {
621        if let Some(v) = self.checked_sub(Rate::<u64, NOM, DENOM>::from_raw(other.raw() as u64)) {
622            v
623        } else {
624            panic!("Sub failed!");
625        }
626    }
627}
628
629// Rate -= Rate (to make shorthands work, until const_generics_defaults is stabilized)
630impl<const NOM: u32, const DENOM: u32> ops::SubAssign<Rate<u32, NOM, DENOM>>
631    for Rate<u64, NOM, DENOM>
632{
633    #[inline]
634    fn sub_assign(&mut self, other: Rate<u32, NOM, DENOM>) {
635        *self = *self - other;
636    }
637}
638
639// Rate + Rate = Rate (to make shorthands work, until const_generics_defaults is
640// stabilized)
641impl<const NOM: u32, const DENOM: u32> ops::Add<Rate<u32, NOM, DENOM>> for Rate<u64, NOM, DENOM> {
642    type Output = Rate<u64, NOM, DENOM>;
643
644    #[inline]
645    fn add(self, other: Rate<u32, NOM, DENOM>) -> Self::Output {
646        if let Some(v) = self.checked_add(Rate::<u64, NOM, DENOM>::from_raw(other.raw() as u64)) {
647            v
648        } else {
649            panic!("Add failed!");
650        }
651    }
652}
653
654// Rate += Rate (to make shorthands work, until const_generics_defaults is stabilized)
655impl<const NOM: u32, const DENOM: u32> ops::AddAssign<Rate<u32, NOM, DENOM>>
656    for Rate<u64, NOM, DENOM>
657{
658    #[inline]
659    fn add_assign(&mut self, other: Rate<u32, NOM, DENOM>) {
660        *self = *self + other;
661    }
662}
663
664impl<const L_NOM: u32, const L_DENOM: u32, const R_NOM: u32, const R_DENOM: u32>
665    PartialOrd<Rate<u32, R_NOM, R_DENOM>> for Rate<u64, L_NOM, L_DENOM>
666{
667    #[inline]
668    fn partial_cmp(&self, other: &Rate<u32, R_NOM, R_DENOM>) -> Option<Ordering> {
669        self.partial_cmp(&Rate::<u64, R_NOM, R_DENOM>::from_raw(other.raw() as u64))
670    }
671}
672
673impl<const L_NOM: u32, const L_DENOM: u32, const R_NOM: u32, const R_DENOM: u32>
674    PartialEq<Rate<u32, R_NOM, R_DENOM>> for Rate<u64, L_NOM, L_DENOM>
675{
676    #[inline]
677    fn eq(&self, other: &Rate<u32, R_NOM, R_DENOM>) -> bool {
678        self.eq(&Rate::<u64, R_NOM, R_DENOM>::from_raw(other.raw() as u64))
679    }
680}
681
682impl<const L_NOM: u32, const L_DENOM: u32, const R_NOM: u32, const R_DENOM: u32>
683    PartialOrd<Rate<u64, R_NOM, R_DENOM>> for Rate<u32, L_NOM, L_DENOM>
684{
685    #[inline]
686    fn partial_cmp(&self, other: &Rate<u64, R_NOM, R_DENOM>) -> Option<Ordering> {
687        Rate::<u64, L_NOM, L_DENOM>::from_raw(self.raw as u64).partial_cmp(other)
688    }
689}
690
691impl<const L_NOM: u32, const L_DENOM: u32, const R_NOM: u32, const R_DENOM: u32>
692    PartialEq<Rate<u64, R_NOM, R_DENOM>> for Rate<u32, L_NOM, L_DENOM>
693{
694    #[inline]
695    fn eq(&self, other: &Rate<u64, R_NOM, R_DENOM>) -> bool {
696        Rate::<u64, L_NOM, L_DENOM>::from_raw(self.raw as u64).eq(other)
697    }
698}
699
700/// Extension trait for simple short-hands for u32 Rate
701pub trait ExtU32 {
702    /// Shorthand for creating a rate which represents hertz.
703    #[allow(non_snake_case)]
704    fn Hz<const NOM: u32, const DENOM: u32>(self) -> Rate<u32, NOM, DENOM>;
705
706    /// Shorthand for creating a rate which represents kilohertz.
707    #[allow(non_snake_case)]
708    fn kHz<const NOM: u32, const DENOM: u32>(self) -> Rate<u32, NOM, DENOM>;
709
710    /// Shorthand for creating a rate which represents megahertz.
711    #[allow(non_snake_case)]
712    fn MHz<const NOM: u32, const DENOM: u32>(self) -> Rate<u32, NOM, DENOM>;
713}
714
715impl ExtU32 for u32 {
716    #[inline]
717    #[allow(non_snake_case)]
718    fn Hz<const NOM: u32, const DENOM: u32>(self) -> Rate<u32, NOM, DENOM> {
719        Rate::<u32, NOM, DENOM>::Hz(self)
720    }
721
722    #[inline]
723    #[allow(non_snake_case)]
724    fn kHz<const NOM: u32, const DENOM: u32>(self) -> Rate<u32, NOM, DENOM> {
725        Rate::<u32, NOM, DENOM>::kHz(self)
726    }
727
728    #[inline]
729    #[allow(non_snake_case)]
730    fn MHz<const NOM: u32, const DENOM: u32>(self) -> Rate<u32, NOM, DENOM> {
731        Rate::<u32, NOM, DENOM>::MHz(self)
732    }
733}
734
735/// Extension trait for simple short-hands for u64 Rate
736pub trait ExtU64 {
737    /// Shorthand for creating a rate which represents hertz.
738    #[allow(non_snake_case)]
739    fn Hz<const NOM: u32, const DENOM: u32>(self) -> Rate<u64, NOM, DENOM>;
740
741    /// Shorthand for creating a rate which represents kilohertz.
742    #[allow(non_snake_case)]
743    fn kHz<const NOM: u32, const DENOM: u32>(self) -> Rate<u64, NOM, DENOM>;
744
745    /// Shorthand for creating a rate which represents megahertz.
746    #[allow(non_snake_case)]
747    fn MHz<const NOM: u32, const DENOM: u32>(self) -> Rate<u64, NOM, DENOM>;
748}
749
750impl ExtU64 for u64 {
751    #[inline]
752    #[allow(non_snake_case)]
753    fn Hz<const NOM: u32, const DENOM: u32>(self) -> Rate<u64, NOM, DENOM> {
754        Rate::<u64, NOM, DENOM>::Hz(self)
755    }
756
757    #[inline]
758    #[allow(non_snake_case)]
759    fn kHz<const NOM: u32, const DENOM: u32>(self) -> Rate<u64, NOM, DENOM> {
760        Rate::<u64, NOM, DENOM>::kHz(self)
761    }
762
763    #[inline]
764    #[allow(non_snake_case)]
765    fn MHz<const NOM: u32, const DENOM: u32>(self) -> Rate<u64, NOM, DENOM> {
766        Rate::<u64, NOM, DENOM>::MHz(self)
767    }
768}