timeout_trait/
timeout.rs

1use crate::*;
2
3pub struct TickTimeout<T: TickInstant> {
4    time: T,
5    timeout: TickDuration<T>,
6}
7
8impl<T> TickTimeout<T>
9where
10    T: TickInstant,
11{
12    pub fn nanos(timeout: u32) -> Self {
13        Self::new(TickDuration::nanos(timeout))
14    }
15
16    pub fn micros(timeout: u32) -> Self {
17        Self::new(TickDuration::micros(timeout))
18    }
19
20    pub fn millis(timeout: u32) -> Self {
21        Self::new(TickDuration::millis(timeout))
22    }
23
24    pub fn new(timeout: TickDuration<T>) -> Self {
25        Self {
26            time: T::now(),
27            timeout,
28        }
29    }
30
31    /// Can be reused without calling `restart()`.
32    #[inline]
33    pub fn timeout(&mut self) -> bool {
34        if self.time.timeout(&self.timeout) {
35            self.time.move_forward(&self.timeout);
36            return true;
37        }
38        false
39    }
40
41    #[inline(always)]
42    pub fn restart(&mut self) {
43        self.time = T::now();
44    }
45
46    #[inline]
47    pub fn time_left(&mut self) -> TickDuration<T> {
48        self.time.time_left(&self.timeout)
49    }
50}
51
52impl<T> From<&TickDuration<T>> for TickTimeout<T>
53where
54    T: TickInstant,
55{
56    fn from(value: &TickDuration<T>) -> Self {
57        Self::new(value.clone())
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64    use crate::mock::MockInstant;
65    use fugit::ExtU32;
66
67    #[test]
68    fn tick_timeout() {
69        let mut now = MockInstant::now();
70        assert_eq!(now.elapsed().as_ticks(), 0);
71        MockInstant::add_time(10.nanos());
72        assert_eq!(now.elapsed().as_ticks(), 10);
73        MockInstant::add_time(1.millis());
74        assert_eq!(now.elapsed().as_ticks(), 1_000_010);
75        MockInstant::add_time(10.micros());
76        let mut now2 = MockInstant::now();
77        assert_eq!(now.elapsed().as_ticks(), 1_010_010);
78        MockInstant::add_time(10.micros());
79        assert_eq!(now2.elapsed().as_ticks(), 10_000);
80
81        let mut t = TickTimeout::<MockInstant>::nanos(100);
82        assert!(!t.timeout());
83        MockInstant::add_time(10.nanos());
84        assert!(!t.timeout());
85        MockInstant::add_time(90.nanos());
86        assert!(t.timeout());
87        assert!(!t.timeout());
88        MockInstant::add_time(100.nanos());
89        assert!(t.timeout());
90
91        MockInstant::add_time(90.nanos());
92        assert!(!t.timeout());
93        t.restart();
94        MockInstant::add_time(90.nanos());
95        assert!(!t.timeout());
96        MockInstant::add_time(10.nanos());
97        assert!(t.timeout());
98
99        let mut t = TickTimeout::<MockInstant>::micros(100);
100        assert!(!t.timeout());
101        MockInstant::add_time(10.micros());
102        assert!(!t.timeout());
103        MockInstant::add_time(90.micros());
104        assert!(t.timeout());
105        assert!(!t.timeout());
106        MockInstant::add_time(100.micros());
107        assert!(t.timeout());
108
109        MockInstant::add_time(90.micros());
110        assert!(!t.timeout());
111        t.restart();
112        MockInstant::add_time(90.micros());
113        assert!(!t.timeout());
114        MockInstant::add_time(10.micros());
115        assert!(t.timeout());
116
117        let mut t = TickTimeout::<MockInstant>::millis(100);
118        assert!(!t.timeout());
119        MockInstant::add_time(10.millis());
120        assert!(!t.timeout());
121        MockInstant::add_time(90.millis());
122        assert!(t.timeout());
123        assert!(!t.timeout());
124        MockInstant::add_time(100.millis());
125        assert!(t.timeout());
126
127        MockInstant::add_time(90.millis());
128        assert!(!t.timeout());
129        t.restart();
130        MockInstant::add_time(90.millis());
131        assert!(!t.timeout());
132        MockInstant::add_time(10.millis());
133        assert!(t.timeout());
134
135        let mut count = 0;
136        let dur = TickDuration::<MockInstant>::nanos(100);
137        let t = MockInstant::now();
138        assert!(t.timeout_with(&dur, || {
139            MockInstant::add_time(10.nanos());
140            count += 1;
141            true
142        }));
143        assert_eq!(count, 10);
144
145        let t = TickTimeout::<MockInstant>::micros(40_000_000);
146        assert_eq!(t.timeout.as_ticks(), 40_000_000_000);
147
148        let mut t = TickTimeout::<MockInstant>::millis(40_000);
149        assert_eq!(t.timeout.as_ticks(), 40_000_000_000);
150
151        assert!(!t.timeout());
152
153        for _ in 0..40 {
154            MockInstant::add_time(999.millis());
155            assert!(!t.timeout());
156        }
157        MockInstant::add_time(100.millis());
158        assert!(t.timeout());
159        assert!(!t.timeout());
160
161        for _ in 0..39 {
162            MockInstant::add_time(999.millis());
163            assert!(!t.timeout());
164        }
165        t.restart();
166        for _ in 0..40 {
167            MockInstant::add_time(999.millis());
168            assert!(!t.timeout());
169        }
170        MockInstant::add_time(100.millis());
171        assert!(t.timeout());
172
173        let dur = TickDuration::<MockInstant>::micros(40_000_000);
174        let t = TickTimeout::from(&dur);
175        assert_eq!(t.timeout.as_ticks(), 40_000_000_000);
176
177        let t = TickTimeout::new(dur);
178        assert_eq!(t.timeout.as_ticks(), 40_000_000_000);
179    }
180}
181
182#[cfg(test)]
183mod tests_fugit {
184    use core::ops::Div;
185    use fugit::{
186        ExtU32, ExtU32Ceil, KilohertzU32, MicrosDurationU32, MillisDurationU32, NanosDurationU64,
187        RateExtU32,
188    };
189
190    #[test]
191    fn duration_tick() {
192        assert_eq!(1 / 1000, 0);
193        assert_eq!(1_u32.div(1000), 0);
194        assert_eq!(1_u32.div_ceil(1000), 1);
195
196        let dur: MicrosDurationU32 = 1.micros();
197        assert_eq!(dur.ticks(), 1);
198
199        let dur: MicrosDurationU32 = 1.millis();
200        assert_eq!(dur.ticks(), 1000);
201        assert_eq!(dur.to_millis(), 1);
202
203        let dur: MillisDurationU32 = 1.millis();
204        assert_eq!(dur.ticks(), 1);
205        assert_eq!(dur.to_micros(), 1000);
206
207        let dur: MillisDurationU32 = 1.micros();
208        assert_eq!(dur.ticks(), 0);
209
210        let dur: MillisDurationU32 = 1.micros_at_least();
211        assert_eq!(dur.ticks(), 1);
212
213        let dur: MicrosDurationU32 = 1.micros();
214        assert_eq!(dur.to_millis(), 0);
215        let dur: MillisDurationU32 = dur.ticks().micros_at_least();
216        assert_eq!(dur.ticks(), 1);
217
218        let a = MicrosDurationU32::micros(100);
219        let b = MicrosDurationU32::micros(99);
220        assert!(b < a);
221
222        let a = NanosDurationU64::micros(100);
223        let b = NanosDurationU64::micros(101);
224        assert!(b > a);
225    }
226
227    #[test]
228    fn rate_tick() {
229        let r: KilohertzU32 = 1.MHz();
230        assert_eq!(r.raw(), 1_000);
231        let f: u32 = r.to_Hz();
232        assert_eq!(f, 1_000_000);
233    }
234}