shadow_rs/core/work/
event.rs

1use shadow_shim_helper_rs::HostId;
2use shadow_shim_helper_rs::emulated_time::EmulatedTime;
3
4use super::task::TaskRef;
5use crate::host::host::Host;
6use crate::network::packet::PacketRc;
7use crate::utility::{Magic, ObjectCounter};
8
9#[derive(Debug)]
10pub struct Event {
11    magic: Magic<Self>,
12    time: EmulatedTime,
13    data: EventData,
14    _counter: ObjectCounter,
15}
16
17impl Event {
18    /// A new packet event, which is an event for packets arriving from the Internet. Packet events
19    /// do not include packets on localhost.
20    pub fn new_packet(packet: PacketRc, time: EmulatedTime, src_host: &Host) -> Self {
21        Self {
22            magic: Magic::new(),
23            time,
24            data: EventData::Packet(PacketEventData {
25                packet,
26                src_host_id: src_host.id(),
27                src_host_event_id: src_host.get_new_event_id(),
28            }),
29            _counter: ObjectCounter::new("Event"),
30        }
31    }
32
33    /// A new local event, which is an event that was generated locally by the host itself (timers,
34    /// localhost packets, etc).
35    pub fn new_local(task: TaskRef, time: EmulatedTime, host: &Host) -> Self {
36        Self {
37            magic: Magic::new(),
38            time,
39            data: EventData::Local(LocalEventData {
40                task,
41                event_id: host.get_new_event_id(),
42            }),
43            _counter: ObjectCounter::new("Event"),
44        }
45    }
46
47    pub fn time(&self) -> EmulatedTime {
48        self.magic.debug_check();
49        self.time
50    }
51
52    pub fn set_time(&mut self, time: EmulatedTime) {
53        self.magic.debug_check();
54        self.time = time;
55    }
56
57    /// The event data.
58    pub fn data(self) -> EventData {
59        self.magic.debug_check();
60        self.data
61    }
62}
63
64impl PartialEq for Event {
65    fn eq(&self, other: &Self) -> bool {
66        self.magic.debug_check();
67        other.magic.debug_check();
68
69        fn check_impl_eq(_: impl Eq) {}
70
71        // below we impl Eq for Event, so we should make sure that all of our comparisons below are
72        // also Eq
73        check_impl_eq(self.time);
74        check_impl_eq(&self.data);
75
76        // check every field except '_counter'
77        self.time == other.time && self.data == other.data
78    }
79}
80
81// we checked above that Event's `PartialEq` impl is also `Eq`
82impl Eq for Event {}
83
84impl PartialOrd for Event {
85    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
86        self.magic.debug_check();
87        other.magic.debug_check();
88
89        // sort by event time, then by the event data
90        let cmp = self.time.cmp(&other.time);
91
92        if cmp.is_ne() {
93            Some(cmp)
94        } else {
95            // event times were equal
96            self.data.partial_cmp(&other.data)
97        }
98    }
99}
100
101/// Data for an event. Different event types will contain different data.
102#[derive(Debug, PartialEq, Eq, PartialOrd)]
103pub enum EventData {
104    // IMPORTANT: The order of these enum variants is important and deliberate. The `PartialOrd`
105    // derive affects the order of events in the event queue, and therefore which events are
106    // processed before others (packet events will be processed before local events), and changing
107    // this could significantly affect the simulation, possibly leading to incorrect behaviour.
108    Packet(PacketEventData),
109    Local(LocalEventData),
110}
111
112#[derive(Debug, PartialEq, Eq)]
113pub struct PacketEventData {
114    packet: PacketRc,
115    src_host_id: HostId,
116    src_host_event_id: u64,
117}
118
119#[derive(Debug, PartialEq, Eq)]
120pub struct LocalEventData {
121    task: TaskRef,
122    event_id: u64,
123}
124
125impl From<PacketEventData> for PacketRc {
126    fn from(data: PacketEventData) -> Self {
127        data.packet
128    }
129}
130
131impl PartialOrd for PacketEventData {
132    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
133        // sort by src host ID, then by event ID
134        let cmp = self
135            .src_host_id
136            .cmp(&other.src_host_id)
137            .then_with(|| self.src_host_event_id.cmp(&other.src_host_event_id));
138
139        // if the above fields were all equal (this should ideally not occur in practice since it
140        // leads to non-determinism, but we handle it anyways)
141        if cmp == std::cmp::Ordering::Equal {
142            if self.packet != other.packet {
143                // packets are not equal, so the events must not be equal
144                assert_ne!(self, other);
145                // we have nothing left to order them by
146                return None;
147            }
148
149            // packets are equal, so the events must be equal
150            assert_eq!(self, other);
151        }
152
153        Some(cmp)
154    }
155}
156
157impl From<LocalEventData> for TaskRef {
158    fn from(data: LocalEventData) -> Self {
159        data.task
160    }
161}
162
163impl PartialOrd for LocalEventData {
164    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
165        // they are local events and should be on the same host, so we can just sort by event ID
166        let cmp = self.event_id.cmp(&other.event_id);
167
168        // if the above fields were all equal (this should ideally not occur in practice since it
169        // leads to non-determinism, but we handle it anyways)
170        if cmp == std::cmp::Ordering::Equal {
171            if self.task != other.task {
172                // tasks are not equal, so the events must not be equal
173                assert_ne!(self, other);
174                // we have nothing left to order them by
175                return None;
176            }
177
178            // tasks are equal, so the events must be equal
179            assert_eq!(self, other);
180        }
181
182        Some(cmp)
183    }
184}