shadow_rs/core/work/
event_queue.rs

1use std::cmp::Reverse;
2use std::collections::binary_heap::BinaryHeap;
3
4use shadow_shim_helper_rs::emulated_time::EmulatedTime;
5
6use super::event::Event;
7
8/// A queue of [`Event`]s ordered by their times.
9#[derive(Debug)]
10pub struct EventQueue {
11    queue: BinaryHeap<Reverse<PanickingOrd<Event>>>,
12    last_popped_event_time: EmulatedTime,
13}
14
15impl EventQueue {
16    pub fn new() -> Self {
17        Self {
18            queue: BinaryHeap::new(),
19            last_popped_event_time: EmulatedTime::SIMULATION_START,
20        }
21    }
22
23    /// Push a new [`Event`] on to the queue.
24    ///
25    /// Will panic if two events are pushed that have no relative order
26    /// (`event_a.partial_cmp(&event_b) == None`). Will be non-deterministic if two events are
27    /// pushed that are equal (`event_a == event_b`).
28    ///
29    /// Will panic if the event time is earlier than the last popped event time (time moves
30    /// backward).
31    pub fn push(&mut self, event: Event) {
32        // make sure time never moves backward
33        assert!(event.time() >= self.last_popped_event_time);
34
35        self.queue.push(Reverse(event.into()));
36    }
37
38    /// Pop the earliest [`Event`] from the queue.
39    pub fn pop(&mut self) -> Option<Event> {
40        let event = self.queue.pop().map(|x| x.0.into_inner());
41
42        // make sure time never moves backward
43        if let Some(ref event) = event {
44            assert!(event.time() >= self.last_popped_event_time);
45            self.last_popped_event_time = event.time();
46        }
47
48        event
49    }
50
51    /// The time of the next [`Event`] (the time of the earliest event in the queue).
52    pub fn next_event_time(&self) -> Option<EmulatedTime> {
53        self.queue.peek().map(|x| x.0.time())
54    }
55}
56
57impl Default for EventQueue {
58    fn default() -> Self {
59        Self::new()
60    }
61}
62
63/// A wrapper type that implements [`Ord`] for types that implement [`PartialOrd`]. If the two
64/// objects cannot be compared (`PartialOrd::partial_cmp` returns `None`), the comparison will
65/// panic.
66#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
67struct PanickingOrd<T: PartialOrd + Eq>(T);
68
69impl<T: PartialOrd + Eq> PanickingOrd<T> {
70    pub fn into_inner(self) -> T {
71        self.0
72    }
73}
74
75impl<T: PartialOrd + Eq> std::convert::From<T> for PanickingOrd<T> {
76    fn from(x: T) -> Self {
77        PanickingOrd(x)
78    }
79}
80
81impl<T: PartialOrd + Eq> PartialOrd for PanickingOrd<T> {
82    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
83        Some(self.cmp(other))
84    }
85}
86
87impl<T: PartialOrd + Eq> Ord for PanickingOrd<T> {
88    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
89        self.0.partial_cmp(&other.0).unwrap()
90    }
91}
92
93impl<T: PartialOrd + Eq> std::ops::Deref for PanickingOrd<T> {
94    type Target = T;
95
96    fn deref(&self) -> &Self::Target {
97        &self.0
98    }
99}
100
101impl<T: PartialOrd + Eq> std::ops::DerefMut for PanickingOrd<T> {
102    fn deref_mut(&mut self) -> &mut Self::Target {
103        &mut self.0
104    }
105}