1use thiserror::Error;
7
8#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
10pub enum TimerRegistration {
11 #[default]
13 Unregistered,
14 Scheduled {
16 generation: u64,
18 deadline_ns: u64,
20 },
21 Running {
23 generation: u64,
25 },
26}
27
28#[derive(Clone, Copy, Debug, Eq, PartialEq)]
30pub enum TimerControlAction {
31 None,
33 Arm {
35 generation: u64,
37 deadline_ns: u64,
39 kind: WakeupArm,
41 },
42 Clear,
44 Disarm {
46 cancelled: bool,
48 },
49}
50
51#[derive(Clone, Copy, Debug, Eq, PartialEq)]
53pub enum WakeupArm {
54 Initial,
55 Replacement,
56}
57
58impl WakeupArm {
59 pub(crate) const fn replaces_existing(self) -> bool {
60 matches!(self, Self::Replacement)
61 }
62}
63
64#[derive(Clone, Copy, Debug, Eq, Error, PartialEq)]
66pub enum TimerControlError {
67 #[error("timer generation exhausted")]
69 GenerationExhausted,
70 #[error("timer completion does not own the running generation")]
72 StaleCompletion,
73}
74
75#[derive(Debug, Default)]
77pub struct TimerControl {
78 generation: u64,
79 registration: TimerRegistration,
80}
81
82#[derive(Clone, Copy)]
83enum DeadlineSelection {
84 Earliest,
85 Exact,
86}
87
88impl DeadlineSelection {
89 const fn replaces(self, current_deadline_ns: u64, requested_deadline_ns: u64) -> bool {
90 match self {
91 Self::Earliest => requested_deadline_ns < current_deadline_ns,
92 Self::Exact => requested_deadline_ns != current_deadline_ns,
93 }
94 }
95}
96
97impl TimerControl {
98 #[must_use]
100 #[cfg(test)]
101 pub(crate) const fn generation(&self) -> u64 {
102 self.generation
103 }
104
105 #[must_use]
107 pub(crate) const fn registration(&self) -> TimerRegistration {
108 self.registration
109 }
110
111 pub(crate) const fn terminate(&mut self) -> bool {
116 let clear_wakeup = matches!(self.registration, TimerRegistration::Scheduled { .. });
117 self.registration = TimerRegistration::Unregistered;
118 clear_wakeup
119 }
120
121 pub(crate) fn schedule(
123 &mut self,
124 deadline_ns: u64,
125 ) -> Result<TimerControlAction, TimerControlError> {
126 self.request_deadline(deadline_ns, DeadlineSelection::Earliest)
127 }
128
129 pub(crate) fn cancel(&mut self) -> Result<TimerControlAction, TimerControlError> {
134 match self.registration {
135 TimerRegistration::Scheduled { .. } => {
136 let generation = self.next_generation()?;
137 self.generation = generation;
138 self.registration = TimerRegistration::Unregistered;
139 Ok(TimerControlAction::Clear)
140 }
141 TimerRegistration::Unregistered | TimerRegistration::Running { .. } => {
142 Ok(TimerControlAction::None)
143 }
144 }
145 }
146
147 pub(crate) fn reconcile(
149 &mut self,
150 deadline_ns: u64,
151 ) -> Result<TimerControlAction, TimerControlError> {
152 self.request_deadline(deadline_ns, DeadlineSelection::Exact)
153 }
154
155 fn request_deadline(
156 &mut self,
157 deadline_ns: u64,
158 selection: DeadlineSelection,
159 ) -> Result<TimerControlAction, TimerControlError> {
160 let replace = match self.registration {
161 TimerRegistration::Unregistered => Some(false),
162 TimerRegistration::Scheduled {
163 deadline_ns: current_deadline_ns,
164 ..
165 } if selection.replaces(current_deadline_ns, deadline_ns) => Some(true),
166 TimerRegistration::Scheduled { .. } | TimerRegistration::Running { .. } => None,
167 };
168 let Some(replace) = replace else {
169 return Ok(TimerControlAction::None);
170 };
171
172 let generation = self.next_generation()?;
173 self.generation = generation;
174 self.registration = TimerRegistration::Scheduled {
175 generation,
176 deadline_ns,
177 };
178 Ok(TimerControlAction::Arm {
179 generation,
180 deadline_ns,
181 kind: if replace {
182 WakeupArm::Replacement
183 } else {
184 WakeupArm::Initial
185 },
186 })
187 }
188
189 pub(crate) const fn begin(&mut self, generation: u64) -> bool {
191 match self.registration {
192 TimerRegistration::Scheduled {
193 generation: scheduled_generation,
194 ..
195 } if scheduled_generation == generation => {
196 self.registration = TimerRegistration::Running { generation };
197 true
198 }
199 TimerRegistration::Unregistered
200 | TimerRegistration::Scheduled { .. }
201 | TimerRegistration::Running { .. } => false,
202 }
203 }
204
205 pub(crate) fn complete(
208 &mut self,
209 generation: u64,
210 next_deadline_ns: Option<u64>,
211 cancelled: bool,
212 ) -> Result<TimerControlAction, TimerControlError> {
213 if self.registration != (TimerRegistration::Running { generation }) {
214 return Err(TimerControlError::StaleCompletion);
215 }
216
217 let next_generation = if next_deadline_ns.is_some() {
218 Some(self.next_generation()?)
219 } else {
220 None
221 };
222
223 if let (Some(deadline_ns), Some(next_generation)) = (next_deadline_ns, next_generation) {
224 self.generation = next_generation;
225 self.registration = TimerRegistration::Scheduled {
226 generation: next_generation,
227 deadline_ns,
228 };
229 Ok(TimerControlAction::Arm {
230 generation: next_generation,
231 deadline_ns,
232 kind: WakeupArm::Initial,
233 })
234 } else {
235 self.registration = TimerRegistration::Unregistered;
236 Ok(TimerControlAction::Disarm { cancelled })
237 }
238 }
239
240 fn next_generation(&self) -> Result<u64, TimerControlError> {
241 self.generation
242 .checked_add(1)
243 .ok_or(TimerControlError::GenerationExhausted)
244 }
245}
246
247#[cfg(test)]
248mod tests {
249 use super::*;
250
251 fn arm(control: &mut TimerControl, deadline_ns: u64) -> u64 {
252 let TimerControlAction::Arm { generation, .. } = control
253 .schedule(deadline_ns)
254 .expect("initial schedule should succeed")
255 else {
256 panic!("initial schedule should arm");
257 };
258 generation
259 }
260
261 #[test]
262 fn duplicate_and_later_schedules_keep_one_earliest_handle() {
263 let mut control = TimerControl::default();
264 assert_eq!(arm(&mut control, 100), 1);
265 assert_eq!(control.schedule(100), Ok(TimerControlAction::None));
266 assert_eq!(control.schedule(200), Ok(TimerControlAction::None));
267 assert_eq!(
268 control.registration(),
269 TimerRegistration::Scheduled {
270 generation: 1,
271 deadline_ns: 100
272 }
273 );
274 }
275
276 #[test]
277 fn earlier_schedule_replaces_and_invalidates_old_generation() {
278 let mut control = TimerControl::default();
279 let old_generation = arm(&mut control, 100);
280 assert_eq!(
281 control.schedule(50),
282 Ok(TimerControlAction::Arm {
283 generation: 2,
284 deadline_ns: 50,
285 kind: WakeupArm::Replacement,
286 })
287 );
288 assert!(!control.begin(old_generation));
289 assert!(control.begin(2));
290 }
291
292 #[test]
293 fn authoritative_reconciliation_can_move_scheduled_deadline_later() {
294 let mut control = TimerControl::default();
295 let old_generation = arm(&mut control, 100);
296 assert_eq!(
297 control.reconcile(200),
298 Ok(TimerControlAction::Arm {
299 generation: 2,
300 deadline_ns: 200,
301 kind: WakeupArm::Replacement,
302 })
303 );
304 assert!(!control.begin(old_generation));
305 assert!(control.begin(2));
306 }
307
308 #[test]
309 fn completion_uses_the_registrys_authoritative_deadline() {
310 let mut control = TimerControl::default();
311 let generation = arm(&mut control, 100);
312 assert!(control.begin(generation));
313 assert_eq!(control.reconcile(300), Ok(TimerControlAction::None));
314 assert_eq!(
315 control.complete(generation, Some(300), false),
316 Ok(TimerControlAction::Arm {
317 generation: 2,
318 deadline_ns: 300,
319 kind: WakeupArm::Initial,
320 })
321 );
322 }
323
324 #[test]
325 fn completion_uses_the_registrys_pending_schedule() {
326 let mut control = TimerControl::default();
327 let generation = arm(&mut control, 100);
328 assert!(control.begin(generation));
329 assert_eq!(control.schedule(90), Ok(TimerControlAction::None));
330 assert_eq!(
331 control.complete(generation, Some(90), false),
332 Ok(TimerControlAction::Arm {
333 generation: 2,
334 deadline_ns: 90,
335 kind: WakeupArm::Initial,
336 })
337 );
338 }
339
340 #[test]
341 fn running_callback_can_request_its_own_cancellation() {
342 let mut control = TimerControl::default();
343 let generation = arm(&mut control, 100);
344 assert!(control.begin(generation));
345 assert_eq!(control.cancel(), Ok(TimerControlAction::None));
346 assert_eq!(
347 control.complete(generation, None, true),
348 Ok(TimerControlAction::Disarm { cancelled: true })
349 );
350 assert_eq!(control.registration(), TimerRegistration::Unregistered);
351 }
352
353 #[test]
354 fn completion_arms_the_registrys_selected_earliest_deadline() {
355 let mut control = TimerControl::default();
356 let generation = arm(&mut control, 100);
357 assert!(control.begin(generation));
358 assert_eq!(
359 control.complete(generation, Some(250), false),
360 Ok(TimerControlAction::Arm {
361 generation: 2,
362 deadline_ns: 250,
363 kind: WakeupArm::Initial,
364 })
365 );
366 }
367
368 #[test]
369 fn completion_honors_the_registrys_cancellation() {
370 let mut control = TimerControl::default();
371 let generation = arm(&mut control, 100);
372 assert!(control.begin(generation));
373 assert_eq!(
374 control.complete(generation, None, true),
375 Ok(TimerControlAction::Disarm { cancelled: true })
376 );
377 }
378
379 #[test]
380 fn completion_honors_the_registrys_later_schedule() {
381 let mut control = TimerControl::default();
382 let generation = arm(&mut control, 100);
383 assert!(control.begin(generation));
384 assert_eq!(
385 control.complete(generation, Some(90), false),
386 Ok(TimerControlAction::Arm {
387 generation: 2,
388 deadline_ns: 90,
389 kind: WakeupArm::Initial,
390 })
391 );
392 }
393
394 #[test]
395 fn scheduled_cancel_invalidates_consumed_generation() {
396 let mut control = TimerControl::default();
397 let generation = arm(&mut control, 100);
398 assert_eq!(control.cancel(), Ok(TimerControlAction::Clear));
399 assert!(!control.begin(generation));
400 assert_eq!(control.generation(), 2);
401 assert_eq!(control.registration(), TimerRegistration::Unregistered);
402 }
403
404 #[test]
405 fn stale_completion_cannot_change_current_registration() {
406 let mut control = TimerControl::default();
407 let generation = arm(&mut control, 100);
408 assert!(control.begin(generation));
409 assert_eq!(
410 control.complete(generation + 1, None, false),
411 Err(TimerControlError::StaleCompletion)
412 );
413 assert_eq!(
414 control.registration(),
415 TimerRegistration::Running { generation }
416 );
417 }
418
419 #[test]
420 fn exhausted_generation_fails_without_replacing_current_handle() {
421 let mut control = TimerControl {
422 generation: u64::MAX,
423 registration: TimerRegistration::Scheduled {
424 generation: u64::MAX,
425 deadline_ns: 100,
426 },
427 };
428
429 assert_eq!(
430 control.schedule(50),
431 Err(TimerControlError::GenerationExhausted)
432 );
433 assert_eq!(
434 control.registration(),
435 TimerRegistration::Scheduled {
436 generation: u64::MAX,
437 deadline_ns: 100
438 }
439 );
440 }
441}