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