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 (new_id, runtime_invalid) = allocate_snapshot();
285 let mut parent_invalid = self.state.invalid.borrow().clone();
286 parent_invalid = parent_invalid.set(new_id);
287 self.state.invalid.replace(parent_invalid.clone());
288 let invalid = parent_invalid.or(&runtime_invalid);
289
290 let self_weak = Arc::downgrade(&self.root_mutable());
291
292 let nested = NestedMutableSnapshot::new(
293 new_id,
294 invalid,
295 merged_read,
296 merged_write,
297 self_weak,
298 self.state.id.get(), );
300
301 self.nested_count.set(self.nested_count.get() + 1);
302 self.state.add_pending_child(new_id);
303
304 let parent_self_weak = Arc::downgrade(self);
305 nested.set_on_dispose({
306 let child_id = new_id;
307 move || {
308 if let Some(parent) = parent_self_weak.upgrade() {
309 if parent.nested_count.get() > 0 {
310 parent
311 .nested_count
312 .set(parent.nested_count.get().saturating_sub(1));
313 }
314 let mut invalid = parent.state.invalid.borrow_mut();
315 let new_set = invalid.clone().clear(child_id);
316 *invalid = new_set;
317 parent.state.remove_pending_child(child_id);
318 }
319 }
320 });
321
322 nested
323 }
324}
325
326#[cfg(test)]
327mod tests {
328 use super::*;
329 use crate::snapshot_v2::runtime::TestRuntimeGuard;
330 use std::rc::Rc;
331
332 fn reset_runtime() -> TestRuntimeGuard {
333 reset_runtime_for_tests()
334 }
335
336 #[test]
337 fn test_nested_readonly_snapshot() {
338 let _guard = reset_runtime();
339 let parent = NestedReadonlySnapshot::new(1, SnapshotIdSet::new(), None, Weak::new());
340 let parent_weak = Arc::downgrade(&parent);
341
342 let nested = NestedReadonlySnapshot::new(1, SnapshotIdSet::new(), None, parent_weak);
343
344 assert_eq!(nested.snapshot_id(), 1);
345 assert!(nested.read_only());
346 assert!(!nested.is_disposed());
347 }
348
349 #[test]
350 fn test_nested_readonly_snapshot_root() {
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 let root = nested.root_nested_readonly();
358 assert_eq!(root.snapshot_id(), 1);
359 }
360
361 #[test]
362 fn test_nested_readonly_dispose() {
363 let _guard = reset_runtime();
364 let parent = NestedReadonlySnapshot::new(1, SnapshotIdSet::new(), None, Weak::new());
365 let parent_weak = Arc::downgrade(&parent);
366
367 let nested = NestedReadonlySnapshot::new(1, SnapshotIdSet::new(), None, parent_weak);
368
369 nested.dispose();
370 assert!(nested.is_disposed());
371 }
372
373 #[test]
374 fn test_nested_mutable_snapshot() {
375 let _guard = reset_runtime();
376 let parent = MutableSnapshot::new(1, SnapshotIdSet::new(), None, None, 0);
377 let parent_weak = Arc::downgrade(&parent);
378
379 let nested =
380 NestedMutableSnapshot::new(2, SnapshotIdSet::new().set(1), None, None, parent_weak, 1);
381
382 assert_eq!(nested.snapshot_id(), 2);
383 assert!(!nested.read_only());
384 assert!(!nested.is_disposed());
385 }
386
387 #[test]
388 fn test_nested_mutable_apply() {
389 let _guard = reset_runtime();
390 let parent = MutableSnapshot::new(1, SnapshotIdSet::new(), None, None, 0);
391 let parent_weak = Arc::downgrade(&parent);
392
393 let nested =
394 NestedMutableSnapshot::new(2, SnapshotIdSet::new().set(1), None, None, parent_weak, 1);
395
396 let result = nested.apply();
397 assert!(result.is_success());
398 assert!(nested.applied.get());
399 }
400
401 #[test]
402 fn test_nested_merge_sets_parent_pending_changes() {
403 let _guard = reset_runtime();
404 struct TestObj {
406 id: crate::state::ObjectId,
407 }
408 impl StateObject for TestObj {
409 fn object_id(&self) -> crate::state::ObjectId {
410 self.id
411 }
412 fn first_record(&self) -> Rc<crate::state::StateRecord> {
413 unimplemented!("not used in v2 tests")
414 }
415 fn readable_record(
416 &self,
417 _snapshot_id: crate::snapshot_id_set::SnapshotId,
418 _invalid: &SnapshotIdSet,
419 ) -> Rc<crate::state::StateRecord> {
420 unimplemented!("not used in v2 tests")
421 }
422 fn prepend_state_record(&self, _record: Rc<crate::state::StateRecord>) {
423 unimplemented!("not used in v2 tests")
424 }
425 fn promote_record(
426 &self,
427 _child_id: crate::snapshot_id_set::SnapshotId,
428 ) -> Result<(), &'static str> {
429 unimplemented!("not used in v2 tests")
430 }
431
432 fn as_any(&self) -> &dyn std::any::Any {
433 self
434 }
435 }
436
437 let parent = MutableSnapshot::new(1, SnapshotIdSet::new(), None, None, 0);
438 let child = parent.take_nested_mutable_snapshot(None, None);
439
440 let obj = Arc::new(TestObj {
441 id: crate::state::ObjectId(100),
442 });
443 child.record_write(obj);
444 assert!(!parent.has_pending_changes());
445 child.apply().check();
446 assert!(parent.has_pending_changes());
447 }
448
449 #[test]
450 fn test_nested_conflict_with_parent_same_object() {
451 let _guard = reset_runtime();
452 struct TestObj {
454 id: crate::state::ObjectId,
455 }
456 impl StateObject for TestObj {
457 fn object_id(&self) -> crate::state::ObjectId {
458 self.id
459 }
460 fn first_record(&self) -> Rc<crate::state::StateRecord> {
461 unimplemented!("not used in v2 tests")
462 }
463 fn readable_record(
464 &self,
465 _snapshot_id: crate::snapshot_id_set::SnapshotId,
466 _invalid: &SnapshotIdSet,
467 ) -> Rc<crate::state::StateRecord> {
468 unimplemented!("not used in v2 tests")
469 }
470 fn prepend_state_record(&self, _record: Rc<crate::state::StateRecord>) {
471 unimplemented!("not used in v2 tests")
472 }
473 fn promote_record(
474 &self,
475 _child_id: crate::snapshot_id_set::SnapshotId,
476 ) -> Result<(), &'static str> {
477 unimplemented!("not used in v2 tests")
478 }
479
480 fn as_any(&self) -> &dyn std::any::Any {
481 self
482 }
483 }
484
485 let parent = MutableSnapshot::new(1, SnapshotIdSet::new(), None, None, 0);
486 let child = parent.take_nested_mutable_snapshot(None, None);
487
488 let obj = Arc::new(TestObj {
489 id: crate::state::ObjectId(200),
490 });
491 parent.record_write(obj.clone());
492 child.record_write(obj.clone());
493
494 let result = child.apply();
495 assert!(result.is_failure());
496 }
497
498 #[test]
499 fn test_nested_mutable_apply_twice_fails() {
500 let _guard = reset_runtime();
501 let parent = MutableSnapshot::new(1, SnapshotIdSet::new(), None, None, 0);
502 let parent_weak = Arc::downgrade(&parent);
503
504 let nested =
505 NestedMutableSnapshot::new(2, SnapshotIdSet::new().set(1), None, None, parent_weak, 1);
506
507 nested.apply().check();
508 let result = nested.apply();
509 assert!(result.is_failure());
510 }
511
512 #[test]
513 fn test_nested_mutable_dispose() {
514 let _guard = reset_runtime();
515 let parent = MutableSnapshot::new(1, SnapshotIdSet::new(), None, None, 0);
516 let parent_weak = Arc::downgrade(&parent);
517
518 let nested =
519 NestedMutableSnapshot::new(2, SnapshotIdSet::new().set(1), None, None, parent_weak, 1);
520
521 nested.dispose();
522 assert!(nested.is_disposed());
523 }
524}