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