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 parent_mutable(&self) -> Option<Arc<MutableSnapshot>> {
208 self.parent.upgrade()
209 }
210
211 pub fn dispose(&self) {
212 if !self.state.disposed.get() && self.nested_count.get() == 0 {
213 self.state.dispose();
214 }
215 }
216
217 pub fn record_read(&self, state: &dyn StateObject) {
218 self.state.record_read(state);
219 }
220
221 pub fn record_write(&self, state: Arc<dyn StateObject>) {
222 if self.applied.get() {
223 panic!("Cannot write to an applied snapshot");
224 }
225 if self.state.disposed.get() {
226 panic!("Cannot write to a disposed snapshot");
227 }
228 self.state.record_write(state, self.state.id.get());
229 }
230
231 pub fn close(&self) {
232 self.state.disposed.set(true);
233 }
234
235 pub fn is_disposed(&self) -> bool {
236 self.state.disposed.get()
237 }
238
239 pub fn apply(&self) -> SnapshotApplyResult {
240 if self.state.disposed.get() {
241 return SnapshotApplyResult::Failure;
242 }
243
244 if self.applied.get() {
245 return SnapshotApplyResult::Failure;
246 }
247
248 if let Some(parent) = self.parent.upgrade() {
250 let child_modified = self.state.modified.borrow();
252 if child_modified.is_empty() {
253 self.applied.set(true);
254 self.state.dispose();
255 return SnapshotApplyResult::Success;
256 }
257 if parent.merge_child_modifications(&child_modified).is_err() {
259 return SnapshotApplyResult::Failure;
260 }
261
262 self.applied.set(true);
263 self.state.dispose();
264 SnapshotApplyResult::Success
265 } else {
266 SnapshotApplyResult::Failure
267 }
268 }
269
270 pub fn take_nested_mutable_snapshot(
271 self: &Arc<Self>,
272 read_observer: Option<ReadObserver>,
273 write_observer: Option<WriteObserver>,
274 ) -> Arc<NestedMutableSnapshot> {
275 let merged_read =
276 merge_read_observers(read_observer, self.state.read_observer.borrow().clone());
277 let merged_write =
278 merge_write_observers(write_observer, self.state.write_observer.borrow().clone());
279
280 let parent_id = self.state.id.get();
282 let current_invalid = self.state.invalid.borrow().clone();
283
284 let (new_id, _runtime_invalid) = allocate_snapshot();
286
287 let parent_invalid_with_child = current_invalid.set(new_id);
289 self.state.invalid.replace(parent_invalid_with_child);
290
291 let invalid = current_invalid.add_range(parent_id + 1, new_id);
294
295 let self_weak = Arc::downgrade(&self.root_mutable());
296
297 let nested = NestedMutableSnapshot::new(
298 new_id,
299 invalid,
300 merged_read,
301 merged_write,
302 self_weak,
303 self.state.id.get(), );
305
306 self.nested_count.set(self.nested_count.get() + 1);
307 self.state.add_pending_child(new_id);
308
309 let parent_self_weak = Arc::downgrade(self);
310 nested.set_on_dispose({
311 let child_id = new_id;
312 move || {
313 if let Some(parent) = parent_self_weak.upgrade() {
314 if parent.nested_count.get() > 0 {
315 parent
316 .nested_count
317 .set(parent.nested_count.get().saturating_sub(1));
318 }
319 let mut invalid = parent.state.invalid.borrow_mut();
320 let new_set = invalid.clone().clear(child_id);
321 *invalid = new_set;
322 parent.state.remove_pending_child(child_id);
323 }
324 }
325 });
326
327 nested
328 }
329}
330
331#[cfg(test)]
332mod tests {
333 use super::*;
334 use crate::snapshot_v2::runtime::TestRuntimeGuard;
335 use std::rc::Rc;
336
337 fn reset_runtime() -> TestRuntimeGuard {
338 reset_runtime_for_tests()
339 }
340
341 fn mock_state_record() -> Rc<crate::state::StateRecord> {
342 crate::state::StateRecord::new(crate::state::PREEXISTING_SNAPSHOT_ID, (), None)
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 mock_state_record()
423 }
424 fn try_readable_record(
425 &self,
426 snapshot_id: crate::snapshot_id_set::SnapshotId,
427 invalid: &SnapshotIdSet,
428 ) -> Option<Rc<crate::state::StateRecord>> {
429 Some(self.readable_record(snapshot_id, invalid))
430 }
431 fn readable_record(
432 &self,
433 _snapshot_id: crate::snapshot_id_set::SnapshotId,
434 _invalid: &SnapshotIdSet,
435 ) -> Rc<crate::state::StateRecord> {
436 mock_state_record()
437 }
438 fn prepend_state_record(&self, _record: Rc<crate::state::StateRecord>) {}
439 fn promote_record(
440 &self,
441 _child_id: crate::snapshot_id_set::SnapshotId,
442 ) -> Result<(), &'static str> {
443 Ok(())
444 }
445
446 fn as_any(&self) -> &dyn std::any::Any {
447 self
448 }
449 }
450
451 let parent = MutableSnapshot::new(1, SnapshotIdSet::new(), None, None, 0);
452 let child = parent.take_nested_mutable_snapshot(None, None);
453
454 let obj = Arc::new(TestObj {
455 id: crate::state::ObjectId(100),
456 });
457 child.record_write(obj);
458 assert!(!parent.has_pending_changes());
459 child.apply().check();
460 assert!(parent.has_pending_changes());
461 }
462
463 #[test]
464 fn test_nested_conflict_with_parent_same_object() {
465 let _guard = reset_runtime();
466 struct TestObj {
468 id: crate::state::ObjectId,
469 }
470 impl StateObject for TestObj {
471 fn object_id(&self) -> crate::state::ObjectId {
472 self.id
473 }
474 fn first_record(&self) -> Rc<crate::state::StateRecord> {
475 mock_state_record()
476 }
477 fn try_readable_record(
478 &self,
479 snapshot_id: crate::snapshot_id_set::SnapshotId,
480 invalid: &SnapshotIdSet,
481 ) -> Option<Rc<crate::state::StateRecord>> {
482 Some(self.readable_record(snapshot_id, invalid))
483 }
484 fn readable_record(
485 &self,
486 _snapshot_id: crate::snapshot_id_set::SnapshotId,
487 _invalid: &SnapshotIdSet,
488 ) -> Rc<crate::state::StateRecord> {
489 mock_state_record()
490 }
491 fn prepend_state_record(&self, _record: Rc<crate::state::StateRecord>) {}
492 fn promote_record(
493 &self,
494 _child_id: crate::snapshot_id_set::SnapshotId,
495 ) -> Result<(), &'static str> {
496 Ok(())
497 }
498
499 fn as_any(&self) -> &dyn std::any::Any {
500 self
501 }
502 }
503
504 let parent = MutableSnapshot::new(1, SnapshotIdSet::new(), None, None, 0);
505 let child = parent.take_nested_mutable_snapshot(None, None);
506
507 let obj = Arc::new(TestObj {
508 id: crate::state::ObjectId(200),
509 });
510 parent.record_write(obj.clone());
511 child.record_write(obj.clone());
512
513 let result = child.apply();
514 assert!(result.is_failure());
515 }
516
517 #[test]
518 fn test_nested_mutable_apply_twice_fails() {
519 let _guard = reset_runtime();
520 let parent = MutableSnapshot::new(1, SnapshotIdSet::new(), None, None, 0);
521 let parent_weak = Arc::downgrade(&parent);
522
523 let nested =
524 NestedMutableSnapshot::new(2, SnapshotIdSet::new().set(1), None, None, parent_weak, 1);
525
526 nested.apply().check();
527 let result = nested.apply();
528 assert!(result.is_failure());
529 }
530
531 #[test]
532 fn test_nested_mutable_dispose() {
533 let _guard = reset_runtime();
534 let parent = MutableSnapshot::new(1, SnapshotIdSet::new(), None, None, 0);
535 let parent_weak = Arc::downgrade(&parent);
536
537 let nested =
538 NestedMutableSnapshot::new(2, SnapshotIdSet::new().set(1), None, None, parent_weak, 1);
539
540 nested.dispose();
541 assert!(nested.is_disposed());
542 }
543}