Skip to main content

cranpose_core/slot_table/
lifecycle_queue.rs

1use super::{NodeSlotState, SlotTable};
2use crate::{runtime, AnchorId, NodeId, RecomposeScope};
3use std::any::Any;
4
5struct ChunkedPending<T> {
6    sealed: Vec<Vec<T>>,
7    active: Vec<T>,
8    len: usize,
9}
10
11impl<T> Default for ChunkedPending<T> {
12    fn default() -> Self {
13        Self {
14            sealed: Vec::new(),
15            active: Vec::new(),
16            len: 0,
17        }
18    }
19}
20
21impl<T> ChunkedPending<T> {
22    fn len(&self) -> usize {
23        self.len
24    }
25
26    fn capacity(&self) -> usize {
27        self.active.capacity() + self.sealed.iter().map(Vec::capacity).sum::<usize>()
28    }
29
30    fn push(&mut self, value: T, initial_capacity: usize, chunk_capacity: usize) {
31        if self.active.capacity() == 0 {
32            self.active = Vec::with_capacity(initial_capacity);
33        } else if self.active.len() == self.active.capacity() {
34            let next_capacity = chunk_capacity.max(initial_capacity);
35            let full_chunk = std::mem::replace(&mut self.active, Vec::with_capacity(next_capacity));
36            self.sealed.push(full_chunk);
37        }
38
39        self.active.push(value);
40        self.len += 1;
41    }
42
43    fn clear_and_drop_reverse(&mut self) {
44        while let Some(value) = self.active.pop() {
45            drop(value);
46        }
47
48        while let Some(mut chunk) = self.sealed.pop() {
49            while let Some(value) = chunk.pop() {
50                drop(value);
51            }
52        }
53
54        self.len = 0;
55    }
56
57    fn drain_forward(&mut self, mut visitor: impl FnMut(T)) {
58        let sealed = std::mem::take(&mut self.sealed);
59        for chunk in sealed {
60            for value in chunk {
61                visitor(value);
62            }
63        }
64        let active = std::mem::take(&mut self.active);
65        for value in active {
66            visitor(value);
67        }
68        self.len = 0;
69    }
70
71    fn trim_retained_capacity(&mut self, retained: usize, initial_capacity: usize) {
72        self.sealed = Vec::new();
73        if self.active.capacity() > retained.saturating_mul(4) {
74            self.active = Vec::with_capacity(retained.max(initial_capacity));
75        }
76    }
77
78    #[cfg(debug_assertions)]
79    fn visit(&self, mut visitor: impl FnMut(&T)) {
80        for chunk in &self.sealed {
81            for value in chunk {
82                visitor(value);
83            }
84        }
85        for value in &self.active {
86            visitor(value);
87        }
88    }
89}
90
91pub(crate) enum DeferredDrop {
92    Group(Option<RecomposeScope>),
93    Value(Box<dyn Any>),
94}
95
96impl DeferredDrop {
97    fn dispose(self) {
98        match self {
99            Self::Group(scope) => drop(scope),
100            Self::Value(value) => drop(value),
101        }
102    }
103}
104
105pub(in crate::slot_table) struct PendingDrops<T> {
106    inner: ChunkedPending<T>,
107}
108
109impl<T> Default for PendingDrops<T> {
110    fn default() -> Self {
111        Self {
112            inner: ChunkedPending::default(),
113        }
114    }
115}
116
117impl<T> PendingDrops<T> {
118    const CHUNK_CAPACITY: usize = 1024;
119    const INITIAL_CAPACITY: usize = 4;
120
121    pub(in crate::slot_table) fn len(&self) -> usize {
122        self.inner.len()
123    }
124
125    pub(in crate::slot_table) fn capacity(&self) -> usize {
126        self.inner.capacity()
127    }
128
129    pub(in crate::slot_table) fn push(&mut self, value: T) {
130        self.inner
131            .push(value, Self::INITIAL_CAPACITY, Self::CHUNK_CAPACITY);
132    }
133
134    pub(in crate::slot_table) fn clear_and_drop_reverse(&mut self) {
135        let _teardown = runtime::enter_state_teardown_scope();
136        self.inner.clear_and_drop_reverse();
137    }
138
139    pub(in crate::slot_table) fn trim_retained_capacity(&mut self, retained: usize) {
140        self.inner
141            .trim_retained_capacity(retained, Self::INITIAL_CAPACITY);
142    }
143}
144
145#[derive(Default)]
146pub(in crate::slot_table) struct OrphanedNodeIds {
147    inner: ChunkedPending<OrphanedNode>,
148}
149
150#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
151pub struct OrphanedNode {
152    pub id: NodeId,
153    pub generation: u32,
154    pub(crate) anchor: AnchorId,
155}
156
157impl OrphanedNode {
158    pub(in crate::slot_table) fn new(id: NodeId, generation: u32, anchor: AnchorId) -> Self {
159        Self {
160            id,
161            generation,
162            anchor,
163        }
164    }
165}
166
167impl OrphanedNodeIds {
168    const CHUNK_CAPACITY: usize = 1024;
169    pub(in crate::slot_table) const INITIAL_CAPACITY: usize = 32;
170
171    pub(in crate::slot_table) fn len(&self) -> usize {
172        self.inner.len()
173    }
174
175    pub(in crate::slot_table) fn capacity(&self) -> usize {
176        self.inner.capacity()
177    }
178
179    pub(in crate::slot_table) fn push(&mut self, orphaned: OrphanedNode) {
180        self.inner
181            .push(orphaned, Self::INITIAL_CAPACITY, Self::CHUNK_CAPACITY);
182    }
183
184    pub(in crate::slot_table) fn drain_forward(&mut self, visitor: impl FnMut(OrphanedNode)) {
185        self.inner.drain_forward(visitor);
186        self.trim_retained_capacity(Self::INITIAL_CAPACITY);
187    }
188
189    pub(in crate::slot_table) fn trim_retained_capacity(&mut self, retained: usize) {
190        self.inner
191            .trim_retained_capacity(retained, Self::INITIAL_CAPACITY);
192    }
193
194    #[cfg(debug_assertions)]
195    pub(in crate::slot_table) fn snapshot(&self) -> Vec<OrphanedNode> {
196        let mut orphaned = Vec::with_capacity(self.len());
197        self.inner.visit(|node| orphaned.push(*node));
198        orphaned
199    }
200}
201
202#[derive(Default)]
203pub(crate) struct SlotLifecycleCoordinator {
204    pending_drops: PendingDrops<DeferredDrop>,
205    orphaned_node_ids: OrphanedNodeIds,
206    preserved_orphaned_node_ids: OrphanedNodeIds,
207}
208
209impl SlotLifecycleCoordinator {
210    pub(crate) fn pending_drops_len(&self) -> usize {
211        self.pending_drops.len()
212    }
213
214    pub(crate) fn pending_drops_capacity(&self) -> usize {
215        self.pending_drops.capacity()
216    }
217
218    pub(crate) fn orphaned_node_ids_len(&self) -> usize {
219        self.orphaned_node_ids.len()
220    }
221
222    pub(crate) fn orphaned_node_ids_capacity(&self) -> usize {
223        self.orphaned_node_ids.capacity()
224    }
225
226    pub(crate) fn deactivate_scope(&self, scope: &RecomposeScope) {
227        scope.deactivate();
228    }
229
230    pub(crate) fn push_drop(&mut self, deferred_drop: DeferredDrop) {
231        self.pending_drops.push(deferred_drop);
232    }
233
234    pub(crate) fn queue_orphaned_node(&mut self, orphaned: OrphanedNode) {
235        self.orphaned_node_ids.push(orphaned);
236    }
237
238    pub(crate) fn preserve_orphaned_node(&mut self, orphaned: OrphanedNode) {
239        self.preserved_orphaned_node_ids.push(orphaned);
240    }
241
242    pub(crate) fn drain_orphaned_node_ids_with(&mut self, visitor: impl FnMut(OrphanedNode)) {
243        self.orphaned_node_ids.drain_forward(visitor);
244    }
245
246    pub(crate) fn drain_orphaned_node_ids(&mut self) -> Vec<OrphanedNode> {
247        let mut orphaned = Vec::with_capacity(self.orphaned_node_ids.len());
248        self.drain_orphaned_node_ids_with(|node| orphaned.push(node));
249        orphaned
250    }
251
252    pub(crate) fn flush_pending_drops(&mut self) {
253        self.pending_drops.clear_and_drop_reverse();
254        let retained = self.pending_drops.len().max(4);
255        self.pending_drops.trim_retained_capacity(retained);
256    }
257
258    pub(crate) fn reconcile_orphaned_nodes(&mut self, table: &SlotTable) {
259        let preserved = self.drain_preserved_orphaned_node_ids();
260        for orphaned in preserved {
261            match table.orphaned_node_state(orphaned) {
262                NodeSlotState::Active => {}
263                NodeSlotState::PreservedGap => self.preserve_orphaned_node(orphaned),
264                NodeSlotState::Missing => self.queue_orphaned_node(orphaned),
265            }
266        }
267    }
268
269    pub(crate) fn dispose_drops_reverse(&mut self, mut drops: Vec<DeferredDrop>) {
270        let _teardown = runtime::enter_state_teardown_scope();
271        while let Some(deferred_drop) = drops.pop() {
272            deferred_drop.dispose();
273        }
274    }
275
276    pub(crate) fn trim_orphaned_node_capacity(&mut self, retained: usize) {
277        self.orphaned_node_ids.trim_retained_capacity(retained);
278    }
279
280    #[cfg(debug_assertions)]
281    pub(crate) fn orphaned_node_ids_snapshot(&self) -> Vec<OrphanedNode> {
282        self.orphaned_node_ids.snapshot()
283    }
284
285    #[cfg(debug_assertions)]
286    pub(crate) fn preserved_orphaned_node_ids_snapshot(&self) -> Vec<OrphanedNode> {
287        self.preserved_orphaned_node_ids.snapshot()
288    }
289
290    pub(crate) fn clear_orphaned_nodes(&mut self) {
291        let _ = self.drain_orphaned_node_ids();
292        let _ = self.drain_preserved_orphaned_node_ids();
293        self.trim_orphaned_node_capacity(32);
294        self.preserved_orphaned_node_ids.trim_retained_capacity(32);
295    }
296
297    fn drain_preserved_orphaned_node_ids(&mut self) -> Vec<OrphanedNode> {
298        let mut orphaned = Vec::with_capacity(self.preserved_orphaned_node_ids.len());
299        self.preserved_orphaned_node_ids
300            .drain_forward(|node| orphaned.push(node));
301        orphaned
302    }
303}