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