tracexec_core/event/
parent.rs1use std::fmt::Debug;
4
5use super::EventId;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum ParentEvent<T> {
9 Become(T),
11 Spawn(T),
13}
14
15impl From<ParentEvent<Self>> for EventId {
16 fn from(value: ParentEvent<Self>) -> Self {
17 match value {
18 ParentEvent::Become(event_id) | ParentEvent::Spawn(event_id) => event_id,
19 }
20 }
21}
22
23impl<T> ParentEvent<T> {
24 pub fn map<U>(self, f: impl FnOnce(T) -> U) -> ParentEvent<U> {
25 match self {
26 Self::Become(v) => ParentEvent::Become(f(v)),
27 Self::Spawn(v) => ParentEvent::Spawn(f(v)),
28 }
29 }
30}
31
32impl<T> ParentEvent<Option<T>> {
33 pub fn transpose(self) -> Option<ParentEvent<T>> {
34 match self {
35 Self::Become(v) => v.map(ParentEvent::Become),
36 Self::Spawn(v) => v.map(ParentEvent::Spawn),
37 }
38 }
39}
40
41pub type ParentEventId = ParentEvent<EventId>;
42
43#[derive(Debug, Clone, Default)]
74pub struct ParentTracker {
75 parent_last_exec: Option<EventId>,
77 last_successful_exec: Option<EventId>,
79}
80
81impl ParentTracker {
82 pub fn new() -> Self {
83 Default::default()
84 }
85
86 pub fn save_parent_last_exec(&mut self, parent: &Self) {
87 self.parent_last_exec = parent.last_successful_exec.or(parent.parent_last_exec);
88 }
89
90 pub fn update_last_exec(&mut self, id: EventId, successful: bool) -> Option<ParentEventId> {
93 let has_successful_exec = self.last_successful_exec.is_some();
94 let old_last_exec = if successful {
95 self.last_successful_exec.replace(id)
96 } else {
97 self.last_successful_exec
98 };
99 if has_successful_exec {
102 old_last_exec.map(ParentEvent::Become)
104 } else {
105 self.parent_last_exec.map(ParentEvent::Spawn)
106 }
107 }
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113
114 #[test]
115 fn test_parent_event_map() {
116 let r#become: ParentEvent<u32> = ParentEvent::Become(10);
117 let spawn: ParentEvent<u32> = ParentEvent::Spawn(20);
118
119 let mapped_become = r#become.map(|x| x * 2);
120 let mapped_spawn = spawn.map(|x| x + 5);
121
122 match mapped_become {
123 ParentEvent::Become(v) => assert_eq!(v, 20),
124 _ => panic!("Expected Become variant"),
125 }
126 match mapped_spawn {
127 ParentEvent::Spawn(v) => assert_eq!(v, 25),
128 _ => panic!("Expected Spawn variant"),
129 }
130 }
131
132 #[test]
133 fn test_parent_event_transpose() {
134 let become_some: ParentEvent<Option<u32>> = ParentEvent::Become(Some(10));
135 let become_none: ParentEvent<Option<u32>> = ParentEvent::Become(None);
136 let spawn_some: ParentEvent<Option<u32>> = ParentEvent::Spawn(Some(5));
137 let spawn_none: ParentEvent<Option<u32>> = ParentEvent::Spawn(None);
138
139 let transposed_become_some = become_some.transpose();
140 let transposed_become_none = become_none.transpose();
141 let transposed_spawn_some = spawn_some.transpose();
142 let transposed_spawn_none = spawn_none.transpose();
143
144 assert_eq!(transposed_become_some, Some(ParentEvent::Become(10)));
145 assert_eq!(transposed_become_none, None);
146 assert_eq!(transposed_spawn_some, Some(ParentEvent::Spawn(5)));
147 assert_eq!(transposed_spawn_none, None);
148 }
149
150 #[test]
151 fn test_parent_tracker_save_and_update() {
152 let mut parent = ParentTracker::new();
153 let mut child = ParentTracker::new();
154
155 let parent_exec1 = EventId::new(1);
156 let parent_exec2 = EventId::new(2);
157
158 assert_eq!(parent.update_last_exec(parent_exec1, true), None);
160 let parent_become = parent.update_last_exec(parent_exec2, true);
162 assert_eq!(parent_become.unwrap(), ParentEvent::Become(EventId::new(1)));
163
164 child.save_parent_last_exec(&parent);
166
167 let child_exec = EventId::new(10);
168 let parent_event = child.update_last_exec(child_exec, true);
169 assert!(matches!(parent_event, Some(ParentEvent::Spawn(_))));
171 }
172
173 #[test]
174 fn test_parent_tracker_update_unsuccessful_exec() {
175 let mut tracker = ParentTracker::new();
176 let parent_id = EventId::new(5);
177 tracker.parent_last_exec = Some(parent_id);
178
179 let exec_id = EventId::new(10);
180 let parent_event = tracker.update_last_exec(exec_id, false);
182 assert!(matches!(parent_event, Some(ParentEvent::Spawn(_))));
183 assert_eq!(tracker.last_successful_exec, None);
184 }
185
186 #[test]
187 fn test_parent_tracker_multiple_execs() {
188 let mut tracker = ParentTracker::new();
189 let first_exec = EventId::new(1);
190 let second_exec = EventId::new(2);
191
192 let parent_event1 = tracker.update_last_exec(first_exec, true);
194 assert!(parent_event1.is_none());
195 assert_eq!(tracker.last_successful_exec.unwrap().into_inner(), 1);
196
197 let parent_event2 = tracker.update_last_exec(second_exec, true);
199 assert_eq!(parent_event2.unwrap(), ParentEvent::Become(EventId::new(1)));
201 assert_eq!(tracker.last_successful_exec.unwrap().into_inner(), 2);
202 }
203}