ora_timer/
resolution.rs

1//! Resolution adapters for timers.
2
3use core::time::Duration;
4
5/// A timer resolution.
6///
7/// Finer resolutions allow for more precise timers, coarser
8/// resolutions may perform better due to grouping targets that
9/// are close together.
10pub trait Resolution {
11    /// The maximum duration that can be represented as [`u32`]
12    /// at this resolution.
13    const MAX_DURATION: Duration;
14
15    /// Convert the given duration into timer cycle steps.
16    /// The given duration is guaranteed to be smaller than [`Resolution::MAX_DURATION`].
17    ///
18    /// If `upper_bound` is true, the returned value should be rounded up.
19    fn cycle_steps(duration: &Duration, upper_bound: bool) -> u32;
20
21    /// Return total steps required for the given duration.
22    /// The returned steps should not be rounded up.
23    fn whole_steps(duration: &Duration) -> u64;
24
25    /// Convert the given steps to a duration.
26    fn steps_as_duration(steps: u64) -> Duration;
27}
28
29/// Microsecond resolution adapter.
30#[derive(Debug)]
31pub enum MicrosecondResolution {}
32
33impl Resolution for MicrosecondResolution {
34    const MAX_DURATION: Duration = Duration::from_micros(u32::MAX as u64);
35
36    #[allow(clippy::cast_possible_truncation)]
37    #[inline]
38    fn cycle_steps(duration: &Duration, upper_bound: bool) -> u32 {
39        let mut steps = (duration.as_secs() * 1_000_000) as u32;
40        let micros = duration.subsec_micros();
41        steps += micros;
42        if upper_bound && duration.subsec_nanos() % 1_000 > 0 {
43            steps = steps.saturating_add(1);
44        }
45        steps
46    }
47
48    #[inline]
49    fn steps_as_duration(steps: u64) -> Duration {
50        Duration::from_micros(steps)
51    }
52
53    #[inline]
54    #[allow(clippy::cast_possible_truncation)]
55    fn whole_steps(duration: &Duration) -> u64 {
56        (duration.as_nanos() / 1_000) as u64
57    }
58}
59
60/// Millisecond resolution adapter.
61#[derive(Debug)]
62pub enum MillisecondResolution {}
63
64impl Resolution for MillisecondResolution {
65    const MAX_DURATION: Duration = Duration::from_millis(u32::MAX as u64);
66
67    #[allow(clippy::cast_possible_truncation)]
68    #[inline]
69    fn cycle_steps(duration: &Duration, upper_bound: bool) -> u32 {
70        let mut steps = (duration.as_secs() * 1000) as u32;
71        let ms = duration.subsec_millis();
72        steps += ms;
73
74        if upper_bound && duration.subsec_nanos() % 1_000_000 > 0 {
75            steps = steps.saturating_add(1);
76        }
77
78        steps
79    }
80
81    #[inline]
82    fn steps_as_duration(steps: u64) -> Duration {
83        Duration::from_millis(steps)
84    }
85
86    #[inline]
87    #[allow(clippy::cast_possible_truncation)]
88    fn whole_steps(duration: &Duration) -> u64 {
89        duration.as_millis() as u64
90    }
91}
92
93/// Second resolution adapter.
94#[derive(Debug)]
95pub enum SecondResolution {}
96
97impl Resolution for SecondResolution {
98    const MAX_DURATION: Duration = Duration::from_secs(u32::MAX as u64);
99
100    #[allow(clippy::cast_possible_truncation)]
101    #[inline]
102    fn cycle_steps(duration: &Duration, upper_bound: bool) -> u32 {
103        let mut steps = duration.as_secs() as u32;
104        if upper_bound && duration.subsec_nanos() > 0 {
105            steps = steps.saturating_add(1);
106        }
107        steps
108    }
109
110    #[inline]
111    fn steps_as_duration(steps: u64) -> Duration {
112        Duration::from_secs(steps)
113    }
114
115    #[inline]
116    fn whole_steps(duration: &Duration) -> u64 {
117        duration.as_secs()
118    }
119}