nmp_threading/grouper/
lifecycle.rs1use nmp_core::substrate::{EventId, KernelEvent};
7
8use crate::block::TimelineBlock;
9use crate::resolver::ParentResolver;
10
11use super::{GroupDelta, Grouper};
12
13impl<R: ParentResolver> Grouper<R> {
14 #[must_use]
17 pub fn on_insert(&mut self, event: &KernelEvent) -> Option<GroupDelta> {
18 if self.by_id.contains_key(&event.id) {
19 return None;
20 }
21 if self
26 .superseded_by
27 .get(&event.id)
28 .is_some_and(|set| !set.is_empty())
29 {
30 self.by_id.insert(event.id.clone(), event.clone());
31 return None;
32 }
33 self.by_id.insert(event.id.clone(), event.clone());
34
35 if let Some(target) = self.resolver.supersedes(event) {
41 self.superseded_by
42 .entry(target.clone())
43 .or_default()
44 .insert(event.id.clone());
45 self.unplace_standalone(&target);
46 }
47
48 let waiting = self.orphans.remove(&event.id).unwrap_or_default();
51
52 let mut delta = self.place_event(event);
53
54 let mut replay_queue: Vec<EventId> = waiting.into_iter().collect();
56 while let Some(child_id) = replay_queue.pop() {
57 if self.seen.contains(&child_id) {
58 continue;
59 }
60 let Some(child) = self.by_id.get(&child_id).cloned() else {
61 continue;
62 };
63 self.place_event(&child);
64 if let Some(more) = self.orphans.remove(&child_id) {
65 replay_queue.extend(more);
66 }
67 }
68
69 self.sort_blocks_newest_first();
70 self.collapse_adjacent();
71 self.sort_blocks_newest_first();
72 if matches!(
73 delta,
74 Some(GroupDelta::BlockInserted(_) | GroupDelta::BlockReplaced(_))
75 ) {
76 delta = delta.and_then(|d| self.reindex_delta(d, &event.id));
77 }
78 delta
79 }
80
81 #[must_use]
83 pub fn on_remove(&mut self, id: &EventId) -> Option<GroupDelta> {
84 self.by_id.remove(id);
85 self.pending_ancestor_ids.remove(id);
86 self.orphaned.remove(id);
87 self.orphans.retain(|_, set| {
88 set.remove(id);
89 !set.is_empty()
90 });
91
92 self.superseded_by.remove(id);
98 let mut restore_candidates: Vec<EventId> = Vec::new();
99 self.superseded_by.retain(|target, set| {
100 set.remove(id);
101 if set.is_empty() {
102 restore_candidates.push(target.clone());
103 false
104 } else {
105 true
106 }
107 });
108
109 let block_delta = self.remove_id_from_blocks(id);
110
111 let mut restored_any = false;
113 for target in restore_candidates {
114 if self.seen.contains(&target) {
115 continue;
116 }
117 let Some(event) = self.by_id.get(&target).cloned() else {
118 continue;
119 };
120 let _ = self.place_event(&event);
121 restored_any = true;
122 }
123
124 if block_delta.is_some() || restored_any {
125 self.collapse_adjacent();
126 self.sort_blocks_newest_first();
127 }
128
129 block_delta
130 }
131
132 fn remove_id_from_blocks(&mut self, id: &EventId) -> Option<GroupDelta> {
133 if !self.seen.remove(id) {
134 return None;
135 }
136
137 let mut removed_idx: Option<usize> = None;
138 let mut block_replaced_idx: Option<usize> = None;
139
140 for (idx, block) in self.blocks.iter_mut().enumerate() {
141 match block {
142 TimelineBlock::Standalone { id: eid, .. } if eid == id => {
143 removed_idx = Some(idx);
144 break;
145 }
146 TimelineBlock::Module {
147 events,
148 has_gap,
149 root,
150 } => {
151 if events.iter().any(|e| e == id) {
152 events.retain(|e| e != id);
153 *has_gap = true;
155 if events.is_empty() {
156 removed_idx = Some(idx);
157 } else if events.len() == 1 {
158 let only = events.remove(0);
159 *block = TimelineBlock::Standalone {
164 id: only,
165 root: root.take(),
166 };
167 block_replaced_idx = Some(idx);
168 } else {
169 block_replaced_idx = Some(idx);
170 }
171 break;
172 }
173 }
174 TimelineBlock::Standalone { .. } => {}
175 }
176 }
177
178 if let Some(idx) = removed_idx {
179 self.blocks.remove(idx);
180 Some(GroupDelta::BlockRemoved(idx))
181 } else {
182 block_replaced_idx.map(GroupDelta::BlockReplaced)
183 }
184 }
185
186 fn unplace_standalone(&mut self, id: &EventId) {
192 let standalone_idx = self.blocks.iter().position(|block| match block {
193 TimelineBlock::Standalone { id: eid, .. } => eid == id,
194 TimelineBlock::Module { .. } => false,
195 });
196 if let Some(idx) = standalone_idx {
197 self.blocks.remove(idx);
198 self.seen.remove(id);
199 }
200 }
201
202 #[must_use]
205 pub fn on_replace(&mut self, old_id: &EventId, new_event: &KernelEvent) -> Option<GroupDelta> {
206 let _ = self.on_remove(old_id); self.on_insert(new_event)
208 }
209}