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 #[test]
346 fn test_nested_readonly_snapshot() {
347 let _guard = reset_runtime();
348 let parent = NestedReadonlySnapshot::new(1, SnapshotIdSet::new(), None, Weak::new());
349 let parent_weak = Arc::downgrade(&parent);
350
351 let nested = NestedReadonlySnapshot::new(1, SnapshotIdSet::new(), None, parent_weak);
352
353 assert_eq!(nested.snapshot_id(), 1);
354 assert!(nested.read_only());
355 assert!(!nested.is_disposed());
356 }
357
358 #[test]
359 fn test_nested_readonly_snapshot_root() {
360 let _guard = reset_runtime();
361 let parent = NestedReadonlySnapshot::new(1, SnapshotIdSet::new(), None, Weak::new());
362 let parent_weak = Arc::downgrade(&parent);
363
364 let nested = NestedReadonlySnapshot::new(1, SnapshotIdSet::new(), None, parent_weak);
365
366 let root = nested.root_nested_readonly();
367 assert_eq!(root.snapshot_id(), 1);
368 }
369
370 #[test]
371 fn test_nested_readonly_dispose() {
372 let _guard = reset_runtime();
373 let parent = NestedReadonlySnapshot::new(1, SnapshotIdSet::new(), None, Weak::new());
374 let parent_weak = Arc::downgrade(&parent);
375
376 let nested = NestedReadonlySnapshot::new(1, SnapshotIdSet::new(), None, parent_weak);
377
378 nested.dispose();
379 assert!(nested.is_disposed());
380 }
381
382 #[test]
383 fn test_nested_mutable_snapshot() {
384 let _guard = reset_runtime();
385 let parent = MutableSnapshot::new(1, SnapshotIdSet::new(), None, None, 0);
386 let parent_weak = Arc::downgrade(&parent);
387
388 let nested =
389 NestedMutableSnapshot::new(2, SnapshotIdSet::new().set(1), None, None, parent_weak, 1);
390
391 assert_eq!(nested.snapshot_id(), 2);
392 assert!(!nested.read_only());
393 assert!(!nested.is_disposed());
394 }
395
396 #[test]
397 fn test_nested_mutable_apply() {
398 let _guard = reset_runtime();
399 let parent = MutableSnapshot::new(1, SnapshotIdSet::new(), None, None, 0);
400 let parent_weak = Arc::downgrade(&parent);
401
402 let nested =
403 NestedMutableSnapshot::new(2, SnapshotIdSet::new().set(1), None, None, parent_weak, 1);
404
405 let result = nested.apply();
406 assert!(result.is_success());
407 assert!(nested.applied.get());
408 }
409
410 #[test]
411 fn test_nested_merge_sets_parent_pending_changes() {
412 let _guard = reset_runtime();
413 struct TestObj {
415 id: crate::state::ObjectId,
416 }
417 impl StateObject for TestObj {
418 fn object_id(&self) -> crate::state::ObjectId {
419 self.id
420 }
421 fn first_record(&self) -> Rc<crate::state::StateRecord> {
422 unimplemented!("not used in v2 tests")
423 }
424 fn readable_record(
425 &self,
426 _snapshot_id: crate::snapshot_id_set::SnapshotId,
427 _invalid: &SnapshotIdSet,
428 ) -> Rc<crate::state::StateRecord> {
429 unimplemented!("not used in v2 tests")
430 }
431 fn prepend_state_record(&self, _record: Rc<crate::state::StateRecord>) {
432 unimplemented!("not used in v2 tests")
433 }
434 fn promote_record(
435 &self,
436 _child_id: crate::snapshot_id_set::SnapshotId,
437 ) -> Result<(), &'static str> {
438 unimplemented!("not used in v2 tests")
439 }
440
441 fn as_any(&self) -> &dyn std::any::Any {
442 self
443 }
444 }
445
446 let parent = MutableSnapshot::new(1, SnapshotIdSet::new(), None, None, 0);
447 let child = parent.take_nested_mutable_snapshot(None, None);
448
449 let obj = Arc::new(TestObj {
450 id: crate::state::ObjectId(100),
451 });
452 child.record_write(obj);
453 assert!(!parent.has_pending_changes());
454 child.apply().check();
455 assert!(parent.has_pending_changes());
456 }
457
458 #[test]
459 fn test_nested_conflict_with_parent_same_object() {
460 let _guard = reset_runtime();
461 struct TestObj {
463 id: crate::state::ObjectId,
464 }
465 impl StateObject for TestObj {
466 fn object_id(&self) -> crate::state::ObjectId {
467 self.id
468 }
469 fn first_record(&self) -> Rc<crate::state::StateRecord> {
470 unimplemented!("not used in v2 tests")
471 }
472 fn readable_record(
473 &self,
474 _snapshot_id: crate::snapshot_id_set::SnapshotId,
475 _invalid: &SnapshotIdSet,
476 ) -> Rc<crate::state::StateRecord> {
477 unimplemented!("not used in v2 tests")
478 }
479 fn prepend_state_record(&self, _record: Rc<crate::state::StateRecord>) {
480 unimplemented!("not used in v2 tests")
481 }
482 fn promote_record(
483 &self,
484 _child_id: crate::snapshot_id_set::SnapshotId,
485 ) -> Result<(), &'static str> {
486 unimplemented!("not used in v2 tests")
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}