Skip to main content

cranpose_core/snapshot_v2/
readonly.rs

1use super::*;
2
3/// A read-only snapshot of state at a specific point in time.
4///
5/// This snapshot cannot be used to modify state. Any attempts to write
6/// to state objects while this snapshot is active will fail.
7///
8/// # Thread Safety
9/// Contains `Cell<T>` and `RefCell<T>` which are not `Send`/`Sync`. This is safe because
10/// snapshots are stored in thread-local storage and never shared across threads. The `Rc`
11/// is used for cheap cloning within a single thread, not for cross-thread sharing.
12pub struct ReadonlySnapshot {
13    pub(super) state: SnapshotState,
14}
15
16impl ReadonlySnapshot {
17    /// Create a new read-only snapshot.
18    pub fn new(
19        id: SnapshotId,
20        invalid: SnapshotIdSet,
21        read_observer: Option<ReadObserver>,
22    ) -> Rc<Self> {
23        Rc::new(Self {
24            state: SnapshotState::new(id, invalid, read_observer, None, false),
25        })
26    }
27
28    pub fn snapshot_id(&self) -> SnapshotId {
29        self.state.id.get()
30    }
31
32    pub fn invalid(&self) -> SnapshotIdSet {
33        self.state.invalid.borrow().clone()
34    }
35
36    pub fn read_only(&self) -> bool {
37        true
38    }
39
40    pub fn root_readonly(&self) -> Rc<Self> {
41        ReadonlySnapshot::new(
42            self.state.id.get(),
43            self.state.invalid.borrow().clone(),
44            self.state.read_observer.borrow().clone(),
45        )
46    }
47
48    pub fn enter<T>(&self, f: impl FnOnce() -> T) -> T {
49        enter_snapshot_scope(AnySnapshot::Readonly(self.root_readonly()), f)
50    }
51
52    pub fn take_nested_snapshot(&self, read_observer: Option<ReadObserver>) -> Rc<Self> {
53        let merged_observer =
54            merge_read_observers(read_observer, self.state.read_observer.borrow().clone());
55        ReadonlySnapshot::new(
56            self.state.id.get(),
57            self.state.invalid.borrow().clone(),
58            merged_observer,
59        )
60    }
61
62    pub fn has_pending_changes(&self) -> bool {
63        false
64    }
65
66    pub fn dispose(&self) {
67        self.state.dispose();
68    }
69
70    pub fn record_read(&self, state: &dyn StateObject) {
71        self.state.record_read(state);
72    }
73
74    pub fn record_write(&self, _state: Rc<dyn StateObject>) {
75        panic!("Cannot write to a read-only snapshot");
76    }
77
78    pub fn is_disposed(&self) -> bool {
79        self.state.disposed.get()
80    }
81
82    pub(crate) fn set_on_dispose<F>(&self, f: F)
83    where
84        F: FnOnce() + 'static,
85    {
86        self.state.set_on_dispose(f);
87    }
88}
89
90#[cfg(test)]
91#[path = "tests/readonly_tests.rs"]
92mod tests;