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