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