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 std::rc::Rc;
330
331 use super::*;
332 use crate::snapshot_v2::runtime::TestRuntimeGuard;
333
334 fn reset_runtime() -> TestRuntimeGuard {
335 reset_runtime_for_tests()
336 }
337
338 fn mock_state_record() -> Rc<crate::state::StateRecord> {
339 crate::state::StateRecord::new(crate::state::PREEXISTING_SNAPSHOT_ID, (), None)
340 }
341
342 #[test]
343 fn test_nested_readonly_snapshot() {
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 assert_eq!(nested.snapshot_id(), 1);
351 assert!(nested.read_only());
352 assert!(!nested.is_disposed());
353 }
354
355 #[test]
356 fn test_nested_readonly_snapshot_root() {
357 let _guard = reset_runtime();
358 let parent = NestedReadonlySnapshot::new(1, SnapshotIdSet::new(), None, Weak::new());
359 let parent_weak = Arc::downgrade(&parent);
360
361 let nested = NestedReadonlySnapshot::new(1, SnapshotIdSet::new(), None, parent_weak);
362
363 let root = nested.root_nested_readonly();
364 assert_eq!(root.snapshot_id(), 1);
365 }
366
367 #[test]
368 fn test_nested_readonly_dispose() {
369 let _guard = reset_runtime();
370 let parent = NestedReadonlySnapshot::new(1, SnapshotIdSet::new(), None, Weak::new());
371 let parent_weak = Arc::downgrade(&parent);
372
373 let nested = NestedReadonlySnapshot::new(1, SnapshotIdSet::new(), None, parent_weak);
374
375 nested.dispose();
376 assert!(nested.is_disposed());
377 }
378
379 #[test]
380 fn test_nested_mutable_snapshot() {
381 let _guard = reset_runtime();
382 let parent = MutableSnapshot::new(1, SnapshotIdSet::new(), None, None, 0);
383 let parent_weak = Arc::downgrade(&parent);
384
385 let nested =
386 NestedMutableSnapshot::new(2, SnapshotIdSet::new().set(1), None, None, parent_weak, 1);
387
388 assert_eq!(nested.snapshot_id(), 2);
389 assert!(!nested.read_only());
390 assert!(!nested.is_disposed());
391 }
392
393 #[test]
394 fn test_nested_mutable_apply() {
395 let _guard = reset_runtime();
396 let parent = MutableSnapshot::new(1, SnapshotIdSet::new(), None, None, 0);
397 let parent_weak = Arc::downgrade(&parent);
398
399 let nested =
400 NestedMutableSnapshot::new(2, SnapshotIdSet::new().set(1), None, None, parent_weak, 1);
401
402 let result = nested.apply();
403 assert!(result.is_success());
404 assert!(nested.applied.get());
405 }
406
407 #[test]
408 fn test_nested_merge_sets_parent_pending_changes() {
409 let _guard = reset_runtime();
410 struct TestObj {
412 id: crate::state::ObjectId,
413 }
414 impl StateObject for TestObj {
415 fn object_id(&self) -> crate::state::ObjectId {
416 self.id
417 }
418 fn first_record(&self) -> Rc<crate::state::StateRecord> {
419 mock_state_record()
420 }
421 fn try_readable_record(
422 &self,
423 snapshot_id: crate::snapshot_id_set::SnapshotId,
424 invalid: &SnapshotIdSet,
425 ) -> Option<Rc<crate::state::StateRecord>> {
426 Some(self.readable_record(snapshot_id, invalid))
427 }
428 fn readable_record(
429 &self,
430 _snapshot_id: crate::snapshot_id_set::SnapshotId,
431 _invalid: &SnapshotIdSet,
432 ) -> Rc<crate::state::StateRecord> {
433 mock_state_record()
434 }
435 fn prepend_state_record(&self, _record: Rc<crate::state::StateRecord>) {}
436 fn promote_record(
437 &self,
438 _child_id: crate::snapshot_id_set::SnapshotId,
439 ) -> Result<(), &'static str> {
440 Ok(())
441 }
442
443 fn as_any(&self) -> &dyn std::any::Any {
444 self
445 }
446 }
447
448 let parent = MutableSnapshot::new(1, SnapshotIdSet::new(), None, None, 0);
449 let child = parent.take_nested_mutable_snapshot(None, None);
450
451 let obj = Arc::new(TestObj {
452 id: crate::state::ObjectId(100),
453 });
454 child.record_write(obj);
455 assert!(!parent.has_pending_changes());
456 child.apply().check();
457 assert!(parent.has_pending_changes());
458 }
459
460 #[test]
461 fn test_nested_conflict_with_parent_same_object() {
462 let _guard = reset_runtime();
463 struct TestObj {
465 id: crate::state::ObjectId,
466 }
467 impl StateObject for TestObj {
468 fn object_id(&self) -> crate::state::ObjectId {
469 self.id
470 }
471 fn first_record(&self) -> Rc<crate::state::StateRecord> {
472 mock_state_record()
473 }
474 fn try_readable_record(
475 &self,
476 snapshot_id: crate::snapshot_id_set::SnapshotId,
477 invalid: &SnapshotIdSet,
478 ) -> Option<Rc<crate::state::StateRecord>> {
479 Some(self.readable_record(snapshot_id, invalid))
480 }
481 fn readable_record(
482 &self,
483 _snapshot_id: crate::snapshot_id_set::SnapshotId,
484 _invalid: &SnapshotIdSet,
485 ) -> Rc<crate::state::StateRecord> {
486 mock_state_record()
487 }
488 fn prepend_state_record(&self, _record: Rc<crate::state::StateRecord>) {}
489 fn promote_record(
490 &self,
491 _child_id: crate::snapshot_id_set::SnapshotId,
492 ) -> Result<(), &'static str> {
493 Ok(())
494 }
495
496 fn as_any(&self) -> &dyn std::any::Any {
497 self
498 }
499 }
500
501 let parent = MutableSnapshot::new(1, SnapshotIdSet::new(), None, None, 0);
502 let child = parent.take_nested_mutable_snapshot(None, None);
503
504 let obj = Arc::new(TestObj {
505 id: crate::state::ObjectId(200),
506 });
507 parent.record_write(obj.clone());
508 child.record_write(obj.clone());
509
510 let result = child.apply();
511 assert!(result.is_failure());
512 }
513
514 #[test]
515 fn test_nested_mutable_apply_twice_fails() {
516 let _guard = reset_runtime();
517 let parent = MutableSnapshot::new(1, SnapshotIdSet::new(), None, None, 0);
518 let parent_weak = Arc::downgrade(&parent);
519
520 let nested =
521 NestedMutableSnapshot::new(2, SnapshotIdSet::new().set(1), None, None, parent_weak, 1);
522
523 nested.apply().check();
524 let result = nested.apply();
525 assert!(result.is_failure());
526 }
527
528 #[test]
529 fn test_nested_mutable_dispose() {
530 let _guard = reset_runtime();
531 let parent = MutableSnapshot::new(1, SnapshotIdSet::new(), None, None, 0);
532 let parent_weak = Arc::downgrade(&parent);
533
534 let nested =
535 NestedMutableSnapshot::new(2, SnapshotIdSet::new().set(1), None, None, parent_weak, 1);
536
537 nested.dispose();
538 assert!(nested.is_disposed());
539 }
540}