Skip to main content

cranpose_core/snapshot_v2/
nested.rs

1use super::*;
2
3/// A nested read-only snapshot.
4///
5/// This is a read-only snapshot that has a parent snapshot. It inherits
6/// the parent's invalid set and can be disposed independently.
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 `Arc`
11/// is used for cheap cloning within a single thread, not for cross-thread sharing.
12pub struct NestedReadonlySnapshot {
13    state: SnapshotState,
14    parent: Weak<NestedReadonlySnapshot>,
15}
16
17impl NestedReadonlySnapshot {
18    pub fn new(
19        id: SnapshotId,
20        invalid: SnapshotIdSet,
21        read_observer: Option<ReadObserver>,
22        parent: Weak<NestedReadonlySnapshot>,
23    ) -> Arc<Self> {
24        Arc::new(Self {
25            state: SnapshotState::new(id, invalid, read_observer, None, false),
26            parent,
27        })
28    }
29
30    pub fn snapshot_id(&self) -> SnapshotId {
31        self.state.id.get()
32    }
33
34    pub fn invalid(&self) -> SnapshotIdSet {
35        self.state.invalid.borrow().clone()
36    }
37
38    pub fn read_only(&self) -> bool {
39        true
40    }
41
42    pub fn root_nested_readonly(&self) -> Arc<NestedReadonlySnapshot> {
43        if let Some(parent) = self.parent.upgrade() {
44            parent.root_nested_readonly()
45        } else {
46            NestedReadonlySnapshot::new(
47                self.state.id.get(),
48                self.state.invalid.borrow().clone(),
49                self.state.read_observer.borrow().clone(),
50                Weak::new(),
51            )
52        }
53    }
54
55    pub fn enter<T>(self: &Arc<Self>, f: impl FnOnce() -> T) -> T {
56        enter_snapshot_scope(AnySnapshot::NestedReadonly(self.clone()), f)
57    }
58
59    pub fn take_nested_snapshot(
60        &self,
61        read_observer: Option<ReadObserver>,
62    ) -> Arc<NestedReadonlySnapshot> {
63        let merged_observer =
64            merge_read_observers(read_observer, self.state.read_observer.borrow().clone());
65
66        NestedReadonlySnapshot::new(
67            self.state.id.get(),
68            self.state.invalid.borrow().clone(),
69            merged_observer,
70            self.parent.clone(),
71        )
72    }
73
74    pub fn has_pending_changes(&self) -> bool {
75        false
76    }
77
78    pub fn dispose(&self) {
79        if !self.state.disposed.get() {
80            self.state.dispose();
81        }
82    }
83
84    pub fn record_read(&self, state: &dyn StateObject) {
85        self.state.record_read(state);
86    }
87
88    pub fn record_write(&self, _state: Arc<dyn StateObject>) {
89        panic!("Cannot write to a read-only snapshot");
90    }
91
92    pub fn close(&self) {
93        self.state.disposed.set(true);
94    }
95
96    pub fn is_disposed(&self) -> bool {
97        self.state.disposed.get()
98    }
99}
100
101/// A nested mutable snapshot.
102///
103/// This is a mutable snapshot that has a parent. Changes made in this
104/// snapshot are applied to the parent when `apply()` is called, not
105/// to the global snapshot.
106///
107/// # Thread Safety
108/// Contains `Cell<T>` and `RefCell<T>` which are not `Send`/`Sync`. This is safe because
109/// snapshots are stored in thread-local storage and never shared across threads. The `Arc`
110/// is used for cheap cloning within a single thread, not for cross-thread sharing.
111pub struct NestedMutableSnapshot {
112    state: SnapshotState,
113    parent: Weak<MutableSnapshot>,
114    nested_count: Cell<usize>,
115    applied: Cell<bool>,
116    base_parent_id: SnapshotId,
117}
118
119impl NestedMutableSnapshot {
120    pub fn new(
121        id: SnapshotId,
122        invalid: SnapshotIdSet,
123        read_observer: Option<ReadObserver>,
124        write_observer: Option<WriteObserver>,
125        parent: Weak<MutableSnapshot>,
126        base_parent_id: SnapshotId,
127    ) -> Arc<Self> {
128        Arc::new(Self {
129            state: SnapshotState::new(id, invalid, read_observer, write_observer, true),
130            parent,
131            nested_count: Cell::new(0),
132            applied: Cell::new(false),
133            base_parent_id,
134        })
135    }
136
137    pub fn snapshot_id(&self) -> SnapshotId {
138        self.state.id.get()
139    }
140
141    pub fn invalid(&self) -> SnapshotIdSet {
142        self.state.invalid.borrow().clone()
143    }
144
145    pub fn read_only(&self) -> bool {
146        false
147    }
148
149    pub(crate) fn set_on_dispose<F>(&self, f: F)
150    where
151        F: FnOnce() + 'static,
152    {
153        self.state.set_on_dispose(f);
154    }
155
156    pub fn root_mutable(&self) -> Arc<MutableSnapshot> {
157        if let Some(parent) = self.parent.upgrade() {
158            parent.root_mutable()
159        } else {
160            MutableSnapshot::new(
161                self.state.id.get(),
162                self.state.invalid.borrow().clone(),
163                self.state.read_observer.borrow().clone(),
164                self.state.write_observer.borrow().clone(),
165                self.base_parent_id,
166            )
167        }
168    }
169
170    pub fn enter<T>(self: &Arc<Self>, f: impl FnOnce() -> T) -> T {
171        enter_snapshot_scope(AnySnapshot::NestedMutable(self.clone()), f)
172    }
173
174    pub fn take_nested_snapshot(
175        &self,
176        read_observer: Option<ReadObserver>,
177    ) -> Arc<ReadonlySnapshot> {
178        let merged_observer =
179            merge_read_observers(read_observer, self.state.read_observer.borrow().clone());
180
181        ReadonlySnapshot::new(
182            self.state.id.get(),
183            self.state.invalid.borrow().clone(),
184            merged_observer,
185        )
186    }
187
188    pub fn has_pending_changes(&self) -> bool {
189        !self.state.modified.borrow().is_empty()
190    }
191
192    pub fn pending_children(&self) -> Vec<SnapshotId> {
193        self.state.pending_children()
194    }
195
196    pub fn has_pending_children(&self) -> bool {
197        self.state.has_pending_children()
198    }
199
200    pub fn dispose(&self) {
201        if !self.state.disposed.get() && self.nested_count.get() == 0 {
202            self.state.dispose();
203        }
204    }
205
206    pub fn record_read(&self, state: &dyn StateObject) {
207        self.state.record_read(state);
208    }
209
210    pub fn record_write(&self, state: Arc<dyn StateObject>) {
211        assert!(!self.applied.get(), "Cannot write to an applied snapshot");
212        assert!(
213            !self.state.disposed.get(),
214            "Cannot write to a disposed snapshot"
215        );
216        self.state.record_write(state, self.state.id.get());
217    }
218
219    pub fn close(&self) {
220        self.state.disposed.set(true);
221    }
222
223    pub fn is_disposed(&self) -> bool {
224        self.state.disposed.get()
225    }
226
227    pub fn apply(&self) -> SnapshotApplyResult {
228        if self.state.disposed.get() {
229            return SnapshotApplyResult::Failure;
230        }
231
232        if self.applied.get() {
233            return SnapshotApplyResult::Failure;
234        }
235
236        if let Some(parent) = self.parent.upgrade() {
237            let child_modified = self.state.modified.borrow();
238            if child_modified.is_empty() {
239                self.applied.set(true);
240                self.state.dispose();
241                return SnapshotApplyResult::Success;
242            }
243            if parent.merge_child_modifications(&child_modified).is_err() {
244                return SnapshotApplyResult::Failure;
245            }
246
247            self.applied.set(true);
248            self.state.dispose();
249            SnapshotApplyResult::Success
250        } else {
251            SnapshotApplyResult::Failure
252        }
253    }
254
255    pub fn take_nested_mutable_snapshot(
256        self: &Arc<Self>,
257        read_observer: Option<ReadObserver>,
258        write_observer: Option<WriteObserver>,
259    ) -> Arc<NestedMutableSnapshot> {
260        let root = Arc::downgrade(&self.root_mutable());
261        allocate_nested_mutable_snapshot(self, root, read_observer, write_observer)
262    }
263}
264
265impl NestedMutableHost for NestedMutableSnapshot {
266    fn snapshot_state(&self) -> &SnapshotState {
267        &self.state
268    }
269
270    fn nested_count(&self) -> &Cell<usize> {
271        &self.nested_count
272    }
273}
274
275#[cfg(test)]
276#[path = "tests/nested_tests.rs"]
277mod tests;