1use alloc::collections::{BinaryHeap, binary_heap};
8use core::hash::Hash;
9use core::time::Duration;
10
11use netstack3_hashmap::{HashMap, hash_map};
12
13use crate::{CoreTimerContext, Instant, InstantBindingsTypes, TimerBindingsTypes, TimerContext};
14
15#[derive(Debug)]
25pub struct LocalTimerHeap<K, V, BT: TimerBindingsTypes + InstantBindingsTypes> {
26 next_wakeup: BT::Timer,
27 heap: KeyedHeap<K, V, BT::Instant>,
28}
29
30impl<K, V, BC> LocalTimerHeap<K, V, BC>
31where
32 K: Hash + Eq + Clone,
33 BC: TimerContext,
34{
35 pub fn new(bindings_ctx: &mut BC, dispatch_id: BC::DispatchId) -> Self {
37 let next_wakeup = bindings_ctx.new_timer(dispatch_id);
38 Self { next_wakeup, heap: KeyedHeap::new() }
39 }
40
41 pub fn new_with_context<D, CC: CoreTimerContext<D, BC>>(
43 bindings_ctx: &mut BC,
44 dispatch_id: D,
45 ) -> Self {
46 Self::new(bindings_ctx, CC::convert_timer(dispatch_id))
47 }
48
49 pub fn schedule_instant(
54 &mut self,
55 bindings_ctx: &mut BC,
56 timer: K,
57 value: V,
58 at: BC::Instant,
59 ) -> Option<(BC::Instant, V)> {
60 let (prev_value, timer_change) = self.heap.schedule(timer, value, at);
61 self.apply_timer_change(bindings_ctx, timer_change);
62 prev_value
63 }
64
65 pub fn schedule_after(
72 &mut self,
73 bindings_ctx: &mut BC,
74 timer: K,
75 value: V,
76 after: Duration,
77 ) -> Option<(BC::Instant, V)> {
78 let time = bindings_ctx.now().checked_add(after).unwrap();
79 self.schedule_instant(bindings_ctx, timer, value, time)
80 }
81
82 pub fn pop(&mut self, bindings_ctx: &mut BC) -> Option<(K, V)> {
84 let (popped, timer_change) = self.heap.pop_if(|t| t <= bindings_ctx.now());
85 self.apply_timer_change(bindings_ctx, timer_change);
86 popped
87 }
88
89 pub fn get(&self, timer: &K) -> Option<(BC::Instant, &V)> {
92 self.heap.map.get(timer).map(|MapEntry { time, value, synced_with_heap: _ }| (*time, value))
93 }
94
95 pub fn cancel(&mut self, bindings_ctx: &mut BC, timer: &K) -> Option<(BC::Instant, V)> {
98 let (scheduled, timer_change) = self.heap.cancel(timer);
99 self.apply_timer_change(bindings_ctx, timer_change);
100 scheduled
101 }
102
103 pub fn iter(&self) -> impl Iterator<Item = (&K, &V, &BC::Instant)> {
105 self.heap
106 .map
107 .iter()
108 .map(|(k, MapEntry { time, value, synced_with_heap: _ })| (k, value, time))
109 }
110
111 fn apply_timer_change(
112 &mut self,
113 bindings_ctx: &mut BC,
114 timer_change: Option<TimerChange<BC::Instant>>,
115 ) {
116 let _: Option<BC::Instant> = match timer_change {
117 Some(TimerChange::Scheduled(time)) => {
118 bindings_ctx.schedule_timer_instant(time, &mut self.next_wakeup)
119 }
120 Some(TimerChange::Canceled) => bindings_ctx.cancel_timer(&mut self.next_wakeup),
121 None => None,
122 };
123 }
124
125 pub fn clear(&mut self, bindings_ctx: &mut BC) {
127 let Self { next_wakeup, heap } = self;
128 heap.clear();
129 let _: Option<BC::Instant> = bindings_ctx.cancel_timer(next_wakeup);
130 }
131
132 pub fn is_empty(&self) -> bool {
134 self.heap.map.is_empty()
135 }
136}
137
138enum TimerChange<T> {
140 Canceled,
141 Scheduled(T),
142}
143
144#[derive(Debug)]
151struct KeyedHeap<K, V, T> {
152 map: HashMap<K, MapEntry<T, V>>,
159 heap: BinaryHeap<HeapEntry<T, K>>,
160}
161
162const GC_MIN_HEAP_SIZE: usize = 20;
164
165impl<K: Hash + Eq + Clone, V, T: Instant> KeyedHeap<K, V, T> {
166 fn new() -> Self {
167 Self { map: HashMap::new(), heap: BinaryHeap::new() }
168 }
169
170 fn maybe_gc(&mut self) -> bool {
175 let Self { map, heap } = self;
176 let threshold = GC_MIN_HEAP_SIZE.max(map.len() * 2);
177 if heap.len() > threshold {
178 heap.clear();
182 heap.extend(map.iter_mut().map(
183 |(key, MapEntry { time, value: _, synced_with_heap })| {
184 *synced_with_heap = true;
185 HeapEntry { time: *time, key: key.clone() }
186 },
187 ));
188 true
189 } else {
190 false
191 }
192 }
193
194 fn schedule(&mut self, key: K, value: V, at: T) -> (Option<(T, V)>, Option<TimerChange<T>>) {
199 let Self { map, heap } = self;
200 let was_front =
201 heap.peek().is_some_and(|HeapEntry { time: _, key: top_key }| top_key == &key);
202 let is_new_front =
203 heap.peek().map(|HeapEntry { time: top_time, key: _ }| at <= *top_time).unwrap_or(true);
204 let (heap_entry, prev) = match map.entry(key) {
205 hash_map::Entry::Occupied(mut o) => {
206 let MapEntry { time: prev_time, value: _, synced_with_heap } = o.get();
207 let (synced_with_heap, heap_entry) = match at.cmp(prev_time) {
212 core::cmp::Ordering::Less => {
213 (true, Some(HeapEntry { time: at, key: o.key().clone() }))
214 }
215 core::cmp::Ordering::Equal => (*synced_with_heap, None),
216 core::cmp::Ordering::Greater => (false, None),
217 };
218 let MapEntry { time, value, synced_with_heap: _ } =
219 o.insert(MapEntry { time: at, value, synced_with_heap });
220 (heap_entry, Some((time, value)))
221 }
222 hash_map::Entry::Vacant(v) => {
223 let heap_entry = Some(HeapEntry { time: at, key: v.key().clone() });
224 let _: &mut MapEntry<_, _> =
225 v.insert(MapEntry { time: at, value, synced_with_heap: true });
226 (heap_entry, None)
227 }
228 };
229 let did_gc = match heap_entry {
230 Some(heap_entry) => {
231 heap.push(heap_entry);
232 self.maybe_gc()
233 }
234 None => false,
235 };
236 if was_front && !is_new_front {
237 let new_top = if did_gc {
239 self.heap.peek().map(|HeapEntry { time, key: _ }| *time)
240 } else {
241 self.heal()
242 }
243 .expect("heap cannot be empty after a `schedule` operation");
244 return (prev, Some(TimerChange::Scheduled(new_top)));
245 }
246 (prev, is_new_front.then_some(TimerChange::Scheduled(at)))
247 }
248
249 fn cancel(&mut self, key: &K) -> (Option<(T, V)>, Option<TimerChange<T>>) {
254 let Self { heap, map } = self;
255 let Some(MapEntry { time, value, synced_with_heap: _ }) = map.remove(key) else {
256 return (None, None);
257 };
258 let was_front = heap.peek().is_some_and(|HeapEntry { time: _, key: top }| key == top);
260 let did_gc = self.maybe_gc();
261 let timer_change = was_front.then(|| {
262 let new_top = if did_gc {
264 self.heap.peek().map(|HeapEntry { time, key: _ }| *time)
265 } else {
266 self.heal()
267 };
268 match new_top {
269 Some(new_top) => TimerChange::Scheduled(new_top),
270 None => TimerChange::Canceled,
271 }
272 });
273 (Some((time, value)), timer_change)
274 }
275
276 fn pop_if<F: FnOnce(T) -> bool>(&mut self, f: F) -> (Option<(K, V)>, Option<TimerChange<T>>) {
285 let Self { heap, map } = self;
286 let Some(peek_mut) = heap.peek_mut() else {
287 return (None, None);
288 };
289 if !f(peek_mut.time) {
290 return (None, None);
291 }
292 let HeapEntry { time: heap_time, key } = binary_heap::PeekMut::pop(peek_mut);
293 let MapEntry { time: scheduled_for, value, synced_with_heap } =
294 map.remove(&key).expect("top of heap must be present in map");
295 debug_assert_eq!(heap_time, scheduled_for);
298 debug_assert!(synced_with_heap);
299 let timer_change = match self.heal() {
300 Some(new_top) => TimerChange::Scheduled(new_top),
301 None => TimerChange::Canceled,
302 };
303 (Some((key, value)), Some(timer_change))
304 }
305
306 fn heal(&mut self) -> Option<T> {
309 let Self { heap, map } = self;
310 loop {
311 let peek_mut = heap.peek_mut()?;
312 let HeapEntry { time: heap_time, key } = &*peek_mut;
313 match map.entry(key.clone()) {
319 hash_map::Entry::Vacant(_) => {
320 let _: HeapEntry<_, _> = binary_heap::PeekMut::pop(peek_mut);
326 }
327 hash_map::Entry::Occupied(mut map_entry) => {
328 let MapEntry { time: scheduled_for, value: _, synced_with_heap } =
329 map_entry.get_mut();
330
331 match heap_time.cmp(scheduled_for) {
332 core::cmp::Ordering::Equal => {
333 *synced_with_heap = true;
336 return Some(*scheduled_for);
337 }
338 core::cmp::Ordering::Less => {
339 let HeapEntry { time: _, key } = binary_heap::PeekMut::pop(peek_mut);
347 if !*synced_with_heap {
348 heap.push(HeapEntry { time: *scheduled_for, key });
349 *synced_with_heap = true;
350 }
351 }
352 core::cmp::Ordering::Greater => {
353 unreachable!(
361 "observed heap time: {:?} later than the scheduled time {:?}",
362 heap_time, scheduled_for
363 );
364 }
365 }
366 }
367 }
368 }
369 }
370
371 fn clear(&mut self) {
372 let Self { map, heap } = self;
373 map.clear();
374 heap.clear();
375 }
376}
377
378#[derive(Debug)]
380struct MapEntry<T, V> {
381 time: T,
382 value: V,
383 synced_with_heap: bool,
386}
387
388#[derive(Debug)]
392struct HeapEntry<T, K> {
393 time: T,
394 key: K,
395}
396
397impl<T: Instant, K> PartialEq for HeapEntry<T, K> {
399 fn eq(&self, other: &Self) -> bool {
400 self.time == other.time
401 }
402}
403
404impl<T: Instant, K> Eq for HeapEntry<T, K> {}
405
406impl<T: Instant, K> Ord for HeapEntry<T, K> {
407 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
408 Ord::cmp(&other.time, &self.time)
411 }
412}
413
414impl<T: Instant, K> PartialOrd for HeapEntry<T, K> {
415 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
416 Some(Ord::cmp(self, other))
417 }
418}
419
420#[cfg(any(test, feature = "testutils"))]
421mod testutil {
422 use core::fmt::Debug;
423 use core::ops::RangeBounds;
424
425 use super::*;
426
427 impl<K, V, BC> LocalTimerHeap<K, V, BC>
428 where
429 K: Hash + Eq + Clone + Debug,
430 V: Debug + Eq + Clone + PartialEq,
431 BC: TimerContext,
432 {
433 #[track_caller]
436 pub fn assert_timers(&self, timers: impl IntoIterator<Item = (K, V, BC::Instant)>) {
437 let wanted = timers.into_iter().map(|(k, v, i)| (k, (v, i))).collect::<HashMap<_, _>>();
438 let actual = self
439 .heap
440 .map
441 .iter()
442 .map(|(k, MapEntry { value, time, synced_with_heap: _ })| {
443 (k.clone(), (value.clone(), *time))
444 })
445 .collect::<HashMap<_, _>>();
446 assert_eq!(actual, wanted);
447 }
448
449 #[track_caller]
452 pub fn assert_timers_after(
453 &self,
454 bindings_ctx: &mut BC,
455 timers: impl IntoIterator<Item = (K, V, Duration)>,
456 ) {
457 let now = bindings_ctx.now();
458 self.assert_timers(timers.into_iter().map(|(k, v, d)| (k, v, now.panicking_add(d))))
459 }
460
461 #[track_caller]
463 pub fn assert_top(&mut self, key: &K, value: &V) {
464 let top = self.heap.heap.peek().map(|HeapEntry { time: heap_time, key }| {
467 let MapEntry { time: map_time, value, synced_with_heap } =
468 self.heap.map.get(key).expect("top of heap must be present in map");
469 assert_eq!(heap_time, map_time);
470 assert!(synced_with_heap);
471 (key, value)
472 });
473 assert_eq!(top, Some((key, value)));
474 }
475
476 #[track_caller]
479 pub fn assert_range<
480 'a,
481 R: RangeBounds<BC::Instant> + Debug,
482 I: IntoIterator<Item = (&'a K, R)>,
483 >(
484 &'a self,
485 expect: I,
486 ) {
487 for (timer, range) in expect {
488 let time = self
489 .get(timer)
490 .map(|(t, _)| t)
491 .unwrap_or_else(|| panic!("timer {timer:?} not present"));
492 assert!(range.contains(&time), "timer {timer:?} is at {time:?} not in {range:?}");
493 }
494 }
495
496 #[track_caller]
499 pub fn assert_range_single<'a, R: RangeBounds<BC::Instant> + Debug>(
500 &'a self,
501 timer: &K,
502 range: R,
503 ) -> (BC::Instant, &'a V) {
504 let (time, value) =
505 self.get(timer).unwrap_or_else(|| panic!("timer {timer:?} not present"));
506 assert!(range.contains(&time), "timer {timer:?} is at {time:?} not in {range:?}");
507 (time, value)
508 }
509 }
510}
511
512#[cfg(test)]
513mod tests {
514 use alloc::vec::Vec;
515
516 use crate::InstantContext;
517 use crate::testutil::{FakeAtomicInstant, FakeInstant, FakeInstantCtx};
518
519 use super::*;
520
521 #[derive(Default)]
522 struct FakeTimerCtx {
523 instant: FakeInstantCtx,
524 }
525
526 impl InstantBindingsTypes for FakeTimerCtx {
527 type Instant = FakeInstant;
528 type AtomicInstant = FakeAtomicInstant;
529 }
530
531 impl InstantContext for FakeTimerCtx {
532 fn now(&self) -> Self::Instant {
533 self.instant.now()
534 }
535 }
536
537 impl TimerBindingsTypes for FakeTimerCtx {
538 type Timer = FakeTimer;
539 type DispatchId = ();
540 type UniqueTimerId = !;
541 }
542
543 impl TimerContext for FakeTimerCtx {
544 fn new_timer(&mut self, (): Self::DispatchId) -> Self::Timer {
545 FakeTimer::default()
546 }
547
548 fn schedule_timer_instant(
549 &mut self,
550 time: Self::Instant,
551 timer: &mut Self::Timer,
552 ) -> Option<Self::Instant> {
553 timer.scheduled.replace(time)
554 }
555
556 fn cancel_timer(&mut self, timer: &mut Self::Timer) -> Option<Self::Instant> {
557 timer.scheduled.take()
558 }
559
560 fn scheduled_instant(&self, timer: &mut Self::Timer) -> Option<Self::Instant> {
561 timer.scheduled.clone()
562 }
563
564 fn unique_timer_id(&self, _: &Self::Timer) -> Self::UniqueTimerId {
565 unimplemented!()
566 }
567 }
568
569 #[derive(Default, Debug)]
570 struct FakeTimer {
571 scheduled: Option<FakeInstant>,
572 }
573
574 #[derive(Eq, PartialEq, Debug, Ord, PartialOrd, Copy, Clone, Hash)]
575 struct TimerId(usize);
576
577 type LocalTimerHeap = super::LocalTimerHeap<TimerId, (), FakeTimerCtx>;
578
579 impl LocalTimerHeap {
580 fn heap_len(&self) -> usize {
581 self.heap.heap.len()
582 }
583
584 #[track_caller]
585 fn assert_heap_entries<I: IntoIterator<Item = (FakeInstant, TimerId)>>(&self, i: I) {
586 let mut want = i.into_iter().collect::<Vec<_>>();
587 want.sort();
588 let mut got = self
589 .heap
590 .heap
591 .iter()
592 .map(|HeapEntry { time, key }| (*time, *key))
593 .collect::<Vec<_>>();
594 got.sort();
595 assert_eq!(got, want);
596 }
597
598 #[track_caller]
599 fn assert_map_entries<I: IntoIterator<Item = (FakeInstant, TimerId)>>(&self, i: I) {
600 let want = i.into_iter().map(|(t, k)| (k, t)).collect::<HashMap<_, _>>();
601 let got = self
602 .heap
603 .map
604 .iter()
605 .map(|(k, MapEntry { time, value: (), synced_with_heap: _ })| (*k, *time))
606 .collect::<HashMap<_, _>>();
607 assert_eq!(got, want);
608 }
609 }
610
611 const TIMER1: TimerId = TimerId(1);
612 const TIMER2: TimerId = TimerId(2);
613 const TIMER3: TimerId = TimerId(3);
614
615 const T1: FakeInstant = FakeInstant { offset: Duration::from_secs(1) };
616 const T2: FakeInstant = FakeInstant { offset: Duration::from_secs(2) };
617 const T3: FakeInstant = FakeInstant { offset: Duration::from_secs(3) };
618 const T4: FakeInstant = FakeInstant { offset: Duration::from_secs(4) };
619 const T5: FakeInstant = FakeInstant { offset: Duration::from_secs(5) };
620
621 #[test]
622 fn schedule_instant() {
623 let mut ctx = FakeTimerCtx::default();
624 let mut heap = LocalTimerHeap::new(&mut ctx, ());
625 assert_eq!(heap.next_wakeup.scheduled, None);
626 heap.assert_heap_entries([]);
627
628 assert_eq!(heap.schedule_instant(&mut ctx, TIMER2, (), T2), None);
629 heap.assert_heap_entries([(T2, TIMER2)]);
630 assert_eq!(heap.next_wakeup.scheduled, Some(T2));
631
632 assert_eq!(heap.schedule_instant(&mut ctx, TIMER1, (), T1), None);
633 heap.assert_heap_entries([(T1, TIMER1), (T2, TIMER2)]);
634 assert_eq!(heap.next_wakeup.scheduled, Some(T1));
635
636 assert_eq!(heap.schedule_instant(&mut ctx, TIMER3, (), T3), None);
637 heap.assert_heap_entries([(T1, TIMER1), (T2, TIMER2), (T3, TIMER3)]);
638 assert_eq!(heap.next_wakeup.scheduled, Some(T1));
639 }
640
641 #[test]
642 fn schedule_after() {
643 let mut ctx = FakeTimerCtx::default();
644 let mut heap = LocalTimerHeap::new(&mut ctx, ());
645 assert_eq!(heap.next_wakeup.scheduled, None);
646 let long_duration = Duration::from_secs(5);
647 let short_duration = Duration::from_secs(1);
648
649 let long_instant = ctx.now().checked_add(long_duration).unwrap();
650 let short_instant = ctx.now().checked_add(short_duration).unwrap();
651
652 assert_eq!(heap.schedule_after(&mut ctx, TIMER1, (), long_duration), None);
653 assert_eq!(heap.next_wakeup.scheduled, Some(long_instant));
654 heap.assert_heap_entries([(long_instant, TIMER1)]);
655 heap.assert_map_entries([(long_instant, TIMER1)]);
656
657 assert_eq!(
658 heap.schedule_after(&mut ctx, TIMER1, (), short_duration),
659 Some((long_instant, ()))
660 );
661 assert_eq!(heap.next_wakeup.scheduled, Some(short_instant));
662 heap.assert_heap_entries([(short_instant, TIMER1), (long_instant, TIMER1)]);
663 heap.assert_map_entries([(short_instant, TIMER1)]);
664 }
665
666 #[test]
667 fn cancel() {
668 let mut ctx = FakeTimerCtx::default();
669 let mut heap = LocalTimerHeap::new(&mut ctx, ());
670 assert_eq!(heap.schedule_instant(&mut ctx, TIMER1, (), T1), None);
671 assert_eq!(heap.schedule_instant(&mut ctx, TIMER2, (), T2), None);
672 assert_eq!(heap.schedule_instant(&mut ctx, TIMER3, (), T3), None);
673 heap.assert_heap_entries([(T1, TIMER1), (T2, TIMER2), (T3, TIMER3)]);
674 assert_eq!(heap.next_wakeup.scheduled, Some(T1));
675
676 assert_eq!(heap.cancel(&mut ctx, &TIMER1), Some((T1, ())));
677 heap.assert_heap_entries([(T2, TIMER2), (T3, TIMER3)]);
678 heap.assert_map_entries([(T2, TIMER2), (T3, TIMER3)]);
679 assert_eq!(heap.next_wakeup.scheduled, Some(T2));
680
681 assert_eq!(heap.cancel(&mut ctx, &TIMER1), None);
682
683 assert_eq!(heap.cancel(&mut ctx, &TIMER3), Some((T3, ())));
684 heap.assert_heap_entries([(T2, TIMER2), (T3, TIMER3)]);
686 heap.assert_map_entries([(T2, TIMER2)]);
687 assert_eq!(heap.next_wakeup.scheduled, Some(T2));
688
689 assert_eq!(heap.cancel(&mut ctx, &TIMER2), Some((T2, ())));
690 heap.assert_heap_entries([]);
691 heap.assert_map_entries([]);
692 assert_eq!(heap.next_wakeup.scheduled, None);
693 }
694
695 #[test]
696 fn pop() {
697 let mut ctx = FakeTimerCtx::default();
698 let mut heap = LocalTimerHeap::new(&mut ctx, ());
699 assert_eq!(heap.schedule_instant(&mut ctx, TIMER1, (), T1), None);
700 assert_eq!(heap.schedule_instant(&mut ctx, TIMER2, (), T2), None);
701 assert_eq!(heap.schedule_instant(&mut ctx, TIMER3, (), T3), None);
702 heap.assert_heap_entries([(T1, TIMER1), (T2, TIMER2), (T3, TIMER3)]);
703 heap.assert_map_entries([(T1, TIMER1), (T2, TIMER2), (T3, TIMER3)]);
704 assert_eq!(heap.next_wakeup.scheduled, Some(T1));
705
706 assert_eq!(heap.pop(&mut ctx), None);
707 heap.assert_heap_entries([(T1, TIMER1), (T2, TIMER2), (T3, TIMER3)]);
708 heap.assert_map_entries([(T1, TIMER1), (T2, TIMER2), (T3, TIMER3)]);
709 assert_eq!(heap.next_wakeup.scheduled, Some(T1));
710
711 ctx.instant.time = T1;
712 assert_eq!(heap.pop(&mut ctx), Some((TIMER1, ())));
713 heap.assert_heap_entries([(T2, TIMER2), (T3, TIMER3)]);
714 heap.assert_map_entries([(T2, TIMER2), (T3, TIMER3)]);
715 assert_eq!(heap.next_wakeup.scheduled, Some(T2));
716 assert_eq!(heap.pop(&mut ctx), None);
717 assert_eq!(heap.next_wakeup.scheduled, Some(T2));
718
719 ctx.instant.time = T3;
720 assert_eq!(heap.pop(&mut ctx), Some((TIMER2, ())));
721 heap.assert_heap_entries([(T3, TIMER3)]);
722 heap.assert_map_entries([(T3, TIMER3)]);
723
724 assert_eq!(heap.next_wakeup.scheduled, Some(T3));
725 assert_eq!(heap.pop(&mut ctx), Some((TIMER3, ())));
726 heap.assert_heap_entries([]);
727 heap.assert_map_entries([]);
728 assert_eq!(heap.next_wakeup.scheduled, None);
729
730 assert_eq!(heap.pop(&mut ctx), None);
731 }
732
733 #[test]
734 fn reschedule() {
735 let mut ctx = FakeTimerCtx::default();
736 let mut heap = LocalTimerHeap::new(&mut ctx, ());
737 assert_eq!(heap.schedule_instant(&mut ctx, TIMER1, (), T1), None);
738 assert_eq!(heap.schedule_instant(&mut ctx, TIMER2, (), T2), None);
739 assert_eq!(heap.schedule_instant(&mut ctx, TIMER3, (), T3), None);
740 heap.assert_heap_entries([(T1, TIMER1), (T2, TIMER2), (T3, TIMER3)]);
741 heap.assert_map_entries([(T1, TIMER1), (T2, TIMER2), (T3, TIMER3)]);
742 assert_eq!(heap.next_wakeup.scheduled, Some(T1));
743
744 assert_eq!(heap.schedule_instant(&mut ctx, TIMER2, (), T4), Some((T2, ())));
745 heap.assert_heap_entries([(T1, TIMER1), (T2, TIMER2), (T3, TIMER3)]);
746 heap.assert_map_entries([(T1, TIMER1), (T4, TIMER2), (T3, TIMER3)]);
747
748 ctx.instant.time = T4;
749 assert_eq!(heap.pop(&mut ctx), Some((TIMER1, ())));
751 heap.assert_heap_entries([(T4, TIMER2), (T3, TIMER3)]);
752 heap.assert_map_entries([(T4, TIMER2), (T3, TIMER3)]);
753 assert_eq!(heap.next_wakeup.scheduled, Some(T3));
754
755 assert_eq!(heap.schedule_instant(&mut ctx, TIMER2, (), T2), Some((T4, ())));
756 heap.assert_heap_entries([(T2, TIMER2), (T4, TIMER2), (T3, TIMER3)]);
757 heap.assert_map_entries([(T2, TIMER2), (T3, TIMER3)]);
758 assert_eq!(heap.next_wakeup.scheduled, Some(T2));
759
760 assert_eq!(heap.pop(&mut ctx), Some((TIMER2, ())));
761 heap.assert_heap_entries([(T4, TIMER2), (T3, TIMER3)]);
763 heap.assert_map_entries([(T3, TIMER3)]);
764 assert_eq!(heap.next_wakeup.scheduled, Some(T3));
765
766 assert_eq!(heap.pop(&mut ctx), Some((TIMER3, ())));
767 heap.assert_heap_entries([]);
768 heap.assert_map_entries([]);
769 assert_eq!(heap.next_wakeup.scheduled, None);
770 assert_eq!(heap.pop(&mut ctx), None);
771 }
772
773 #[test]
774 fn reschedule_later_heals_stale_entries() {
775 let mut ctx = FakeTimerCtx::default();
776 let mut heap = LocalTimerHeap::new(&mut ctx, ());
777
778 assert_eq!(heap.schedule_instant(&mut ctx, TIMER1, (), T3), None);
781 assert_eq!(heap.schedule_instant(&mut ctx, TIMER1, (), T2), Some((T3, ())));
782 assert_eq!(heap.schedule_instant(&mut ctx, TIMER1, (), T1), Some((T2, ())));
783 heap.assert_heap_entries([(T1, TIMER1), (T2, TIMER1), (T3, TIMER1)]);
784 heap.assert_map_entries([(T1, TIMER1)]);
785
786 assert_eq!(heap.schedule_instant(&mut ctx, TIMER1, (), T4), Some((T1, ())));
789 heap.assert_heap_entries([(T4, TIMER1)]);
790 heap.assert_map_entries([(T4, TIMER1)]);
791 assert_eq!(heap.next_wakeup.scheduled, Some(T4));
792 }
793
794 #[test]
795 fn reschedule_later_heals_stale_entries_with_multiple_timers() {
796 let mut ctx = FakeTimerCtx::default();
797 let mut heap = LocalTimerHeap::new(&mut ctx, ());
798
799 assert_eq!(heap.schedule_instant(&mut ctx, TIMER1, (), T4), None);
803 assert_eq!(heap.schedule_instant(&mut ctx, TIMER2, (), T3), None);
804 assert_eq!(heap.schedule_instant(&mut ctx, TIMER1, (), T2), Some((T4, ())));
805 assert_eq!(heap.schedule_instant(&mut ctx, TIMER1, (), T1), Some((T2, ())));
806 heap.assert_heap_entries([(T1, TIMER1), (T2, TIMER1), (T3, TIMER2), (T4, TIMER1)]);
807 heap.assert_map_entries([(T1, TIMER1), (T3, TIMER2)]);
808
809 assert_eq!(heap.schedule_instant(&mut ctx, TIMER1, (), T5), Some((T1, ())));
812 heap.assert_heap_entries([(T3, TIMER2), (T4, TIMER1), (T5, TIMER1)]);
813 heap.assert_map_entries([(T3, TIMER2), (T5, TIMER1)]);
814
815 assert_eq!(heap.next_wakeup.scheduled, Some(T3));
818 ctx.instant.time = T3;
819 assert_eq!(heap.pop(&mut ctx), Some((TIMER2, ())));
820 heap.assert_heap_entries([(T5, TIMER1)]);
821 heap.assert_map_entries([(T5, TIMER1)]);
822 }
823
824 #[test]
827 fn multiple_timers_same_instant() {
828 let mut ctx = FakeTimerCtx::default();
829 let mut heap = LocalTimerHeap::new(&mut ctx, ());
830 assert_eq!(heap.schedule_instant(&mut ctx, TIMER1, (), T1), None);
831 assert_eq!(heap.schedule_instant(&mut ctx, TIMER2, (), T1), None);
832 assert_eq!(heap.next_wakeup.scheduled.take(), Some(T1));
833
834 ctx.instant.time = T1;
835
836 assert!(heap.pop(&mut ctx).is_some());
838 assert_eq!(heap.next_wakeup.scheduled, Some(T1));
839 assert!(heap.pop(&mut ctx).is_some());
840 assert_eq!(heap.next_wakeup.scheduled, None);
841 assert_eq!(heap.pop(&mut ctx), None);
842 }
843
844 #[test]
845 fn clear() {
846 let mut ctx = FakeTimerCtx::default();
847 let mut heap = LocalTimerHeap::new(&mut ctx, ());
848 assert_eq!(heap.schedule_instant(&mut ctx, TIMER1, (), T1), None);
849 assert_eq!(heap.schedule_instant(&mut ctx, TIMER2, (), T1), None);
850 heap.clear(&mut ctx);
851 heap.assert_map_entries([]);
852 assert_eq!(heap.next_wakeup.scheduled, None);
853 }
854
855 #[test]
856 fn reschedule_single_timer_will_trigger_gc() {
857 let mut ctx = FakeTimerCtx::default();
858 let mut heap = LocalTimerHeap::new(&mut ctx, ());
859
860 let mut next_time = FakeInstant { offset: Duration::from_secs(1000) };
861 assert_eq!(heap.schedule_instant(&mut ctx, TIMER1, (), next_time), None);
862
863 for i in 1..GC_MIN_HEAP_SIZE + 1 {
867 let prev_time = next_time;
868 next_time = next_time.checked_sub(Duration::from_secs(1)).unwrap();
869 assert_eq!(
870 heap.schedule_instant(&mut ctx, TIMER1, (), next_time),
871 Some((prev_time, ()))
872 );
873 if i == GC_MIN_HEAP_SIZE {
874 assert_eq!(heap.heap_len(), 1);
876 } else {
877 assert_eq!(heap.heap_len(), 1 + i);
879 }
880 }
881 }
882
883 #[test]
884 fn reschedule_multiple_timers_will_trigger_gc() {
885 let mut ctx = FakeTimerCtx::default();
886 let mut heap = LocalTimerHeap::new(&mut ctx, ());
887
888 let num_timers = GC_MIN_HEAP_SIZE;
890 for i in 0..num_timers {
891 assert_eq!(heap.schedule_instant(&mut ctx, TimerId(i), (), T3), None);
892 }
893 assert_eq!(heap.heap_len(), num_timers);
894
895 for i in 0..num_timers {
899 assert_eq!(heap.schedule_instant(&mut ctx, TimerId(i), (), T2), Some((T3, ())));
900 }
901 assert_eq!(heap.heap_len(), num_timers * 2);
902
903 assert_eq!(heap.schedule_instant(&mut ctx, TimerId(0), (), T1), Some((T2, ())));
906 assert_eq!(heap.heap_len(), num_timers);
907 }
908
909 #[test]
910 fn cancel_will_trigger_gc() {
911 let mut ctx = FakeTimerCtx::default();
912 let mut heap = LocalTimerHeap::new(&mut ctx, ());
913
914 let num_timers = GC_MIN_HEAP_SIZE;
917 assert_eq!(heap.schedule_instant(&mut ctx, TimerId(num_timers), (), T1), None);
918 for i in 0..num_timers {
919 assert_eq!(heap.schedule_instant(&mut ctx, TimerId(i), (), T2), None);
920 }
921 assert_eq!(heap.heap_len(), num_timers + 1);
922
923 let tipping_point = num_timers / 2;
930 for i in 0..tipping_point {
931 assert_eq!(heap.cancel(&mut ctx, &TimerId(i)), Some((T2, ())));
932 assert_eq!(heap.heap_len(), num_timers + 1);
933 }
934 assert_eq!(heap.cancel(&mut ctx, &TimerId(tipping_point)), Some((T2, ())));
935 assert_eq!(heap.heap_len(), num_timers - tipping_point);
936 }
937}