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 root = Arc::downgrade(&self.root_mutable());
264 allocate_nested_mutable_snapshot(self, root, read_observer, write_observer)
265 }
266}
267
268impl NestedMutableHost for NestedMutableSnapshot {
269 fn snapshot_state(&self) -> &SnapshotState {
270 &self.state
271 }
272
273 fn nested_count(&self) -> &Cell<usize> {
274 &self.nested_count
275 }
276}
277
278#[cfg(test)]
279mod tests {
280 use std::rc::Rc;
281
282 use super::*;
283 use crate::snapshot_v2::runtime::TestRuntimeGuard;
284
285 fn reset_runtime() -> TestRuntimeGuard {
286 reset_runtime_for_tests()
287 }
288
289 fn mock_state_record() -> Rc<crate::state::StateRecord> {
290 crate::state::StateRecord::new(crate::state::PREEXISTING_SNAPSHOT_ID, (), None)
291 }
292
293 #[test]
294 fn test_nested_readonly_snapshot() {
295 let _guard = reset_runtime();
296 let parent = NestedReadonlySnapshot::new(1, SnapshotIdSet::new(), None, Weak::new());
297 let parent_weak = Arc::downgrade(&parent);
298
299 let nested = NestedReadonlySnapshot::new(1, SnapshotIdSet::new(), None, parent_weak);
300
301 assert_eq!(nested.snapshot_id(), 1);
302 assert!(nested.read_only());
303 assert!(!nested.is_disposed());
304 }
305
306 #[test]
307 fn test_nested_readonly_snapshot_root() {
308 let _guard = reset_runtime();
309 let parent = NestedReadonlySnapshot::new(1, SnapshotIdSet::new(), None, Weak::new());
310 let parent_weak = Arc::downgrade(&parent);
311
312 let nested = NestedReadonlySnapshot::new(1, SnapshotIdSet::new(), None, parent_weak);
313
314 let root = nested.root_nested_readonly();
315 assert_eq!(root.snapshot_id(), 1);
316 }
317
318 #[test]
319 fn test_nested_readonly_dispose() {
320 let _guard = reset_runtime();
321 let parent = NestedReadonlySnapshot::new(1, SnapshotIdSet::new(), None, Weak::new());
322 let parent_weak = Arc::downgrade(&parent);
323
324 let nested = NestedReadonlySnapshot::new(1, SnapshotIdSet::new(), None, parent_weak);
325
326 nested.dispose();
327 assert!(nested.is_disposed());
328 }
329
330 #[test]
331 fn test_nested_mutable_snapshot() {
332 let _guard = reset_runtime();
333 let parent = MutableSnapshot::new(1, SnapshotIdSet::new(), None, None, 0);
334 let parent_weak = Arc::downgrade(&parent);
335
336 let nested =
337 NestedMutableSnapshot::new(2, SnapshotIdSet::new().set(1), None, None, parent_weak, 1);
338
339 assert_eq!(nested.snapshot_id(), 2);
340 assert!(!nested.read_only());
341 assert!(!nested.is_disposed());
342 }
343
344 #[test]
345 fn test_nested_mutable_apply() {
346 let _guard = reset_runtime();
347 let parent = MutableSnapshot::new(1, SnapshotIdSet::new(), None, None, 0);
348 let parent_weak = Arc::downgrade(&parent);
349
350 let nested =
351 NestedMutableSnapshot::new(2, SnapshotIdSet::new().set(1), None, None, parent_weak, 1);
352
353 let result = nested.apply();
354 assert!(result.is_success());
355 assert!(nested.applied.get());
356 }
357
358 #[test]
359 fn test_nested_merge_sets_parent_pending_changes() {
360 let _guard = reset_runtime();
361 struct TestObj {
362 id: crate::state::ObjectId,
363 }
364 impl StateObject for TestObj {
365 fn object_id(&self) -> crate::state::ObjectId {
366 self.id
367 }
368 fn first_record(&self) -> Rc<crate::state::StateRecord> {
369 mock_state_record()
370 }
371 fn try_readable_record(
372 &self,
373 snapshot_id: crate::snapshot_id_set::SnapshotId,
374 invalid: &SnapshotIdSet,
375 ) -> Option<Rc<crate::state::StateRecord>> {
376 Some(self.readable_record(snapshot_id, invalid))
377 }
378 fn readable_record(
379 &self,
380 _snapshot_id: crate::snapshot_id_set::SnapshotId,
381 _invalid: &SnapshotIdSet,
382 ) -> Rc<crate::state::StateRecord> {
383 mock_state_record()
384 }
385 fn prepend_state_record(&self, _record: Rc<crate::state::StateRecord>) {}
386 fn promote_record(
387 &self,
388 _child_id: crate::snapshot_id_set::SnapshotId,
389 ) -> Result<(), &'static str> {
390 Ok(())
391 }
392
393 fn as_any(&self) -> &dyn std::any::Any {
394 self
395 }
396 }
397
398 let parent = MutableSnapshot::new(1, SnapshotIdSet::new(), None, None, 0);
399 let child = parent.take_nested_mutable_snapshot(None, None);
400
401 let obj = Arc::new(TestObj {
402 id: crate::state::ObjectId(100),
403 });
404 child.record_write(obj);
405 assert!(!parent.has_pending_changes());
406 child.apply().check();
407 assert!(parent.has_pending_changes());
408 }
409
410 #[test]
411 fn test_nested_conflict_with_parent_same_object() {
412 let _guard = reset_runtime();
413 struct TestObj {
414 id: crate::state::ObjectId,
415 }
416 impl StateObject for TestObj {
417 fn object_id(&self) -> crate::state::ObjectId {
418 self.id
419 }
420 fn first_record(&self) -> Rc<crate::state::StateRecord> {
421 mock_state_record()
422 }
423 fn try_readable_record(
424 &self,
425 snapshot_id: crate::snapshot_id_set::SnapshotId,
426 invalid: &SnapshotIdSet,
427 ) -> Option<Rc<crate::state::StateRecord>> {
428 Some(self.readable_record(snapshot_id, invalid))
429 }
430 fn readable_record(
431 &self,
432 _snapshot_id: crate::snapshot_id_set::SnapshotId,
433 _invalid: &SnapshotIdSet,
434 ) -> Rc<crate::state::StateRecord> {
435 mock_state_record()
436 }
437 fn prepend_state_record(&self, _record: Rc<crate::state::StateRecord>) {}
438 fn promote_record(
439 &self,
440 _child_id: crate::snapshot_id_set::SnapshotId,
441 ) -> Result<(), &'static str> {
442 Ok(())
443 }
444
445 fn as_any(&self) -> &dyn std::any::Any {
446 self
447 }
448 }
449
450 let parent = MutableSnapshot::new(1, SnapshotIdSet::new(), None, None, 0);
451 let child = parent.take_nested_mutable_snapshot(None, None);
452
453 let obj = Arc::new(TestObj {
454 id: crate::state::ObjectId(200),
455 });
456 parent.record_write(obj.clone());
457 child.record_write(obj.clone());
458
459 let result = child.apply();
460 assert!(result.is_failure());
461 }
462
463 #[test]
464 fn test_nested_mutable_apply_twice_fails() {
465 let _guard = reset_runtime();
466 let parent = MutableSnapshot::new(1, SnapshotIdSet::new(), None, None, 0);
467 let parent_weak = Arc::downgrade(&parent);
468
469 let nested =
470 NestedMutableSnapshot::new(2, SnapshotIdSet::new().set(1), None, None, parent_weak, 1);
471
472 nested.apply().check();
473 let result = nested.apply();
474 assert!(result.is_failure());
475 }
476
477 #[test]
478 fn test_nested_mutable_dispose() {
479 let _guard = reset_runtime();
480 let parent = MutableSnapshot::new(1, SnapshotIdSet::new(), None, None, 0);
481 let parent_weak = Arc::downgrade(&parent);
482
483 let nested =
484 NestedMutableSnapshot::new(2, SnapshotIdSet::new().set(1), None, None, parent_weak, 1);
485
486 nested.dispose();
487 assert!(nested.is_disposed());
488 }
489}