cranpose_core/slot_table/
lifecycle_queue.rs1use 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}