cranpose_core/snapshot_v2/
nested.rs1use super::*;
4
5#[allow(clippy::arc_with_non_send_sync)]
15pub struct NestedReadonlySnapshot {
16 state: SnapshotState,
17 parent: Weak<NestedReadonlySnapshot>,
18}
19
20impl NestedReadonlySnapshot {
21 pub fn new(
22 id: SnapshotId,
23 invalid: SnapshotIdSet,
24 read_observer: Option<ReadObserver>,
25 parent: Weak<NestedReadonlySnapshot>,
26 ) -> Arc<Self> {
27 Arc::new(Self {
28 state: SnapshotState::new(id, invalid, read_observer, None, false),
29 parent,
30 })
31 }
32
33 pub fn snapshot_id(&self) -> SnapshotId {
34 self.state.id.get()
35 }
36
37 pub fn invalid(&self) -> SnapshotIdSet {
38 self.state.invalid.borrow().clone()
39 }
40
41 pub fn read_only(&self) -> bool {
42 true
43 }
44
45 pub fn root_nested_readonly(&self) -> Arc<NestedReadonlySnapshot> {
46 if let Some(parent) = self.parent.upgrade() {
47 parent.root_nested_readonly()
48 } else {
49 NestedReadonlySnapshot::new(
51 self.state.id.get(),
52 self.state.invalid.borrow().clone(),
53 self.state.read_observer.clone(),
54 Weak::new(),
55 )
56 }
57 }
58
59 pub fn enter<T>(self: &Arc<Self>, f: impl FnOnce() -> T) -> T {
60 let previous = current_snapshot();
61 set_current_snapshot(Some(AnySnapshot::NestedReadonly(self.clone())));
62 let result = f();
63 set_current_snapshot(previous);
64 result
65 }
66
67 pub fn take_nested_snapshot(
68 &self,
69 read_observer: Option<ReadObserver>,
70 ) -> Arc<NestedReadonlySnapshot> {
71 let merged_observer = merge_read_observers(read_observer, self.state.read_observer.clone());
72
73 NestedReadonlySnapshot::new(
74 self.state.id.get(),
75 self.state.invalid.borrow().clone(),
76 merged_observer,
77 self.parent.clone(),
78 )
79 }
80
81 pub fn has_pending_changes(&self) -> bool {
82 false
83 }
84
85 pub fn dispose(&self) {
86 if !self.state.disposed.get() {
87 self.state.dispose();
88 }
89 }
90
91 pub fn record_read(&self, state: &dyn StateObject) {
92 self.state.record_read(state);
93 }
94
95 pub fn record_write(&self, _state: Arc<dyn StateObject>) {
96 panic!("Cannot write to a read-only snapshot");
97 }
98
99 pub fn close(&self) {
100 self.state.disposed.set(true);
101 }
102
103 pub fn is_disposed(&self) -> bool {
104 self.state.disposed.get()
105 }
106}
107
108#[allow(clippy::arc_with_non_send_sync)]
119pub struct NestedMutableSnapshot {
120 state: SnapshotState,
121 parent: Weak<MutableSnapshot>,
122 nested_count: Cell<usize>,
123 applied: Cell<bool>,
124 base_parent_id: SnapshotId,
126}
127
128impl NestedMutableSnapshot {
129 pub fn new(
130 id: SnapshotId,
131 invalid: SnapshotIdSet,
132 read_observer: Option<ReadObserver>,
133 write_observer: Option<WriteObserver>,
134 parent: Weak<MutableSnapshot>,
135 base_parent_id: SnapshotId,
136 ) -> Arc<Self> {
137 Arc::new(Self {
138 state: SnapshotState::new(id, invalid, read_observer, write_observer, true),
139 parent,
140 nested_count: Cell::new(0),
141 applied: Cell::new(false),
142 base_parent_id,
143 })
144 }
145
146 pub fn snapshot_id(&self) -> SnapshotId {
147 self.state.id.get()
148 }
149
150 pub fn invalid(&self) -> SnapshotIdSet {
151 self.state.invalid.borrow().clone()
152 }
153
154 pub fn read_only(&self) -> bool {
155 false
156 }
157
158 pub(crate) fn set_on_dispose<F>(&self, f: F)
159 where
160 F: FnOnce() + 'static,
161 {
162 self.state.set_on_dispose(f);
163 }
164
165 pub fn root_mutable(&self) -> Arc<MutableSnapshot> {
166 if let Some(parent) = self.parent.upgrade() {
167 parent.root_mutable()
168 } else {
169 MutableSnapshot::new(
171 self.state.id.get(),
172 self.state.invalid.borrow().clone(),
173 self.state.read_observer.clone(),
174 self.state.write_observer.clone(),
175 self.base_parent_id,
176 )
177 }
178 }
179
180 pub fn enter<T>(self: &Arc<Self>, f: impl FnOnce() -> T) -> T {
181 let previous = current_snapshot();
182 set_current_snapshot(Some(AnySnapshot::NestedMutable(self.clone())));
183 let result = f();
184 set_current_snapshot(previous);
185 result
186 }
187
188 pub fn take_nested_snapshot(
189 &self,
190 read_observer: Option<ReadObserver>,
191 ) -> Arc<ReadonlySnapshot> {
192 let merged_observer = merge_read_observers(read_observer, self.state.read_observer.clone());
193
194 ReadonlySnapshot::new(
195 self.state.id.get(),
196 self.state.invalid.borrow().clone(),
197 merged_observer,
198 )
199 }
200
201 pub fn has_pending_changes(&self) -> bool {
202 !self.state.modified.borrow().is_empty()
203 }
204
205 pub fn pending_children(&self) -> Vec<SnapshotId> {
206 self.state.pending_children()
207 }
208
209 pub fn has_pending_children(&self) -> bool {
210 self.state.has_pending_children()
211 }
212
213 pub fn parent_mutable(&self) -> Option<Arc<MutableSnapshot>> {
214 self.parent.upgrade()
215 }
216
217 pub fn dispose(&self) {
218 if !self.state.disposed.get() && self.nested_count.get() == 0 {
219 self.state.dispose();
220 }
221 }
222
223 pub fn record_read(&self, state: &dyn StateObject) {
224 self.state.record_read(state);
225 }
226
227 pub fn record_write(&self, state: Arc<dyn StateObject>) {
228 if self.applied.get() {
229 panic!("Cannot write to an applied snapshot");
230 }
231 if self.state.disposed.get() {
232 panic!("Cannot write to a disposed snapshot");
233 }
234 self.state.record_write(state, self.state.id.get());
235 }
236
237 pub fn close(&self) {
238 self.state.disposed.set(true);
239 }
240
241 pub fn is_disposed(&self) -> bool {
242 self.state.disposed.get()
243 }
244
245 pub fn apply(&self) -> SnapshotApplyResult {
246 if self.state.disposed.get() {
247 return SnapshotApplyResult::Failure;
248 }
249
250 if self.applied.get() {
251 return SnapshotApplyResult::Failure;
252 }
253
254 if let Some(parent) = self.parent.upgrade() {
256 let child_modified = self.state.modified.borrow();
258 if child_modified.is_empty() {
259 self.applied.set(true);
260 self.state.dispose();
261 return SnapshotApplyResult::Success;
262 }
263 if parent.merge_child_modifications(&child_modified).is_err() {
265 return SnapshotApplyResult::Failure;
266 }
267
268 self.applied.set(true);
269 self.state.dispose();
270 SnapshotApplyResult::Success
271 } else {
272 SnapshotApplyResult::Failure
273 }
274 }
275
276 pub fn take_nested_mutable_snapshot(
277 self: &Arc<Self>,
278 read_observer: Option<ReadObserver>,
279 write_observer: Option<WriteObserver>,
280 ) -> Arc<NestedMutableSnapshot> {
281 let merged_read = merge_read_observers(read_observer, self.state.read_observer.clone());
282 let merged_write = merge_write_observers(write_observer, self.state.write_observer.clone());
283
284 let parent_id = self.state.id.get();
286 let current_invalid = self.state.invalid.borrow().clone();
287
288 let (new_id, _runtime_invalid) = allocate_snapshot();
290
291 let parent_invalid_with_child = current_invalid.set(new_id);
293 self.state.invalid.replace(parent_invalid_with_child);
294
295 let invalid = current_invalid.add_range(parent_id + 1, new_id);
298
299 let self_weak = Arc::downgrade(&self.root_mutable());
300
301 let nested = NestedMutableSnapshot::new(
302 new_id,
303 invalid,
304 merged_read,
305 merged_write,
306 self_weak,
307 self.state.id.get(), );
309
310 self.nested_count.set(self.nested_count.get() + 1);
311 self.state.add_pending_child(new_id);
312
313 let parent_self_weak = Arc::downgrade(self);
314 nested.set_on_dispose({
315 let child_id = new_id;
316 move || {
317 if let Some(parent) = parent_self_weak.upgrade() {
318 if parent.nested_count.get() > 0 {
319 parent
320 .nested_count
321 .set(parent.nested_count.get().saturating_sub(1));
322 }
323 let mut invalid = parent.state.invalid.borrow_mut();
324 let new_set = invalid.clone().clear(child_id);
325 *invalid = new_set;
326 parent.state.remove_pending_child(child_id);
327 }
328 }
329 });
330
331 nested
332 }
333}
334
335#[cfg(test)]
336mod tests {
337 use super::*;
338 use crate::snapshot_v2::runtime::TestRuntimeGuard;
339 use std::rc::Rc;
340
341 fn reset_runtime() -> TestRuntimeGuard {
342 reset_runtime_for_tests()
343 }
344
345 fn mock_state_record() -> Rc<crate::state::StateRecord> {
346 crate::state::StateRecord::new(crate::state::PREEXISTING_SNAPSHOT_ID, (), None)
347 }
348
349 #[test]
350 fn test_nested_readonly_snapshot() {
351 let _guard = reset_runtime();
352 let parent = NestedReadonlySnapshot::new(1, SnapshotIdSet::new(), None, Weak::new());
353 let parent_weak = Arc::downgrade(&parent);
354
355 let nested = NestedReadonlySnapshot::new(1, SnapshotIdSet::new(), None, parent_weak);
356
357 assert_eq!(nested.snapshot_id(), 1);
358 assert!(nested.read_only());
359 assert!(!nested.is_disposed());
360 }
361
362 #[test]
363 fn test_nested_readonly_snapshot_root() {
364 let _guard = reset_runtime();
365 let parent = NestedReadonlySnapshot::new(1, SnapshotIdSet::new(), None, Weak::new());
366 let parent_weak = Arc::downgrade(&parent);
367
368 let nested = NestedReadonlySnapshot::new(1, SnapshotIdSet::new(), None, parent_weak);
369
370 let root = nested.root_nested_readonly();
371 assert_eq!(root.snapshot_id(), 1);
372 }
373
374 #[test]
375 fn test_nested_readonly_dispose() {
376 let _guard = reset_runtime();
377 let parent = NestedReadonlySnapshot::new(1, SnapshotIdSet::new(), None, Weak::new());
378 let parent_weak = Arc::downgrade(&parent);
379
380 let nested = NestedReadonlySnapshot::new(1, SnapshotIdSet::new(), None, parent_weak);
381
382 nested.dispose();
383 assert!(nested.is_disposed());
384 }
385
386 #[test]
387 fn test_nested_mutable_snapshot() {
388 let _guard = reset_runtime();
389 let parent = MutableSnapshot::new(1, SnapshotIdSet::new(), None, None, 0);
390 let parent_weak = Arc::downgrade(&parent);
391
392 let nested =
393 NestedMutableSnapshot::new(2, SnapshotIdSet::new().set(1), None, None, parent_weak, 1);
394
395 assert_eq!(nested.snapshot_id(), 2);
396 assert!(!nested.read_only());
397 assert!(!nested.is_disposed());
398 }
399
400 #[test]
401 fn test_nested_mutable_apply() {
402 let _guard = reset_runtime();
403 let parent = MutableSnapshot::new(1, SnapshotIdSet::new(), None, None, 0);
404 let parent_weak = Arc::downgrade(&parent);
405
406 let nested =
407 NestedMutableSnapshot::new(2, SnapshotIdSet::new().set(1), None, None, parent_weak, 1);
408
409 let result = nested.apply();
410 assert!(result.is_success());
411 assert!(nested.applied.get());
412 }
413
414 #[test]
415 fn test_nested_merge_sets_parent_pending_changes() {
416 let _guard = reset_runtime();
417 struct TestObj {
419 id: crate::state::ObjectId,
420 }
421 impl StateObject for TestObj {
422 fn object_id(&self) -> crate::state::ObjectId {
423 self.id
424 }
425 fn first_record(&self) -> Rc<crate::state::StateRecord> {
426 mock_state_record()
427 }
428 fn readable_record(
429 &self,
430 _snapshot_id: crate::snapshot_id_set::SnapshotId,
431 _invalid: &SnapshotIdSet,
432 ) -> Rc<crate::state::StateRecord> {
433 mock_state_record()
434 }
435 fn prepend_state_record(&self, _record: Rc<crate::state::StateRecord>) {}
436 fn promote_record(
437 &self,
438 _child_id: crate::snapshot_id_set::SnapshotId,
439 ) -> Result<(), &'static str> {
440 Ok(())
441 }
442
443 fn as_any(&self) -> &dyn std::any::Any {
444 self
445 }
446 }
447
448 let parent = MutableSnapshot::new(1, SnapshotIdSet::new(), None, None, 0);
449 let child = parent.take_nested_mutable_snapshot(None, None);
450
451 let obj = Arc::new(TestObj {
452 id: crate::state::ObjectId(100),
453 });
454 child.record_write(obj);
455 assert!(!parent.has_pending_changes());
456 child.apply().check();
457 assert!(parent.has_pending_changes());
458 }
459
460 #[test]
461 fn test_nested_conflict_with_parent_same_object() {
462 let _guard = reset_runtime();
463 struct TestObj {
465 id: crate::state::ObjectId,
466 }
467 impl StateObject for TestObj {
468 fn object_id(&self) -> crate::state::ObjectId {
469 self.id
470 }
471 fn first_record(&self) -> Rc<crate::state::StateRecord> {
472 mock_state_record()
473 }
474 fn readable_record(
475 &self,
476 _snapshot_id: crate::snapshot_id_set::SnapshotId,
477 _invalid: &SnapshotIdSet,
478 ) -> Rc<crate::state::StateRecord> {
479 mock_state_record()
480 }
481 fn prepend_state_record(&self, _record: Rc<crate::state::StateRecord>) {}
482 fn promote_record(
483 &self,
484 _child_id: crate::snapshot_id_set::SnapshotId,
485 ) -> Result<(), &'static str> {
486 Ok(())
487 }
488
489 fn as_any(&self) -> &dyn std::any::Any {
490 self
491 }
492 }
493
494 let parent = MutableSnapshot::new(1, SnapshotIdSet::new(), None, None, 0);
495 let child = parent.take_nested_mutable_snapshot(None, None);
496
497 let obj = Arc::new(TestObj {
498 id: crate::state::ObjectId(200),
499 });
500 parent.record_write(obj.clone());
501 child.record_write(obj.clone());
502
503 let result = child.apply();
504 assert!(result.is_failure());
505 }
506
507 #[test]
508 fn test_nested_mutable_apply_twice_fails() {
509 let _guard = reset_runtime();
510 let parent = MutableSnapshot::new(1, SnapshotIdSet::new(), None, None, 0);
511 let parent_weak = Arc::downgrade(&parent);
512
513 let nested =
514 NestedMutableSnapshot::new(2, SnapshotIdSet::new().set(1), None, None, parent_weak, 1);
515
516 nested.apply().check();
517 let result = nested.apply();
518 assert!(result.is_failure());
519 }
520
521 #[test]
522 fn test_nested_mutable_dispose() {
523 let _guard = reset_runtime();
524 let parent = MutableSnapshot::new(1, SnapshotIdSet::new(), None, None, 0);
525 let parent_weak = Arc::downgrade(&parent);
526
527 let nested =
528 NestedMutableSnapshot::new(2, SnapshotIdSet::new().set(1), None, None, parent_weak, 1);
529
530 nested.dispose();
531 assert!(nested.is_disposed());
532 }
533}