1use shadow_shim_helper_rs::HostId;
2use shadow_shim_helper_rs::emulated_time::EmulatedTime;
34use super::task::TaskRef;
5use crate::host::host::Host;
6use crate::network::packet::PacketRc;
7use crate::utility::{Magic, ObjectCounter};
89#[derive(Debug)]
10pub struct Event {
11 magic: Magic<Self>,
12 time: EmulatedTime,
13 data: EventData,
14 _counter: ObjectCounter,
15}
1617impl 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.
20pub fn new_packet(packet: PacketRc, time: EmulatedTime, src_host: &Host) -> Self {
21Self {
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 }
3233/// A new local event, which is an event that was generated locally by the host itself (timers,
34 /// localhost packets, etc).
35pub fn new_local(task: TaskRef, time: EmulatedTime, host: &Host) -> Self {
36Self {
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 }
4647pub fn time(&self) -> EmulatedTime {
48self.magic.debug_check();
49self.time
50 }
5152pub fn set_time(&mut self, time: EmulatedTime) {
53self.magic.debug_check();
54self.time = time;
55 }
5657/// The event data.
58pub fn data(self) -> EventData {
59self.magic.debug_check();
60self.data
61 }
62}
6364impl PartialEq for Event {
65fn eq(&self, other: &Self) -> bool {
66self.magic.debug_check();
67 other.magic.debug_check();
6869fn check_impl_eq(_: impl Eq) {}
7071// below we impl Eq for Event, so we should make sure that all of our comparisons below are
72 // also Eq
73check_impl_eq(self.time);
74 check_impl_eq(&self.data);
7576// check every field except '_counter'
77self.time == other.time && self.data == other.data
78 }
79}
8081// we checked above that Event's `PartialEq` impl is also `Eq`
82impl Eq for Event {}
8384impl PartialOrd for Event {
85fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
86self.magic.debug_check();
87 other.magic.debug_check();
8889// sort by event time, then by the event data
90let cmp = self.time.cmp(&other.time);
9192if cmp.is_ne() {
93Some(cmp)
94 } else {
95// event times were equal
96self.data.partial_cmp(&other.data)
97 }
98 }
99}
100101/// 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.
108Packet(PacketEventData),
109 Local(LocalEventData),
110}
111112#[derive(Debug, PartialEq, Eq)]
113pub struct PacketEventData {
114 packet: PacketRc,
115 src_host_id: HostId,
116 src_host_event_id: u64,
117}
118119#[derive(Debug, PartialEq, Eq)]
120pub struct LocalEventData {
121 task: TaskRef,
122 event_id: u64,
123}
124125impl From<PacketEventData> for PacketRc {
126fn from(data: PacketEventData) -> Self {
127 data.packet
128 }
129}
130131impl PartialOrd for PacketEventData {
132fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
133// sort by src host ID, then by event ID
134let 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));
138139// 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)
141if cmp == std::cmp::Ordering::Equal {
142if self.packet != other.packet {
143// packets are not equal, so the events must not be equal
144assert_ne!(self, other);
145// we have nothing left to order them by
146return None;
147 }
148149// packets are equal, so the events must be equal
150assert_eq!(self, other);
151 }
152153Some(cmp)
154 }
155}
156157impl From<LocalEventData> for TaskRef {
158fn from(data: LocalEventData) -> Self {
159 data.task
160 }
161}
162163impl PartialOrd for LocalEventData {
164fn 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
166let cmp = self.event_id.cmp(&other.event_id);
167168// 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)
170if cmp == std::cmp::Ordering::Equal {
171if self.task != other.task {
172// tasks are not equal, so the events must not be equal
173assert_ne!(self, other);
174// we have nothing left to order them by
175return None;
176 }
177178// tasks are equal, so the events must be equal
179assert_eq!(self, other);
180 }
181182Some(cmp)
183 }
184}