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)]
29enum PendingCommand {
30 Cancel { sequence: u64 },
31 Reconcile { sequence: u64, deadline_ns: u64 },
32 Schedule { sequence: u64, deadline_ns: u64 },
33}
34
35#[derive(Clone, Copy, Debug, Eq, PartialEq)]
37pub enum TimerControlAction {
38 None,
40 Arm {
42 generation: u64,
44 deadline_ns: u64,
46 },
47 Replace {
49 generation: u64,
51 deadline_ns: u64,
53 },
54 Clear,
56 Disarm {
58 cancelled: bool,
60 },
61}
62
63#[non_exhaustive]
65#[derive(Clone, Copy, Debug, Eq, Error, PartialEq)]
66pub enum TimerControlError {
67 #[error("timer request sequence exhausted")]
69 RequestSequenceExhausted,
70 #[error("timer generation exhausted")]
72 GenerationExhausted,
73 #[error("timer completion does not own the running generation")]
75 StaleCompletion,
76}
77
78#[derive(Debug, Default)]
80pub struct TimerControl {
81 generation: u64,
82 request_sequence: u64,
83 registration: TimerRegistration,
84 pending: Option<PendingCommand>,
85}
86
87impl TimerControl {
88 #[must_use]
90 pub const fn generation(&self) -> u64 {
91 self.generation
92 }
93
94 #[must_use]
96 pub const fn registration(&self) -> TimerRegistration {
97 self.registration
98 }
99
100 pub fn schedule(&mut self, deadline_ns: u64) -> Result<TimerControlAction, TimerControlError> {
102 let sequence = self.next_request_sequence()?;
103
104 match self.registration {
105 TimerRegistration::Unregistered => {
106 let generation = self.next_generation()?;
107 self.request_sequence = sequence;
108 self.generation = generation;
109 self.registration = TimerRegistration::Scheduled {
110 generation,
111 deadline_ns,
112 };
113 Ok(TimerControlAction::Arm {
114 generation,
115 deadline_ns,
116 })
117 }
118 TimerRegistration::Scheduled {
119 deadline_ns: current_deadline,
120 ..
121 } if deadline_ns < current_deadline => {
122 let generation = self.next_generation()?;
123 self.request_sequence = sequence;
124 self.generation = generation;
125 self.registration = TimerRegistration::Scheduled {
126 generation,
127 deadline_ns,
128 };
129 Ok(TimerControlAction::Replace {
130 generation,
131 deadline_ns,
132 })
133 }
134 TimerRegistration::Scheduled { .. } => {
135 self.request_sequence = sequence;
136 Ok(TimerControlAction::None)
137 }
138 TimerRegistration::Running { .. } => {
139 self.request_sequence = sequence;
140 self.pending = Some(match self.pending {
141 Some(
142 PendingCommand::Schedule {
143 deadline_ns: current_deadline,
144 ..
145 }
146 | PendingCommand::Reconcile {
147 deadline_ns: current_deadline,
148 ..
149 },
150 ) => PendingCommand::Schedule {
151 sequence,
152 deadline_ns: current_deadline.min(deadline_ns),
153 },
154 Some(PendingCommand::Cancel { .. }) | None => PendingCommand::Schedule {
155 sequence,
156 deadline_ns,
157 },
158 });
159 Ok(TimerControlAction::None)
160 }
161 }
162 }
163
164 pub fn cancel(&mut self) -> Result<TimerControlAction, TimerControlError> {
166 let sequence = self.next_request_sequence()?;
167
168 match self.registration {
169 TimerRegistration::Unregistered => {
170 self.request_sequence = sequence;
171 Ok(TimerControlAction::None)
172 }
173 TimerRegistration::Scheduled { .. } => {
174 let generation = self.next_generation()?;
175 self.request_sequence = sequence;
176 self.generation = generation;
177 self.registration = TimerRegistration::Unregistered;
178 self.pending = None;
179 Ok(TimerControlAction::Clear)
180 }
181 TimerRegistration::Running { .. } => {
182 self.request_sequence = sequence;
183 self.pending = Some(PendingCommand::Cancel { sequence });
184 Ok(TimerControlAction::None)
185 }
186 }
187 }
188
189 pub fn reconcile(&mut self, deadline_ns: u64) -> Result<TimerControlAction, TimerControlError> {
191 let sequence = self.next_request_sequence()?;
192
193 match self.registration {
194 TimerRegistration::Unregistered => {
195 let generation = self.next_generation()?;
196 self.request_sequence = sequence;
197 self.generation = generation;
198 self.registration = TimerRegistration::Scheduled {
199 generation,
200 deadline_ns,
201 };
202 Ok(TimerControlAction::Arm {
203 generation,
204 deadline_ns,
205 })
206 }
207 TimerRegistration::Scheduled {
208 deadline_ns: current_deadline,
209 ..
210 } if deadline_ns == current_deadline => {
211 self.request_sequence = sequence;
212 Ok(TimerControlAction::None)
213 }
214 TimerRegistration::Scheduled { .. } => {
215 let generation = self.next_generation()?;
216 self.request_sequence = sequence;
217 self.generation = generation;
218 self.registration = TimerRegistration::Scheduled {
219 generation,
220 deadline_ns,
221 };
222 Ok(TimerControlAction::Replace {
223 generation,
224 deadline_ns,
225 })
226 }
227 TimerRegistration::Running { .. } => {
228 self.request_sequence = sequence;
229 self.pending = Some(PendingCommand::Reconcile {
230 sequence,
231 deadline_ns,
232 });
233 Ok(TimerControlAction::None)
234 }
235 }
236 }
237
238 pub const fn begin(&mut self, generation: u64) -> bool {
240 match self.registration {
241 TimerRegistration::Scheduled {
242 generation: scheduled_generation,
243 ..
244 } if scheduled_generation == generation => {
245 self.registration = TimerRegistration::Running { generation };
246 true
247 }
248 TimerRegistration::Unregistered
249 | TimerRegistration::Scheduled { .. }
250 | TimerRegistration::Running { .. } => false,
251 }
252 }
253
254 pub fn complete(
257 &mut self,
258 generation: u64,
259 directive_deadline_ns: Option<u64>,
260 ) -> Result<TimerControlAction, TimerControlError> {
261 if self.registration != (TimerRegistration::Running { generation }) {
262 return Err(TimerControlError::StaleCompletion);
263 }
264
265 let (deadline_ns, cancelled) = match self.pending {
266 Some(PendingCommand::Cancel { .. }) => (None, true),
267 Some(PendingCommand::Reconcile { deadline_ns, .. }) => (Some(deadline_ns), false),
268 Some(PendingCommand::Schedule { deadline_ns, .. }) => (
269 Some(
270 directive_deadline_ns
271 .map_or(deadline_ns, |directive| directive.min(deadline_ns)),
272 ),
273 false,
274 ),
275 None => (directive_deadline_ns, false),
276 };
277
278 let next_generation = if deadline_ns.is_some() {
279 Some(self.next_generation()?)
280 } else {
281 None
282 };
283
284 self.pending = None;
285 if let (Some(deadline_ns), Some(next_generation)) = (deadline_ns, next_generation) {
286 self.generation = next_generation;
287 self.registration = TimerRegistration::Scheduled {
288 generation: next_generation,
289 deadline_ns,
290 };
291 Ok(TimerControlAction::Arm {
292 generation: next_generation,
293 deadline_ns,
294 })
295 } else {
296 self.registration = TimerRegistration::Unregistered;
297 Ok(TimerControlAction::Disarm { cancelled })
298 }
299 }
300
301 fn next_generation(&self) -> Result<u64, TimerControlError> {
302 self.generation
303 .checked_add(1)
304 .ok_or(TimerControlError::GenerationExhausted)
305 }
306
307 fn next_request_sequence(&self) -> Result<u64, TimerControlError> {
308 self.request_sequence
309 .checked_add(1)
310 .ok_or(TimerControlError::RequestSequenceExhausted)
311 }
312}
313
314#[cfg(test)]
315mod tests {
316 use super::*;
317
318 fn arm(control: &mut TimerControl, deadline_ns: u64) -> u64 {
319 let TimerControlAction::Arm { generation, .. } = control
320 .schedule(deadline_ns)
321 .expect("initial schedule should succeed")
322 else {
323 panic!("initial schedule should arm");
324 };
325 generation
326 }
327
328 #[test]
329 fn duplicate_and_later_schedules_keep_one_earliest_handle() {
330 let mut control = TimerControl::default();
331 assert_eq!(arm(&mut control, 100), 1);
332 assert_eq!(control.schedule(100), Ok(TimerControlAction::None));
333 assert_eq!(control.schedule(200), Ok(TimerControlAction::None));
334 assert_eq!(
335 control.registration(),
336 TimerRegistration::Scheduled {
337 generation: 1,
338 deadline_ns: 100
339 }
340 );
341 }
342
343 #[test]
344 fn earlier_schedule_replaces_and_invalidates_old_generation() {
345 let mut control = TimerControl::default();
346 let old_generation = arm(&mut control, 100);
347 assert_eq!(
348 control.schedule(50),
349 Ok(TimerControlAction::Replace {
350 generation: 2,
351 deadline_ns: 50
352 })
353 );
354 assert!(!control.begin(old_generation));
355 assert!(control.begin(2));
356 }
357
358 #[test]
359 fn authoritative_reconciliation_can_move_scheduled_deadline_later() {
360 let mut control = TimerControl::default();
361 let old_generation = arm(&mut control, 100);
362 assert_eq!(
363 control.reconcile(200),
364 Ok(TimerControlAction::Replace {
365 generation: 2,
366 deadline_ns: 200
367 })
368 );
369 assert!(!control.begin(old_generation));
370 assert!(control.begin(2));
371 }
372
373 #[test]
374 fn authoritative_reconciliation_while_running_replaces_callback_deadline() {
375 let mut control = TimerControl::default();
376 let generation = arm(&mut control, 100);
377 assert!(control.begin(generation));
378 assert_eq!(control.reconcile(300), Ok(TimerControlAction::None));
379 assert_eq!(
380 control.complete(generation, Some(150)),
381 Ok(TimerControlAction::Arm {
382 generation: 2,
383 deadline_ns: 300
384 })
385 );
386 }
387
388 #[test]
389 fn schedule_while_running_waits_and_survives_callback_stop() {
390 let mut control = TimerControl::default();
391 let generation = arm(&mut control, 100);
392 assert!(control.begin(generation));
393 assert_eq!(control.schedule(90), Ok(TimerControlAction::None));
394 assert_eq!(
395 control.complete(generation, None),
396 Ok(TimerControlAction::Arm {
397 generation: 2,
398 deadline_ns: 90
399 })
400 );
401 }
402
403 #[test]
404 fn running_callback_can_request_its_own_cancellation() {
405 let mut control = TimerControl::default();
406 let generation = arm(&mut control, 100);
407 assert!(control.begin(generation));
408 assert_eq!(control.cancel(), Ok(TimerControlAction::None));
409 assert_eq!(
410 control.complete(generation, Some(200)),
411 Ok(TimerControlAction::Disarm { cancelled: true })
412 );
413 assert_eq!(control.registration(), TimerRegistration::Unregistered);
414 }
415
416 #[test]
417 fn running_schedule_coalesces_to_earliest_deadline() {
418 let mut control = TimerControl::default();
419 let generation = arm(&mut control, 100);
420 assert!(control.begin(generation));
421 assert_eq!(control.schedule(300), Ok(TimerControlAction::None));
422 assert_eq!(control.schedule(250), Ok(TimerControlAction::None));
423 assert_eq!(
424 control.complete(generation, Some(275)),
425 Ok(TimerControlAction::Arm {
426 generation: 2,
427 deadline_ns: 250
428 })
429 );
430 }
431
432 #[test]
433 fn later_cancel_suppresses_callback_rearm() {
434 let mut control = TimerControl::default();
435 let generation = arm(&mut control, 100);
436 assert!(control.begin(generation));
437 assert_eq!(control.schedule(80), Ok(TimerControlAction::None));
438 assert_eq!(control.cancel(), Ok(TimerControlAction::None));
439 assert_eq!(
440 control.complete(generation, Some(75)),
441 Ok(TimerControlAction::Disarm { cancelled: true })
442 );
443 }
444
445 #[test]
446 fn schedule_after_cancel_reenables_only_after_completion() {
447 let mut control = TimerControl::default();
448 let generation = arm(&mut control, 100);
449 assert!(control.begin(generation));
450 assert_eq!(control.cancel(), Ok(TimerControlAction::None));
451 assert_eq!(control.schedule(90), Ok(TimerControlAction::None));
452 assert_eq!(
453 control.complete(generation, Some(95)),
454 Ok(TimerControlAction::Arm {
455 generation: 2,
456 deadline_ns: 90
457 })
458 );
459 }
460
461 #[test]
462 fn scheduled_cancel_invalidates_consumed_generation() {
463 let mut control = TimerControl::default();
464 let generation = arm(&mut control, 100);
465 assert_eq!(control.cancel(), Ok(TimerControlAction::Clear));
466 assert!(!control.begin(generation));
467 assert_eq!(control.generation(), 2);
468 assert_eq!(control.registration(), TimerRegistration::Unregistered);
469 }
470
471 #[test]
472 fn stale_completion_cannot_change_current_registration() {
473 let mut control = TimerControl::default();
474 let generation = arm(&mut control, 100);
475 assert!(control.begin(generation));
476 assert_eq!(
477 control.complete(generation + 1, None),
478 Err(TimerControlError::StaleCompletion)
479 );
480 assert_eq!(
481 control.registration(),
482 TimerRegistration::Running { generation }
483 );
484 }
485
486 #[test]
487 fn exhausted_request_sequence_fails_without_mutating_registration() {
488 let mut control = TimerControl {
489 request_sequence: u64::MAX,
490 ..TimerControl::default()
491 };
492
493 assert_eq!(
494 control.schedule(100),
495 Err(TimerControlError::RequestSequenceExhausted)
496 );
497 assert_eq!(control.registration(), TimerRegistration::Unregistered);
498 }
499
500 #[test]
501 fn exhausted_generation_fails_without_replacing_current_handle() {
502 let mut control = TimerControl {
503 generation: u64::MAX,
504 registration: TimerRegistration::Scheduled {
505 generation: u64::MAX,
506 deadline_ns: 100,
507 },
508 ..TimerControl::default()
509 };
510
511 assert_eq!(
512 control.schedule(50),
513 Err(TimerControlError::GenerationExhausted)
514 );
515 assert_eq!(
516 control.registration(),
517 TimerRegistration::Scheduled {
518 generation: u64::MAX,
519 deadline_ns: 100
520 }
521 );
522 }
523}