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 test_that::prelude::*;
113
114 use super::*;
115
116 #[test]
117 fn test_parent_event_map() {
118 let r#become: ParentEvent<u32> = ParentEvent::Become(10);
119 let spawn: ParentEvent<u32> = ParentEvent::Spawn(20);
120
121 let mapped_become = r#become.map(|x| x * 2);
122 let mapped_spawn = spawn.map(|x| x + 5);
123
124 match mapped_become {
125 ParentEvent::Become(v) => assert_eq!(v, 20),
126 _ => panic!("Expected Become variant"),
127 }
128 match mapped_spawn {
129 ParentEvent::Spawn(v) => assert_eq!(v, 25),
130 _ => panic!("Expected Spawn variant"),
131 }
132 }
133
134 #[test]
135 fn test_parent_event_transpose() {
136 let become_some: ParentEvent<Option<u32>> = ParentEvent::Become(Some(10));
137 let become_none: ParentEvent<Option<u32>> = ParentEvent::Become(None);
138 let spawn_some: ParentEvent<Option<u32>> = ParentEvent::Spawn(Some(5));
139 let spawn_none: ParentEvent<Option<u32>> = ParentEvent::Spawn(None);
140
141 let transposed_become_some = become_some.transpose();
142 let transposed_become_none = become_none.transpose();
143 let transposed_spawn_some = spawn_some.transpose();
144 let transposed_spawn_none = spawn_none.transpose();
145
146 assert_eq!(transposed_become_some, Some(ParentEvent::Become(10)));
147 assert_eq!(transposed_become_none, None);
148 assert_eq!(transposed_spawn_some, Some(ParentEvent::Spawn(5)));
149 assert_eq!(transposed_spawn_none, None);
150 }
151
152 #[test]
153 fn test_parent_tracker_save_and_update() {
154 let mut parent = ParentTracker::new();
155 let mut child = ParentTracker::new();
156
157 let parent_exec1 = EventId::new(1);
158 let parent_exec2 = EventId::new(2);
159
160 assert_eq!(parent.update_last_exec(parent_exec1, true), None);
162 let parent_become = parent.update_last_exec(parent_exec2, true);
164 assert_eq!(parent_become.unwrap(), ParentEvent::Become(EventId::new(1)));
165
166 child.save_parent_last_exec(&parent);
168
169 let child_exec = EventId::new(10);
170 let parent_event = child.update_last_exec(child_exec, true);
171 assert!(matches!(parent_event, Some(ParentEvent::Spawn(_))));
173 }
174
175 #[test]
176 fn test_parent_tracker_update_unsuccessful_exec() {
177 let mut tracker = ParentTracker::new();
178 let parent_id = EventId::new(5);
179 tracker.parent_last_exec = Some(parent_id);
180
181 let exec_id = EventId::new(10);
182 let parent_event = tracker.update_last_exec(exec_id, false);
184 assert!(matches!(parent_event, Some(ParentEvent::Spawn(_))));
185 assert_eq!(tracker.last_successful_exec, None);
186 }
187
188 #[test]
189 fn test_parent_tracker_multiple_execs() {
190 let mut tracker = ParentTracker::new();
191 let first_exec = EventId::new(1);
192 let second_exec = EventId::new(2);
193
194 let parent_event1 = tracker.update_last_exec(first_exec, true);
196 assert_that!(parent_event1, none());
197 assert_eq!(tracker.last_successful_exec.unwrap().into_inner(), 1);
198
199 let parent_event2 = tracker.update_last_exec(second_exec, true);
201 assert_eq!(parent_event2.unwrap(), ParentEvent::Become(EventId::new(1)));
203 assert_eq!(tracker.last_successful_exec.unwrap().into_inner(), 2);
204 }
205}