cranpose_core/snapshot_v2/
transparent.rs1use super::*;
7
8#[allow(clippy::arc_with_non_send_sync)]
18pub struct TransparentObserverMutableSnapshot {
19 state: SnapshotState,
20 parent: Option<Weak<TransparentObserverMutableSnapshot>>,
21 nested_count: Cell<usize>,
22 applied: Cell<bool>,
23 reusable: Cell<bool>,
25}
26
27impl TransparentObserverMutableSnapshot {
28 pub fn new(
29 id: SnapshotId,
30 invalid: SnapshotIdSet,
31 read_observer: Option<ReadObserver>,
32 write_observer: Option<WriteObserver>,
33 parent: Option<Weak<TransparentObserverMutableSnapshot>>,
34 ) -> Arc<Self> {
35 Arc::new(Self {
36 state: SnapshotState::new(id, invalid, read_observer, write_observer, false),
37 parent,
38 nested_count: Cell::new(0),
39 applied: Cell::new(false),
40 reusable: Cell::new(true),
41 })
42 }
43
44 pub fn can_reuse(&self) -> bool {
46 self.reusable.get()
47 }
48
49 pub fn set_read_observer(&self, _observer: Option<ReadObserver>) {
51 if !self.can_reuse() {
52 panic!("Cannot change observers on non-reusable snapshot");
53 }
54 }
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 }
66
67 pub fn snapshot_id(&self) -> SnapshotId {
68 self.state.id.get()
69 }
70
71 pub fn invalid(&self) -> SnapshotIdSet {
72 self.state.invalid.borrow().clone()
73 }
74
75 pub fn read_only(&self) -> bool {
76 false
77 }
78
79 pub fn root_transparent_mutable(self: &Arc<Self>) -> Arc<Self> {
80 match &self.parent {
81 Some(weak) => weak
82 .upgrade()
83 .map(|parent| parent.root_transparent_mutable())
84 .unwrap_or_else(|| self.clone()),
85 None => self.clone(),
86 }
87 }
88
89 pub fn enter<T>(self: &Arc<Self>, f: impl FnOnce() -> T) -> T {
90 let prev = current_snapshot();
91
92 if let Some(ref snapshot) = prev {
93 if snapshot.is_same_transparent(self) {
94 return f();
95 }
96 }
97
98 set_current_snapshot(Some(AnySnapshot::TransparentMutable(self.clone())));
99 let out = f();
100 set_current_snapshot(prev);
101 out
102 }
103
104 pub fn take_nested_snapshot(
105 &self,
106 read_observer: Option<ReadObserver>,
107 ) -> Arc<ReadonlySnapshot> {
108 let merged_observer = merge_read_observers(read_observer, self.state.read_observer.clone());
109 ReadonlySnapshot::new(
110 self.state.id.get(),
111 self.state.invalid.borrow().clone(),
112 merged_observer,
113 )
114 }
115
116 pub fn has_pending_changes(&self) -> bool {
117 !self.state.modified.borrow().is_empty()
118 }
119
120 pub fn dispose(&self) {
121 if !self.state.disposed.get() && self.nested_count.get() == 0 {
122 self.state.dispose();
123 }
124 }
125
126 pub fn record_read(&self, state: &dyn StateObject) {
127 self.state.record_read(state);
128 }
129
130 pub fn record_write(&self, state: Arc<dyn StateObject>) {
131 if self.applied.get() {
132 panic!("Cannot write to an applied snapshot");
133 }
134 self.state.record_write(state, self.state.id.get());
135 }
136
137 pub fn close(&self) {
138 self.state.disposed.set(true);
139 }
140
141 pub fn is_disposed(&self) -> bool {
142 self.state.disposed.get()
143 }
144
145 pub fn apply(&self) -> SnapshotApplyResult {
146 if self.state.disposed.get() || self.applied.get() {
147 return SnapshotApplyResult::Failure;
148 }
149
150 self.applied.set(true);
151 SnapshotApplyResult::Success
152 }
153
154 pub fn take_nested_mutable_snapshot(
155 &self,
156 read_observer: Option<ReadObserver>,
157 write_observer: Option<WriteObserver>,
158 ) -> Arc<TransparentObserverMutableSnapshot> {
159 let merged_read = merge_read_observers(read_observer, self.state.read_observer.clone());
160 let merged_write = merge_write_observers(write_observer, self.state.write_observer.clone());
161
162 let mut invalid = self.state.invalid.borrow().clone();
163 let new_id = self.state.id.get() + 1;
164 invalid = invalid.set(new_id);
165
166 TransparentObserverMutableSnapshot::new(
167 new_id,
168 invalid,
169 merged_read,
170 merged_write,
171 self.parent.clone(),
172 )
173 }
174}
175
176#[allow(clippy::arc_with_non_send_sync)]
185pub struct TransparentObserverSnapshot {
186 state: SnapshotState,
187 parent: Option<Weak<TransparentObserverSnapshot>>,
188 reusable: Cell<bool>,
189}
190
191impl TransparentObserverSnapshot {
192 pub fn new(
193 id: SnapshotId,
194 invalid: SnapshotIdSet,
195 read_observer: Option<ReadObserver>,
196 parent: Option<Weak<TransparentObserverSnapshot>>,
197 ) -> Arc<Self> {
198 Arc::new(Self {
199 state: SnapshotState::new(id, invalid, read_observer, None, false),
200 parent,
201 reusable: Cell::new(true),
202 })
203 }
204
205 pub fn can_reuse(&self) -> bool {
207 self.reusable.get()
208 }
209
210 pub fn set_read_observer(&self, _observer: Option<ReadObserver>) {
212 if !self.can_reuse() {
213 panic!("Cannot change observers on non-reusable snapshot");
214 }
215 }
217
218 pub fn snapshot_id(&self) -> SnapshotId {
219 self.state.id.get()
220 }
221
222 pub fn invalid(&self) -> SnapshotIdSet {
223 self.state.invalid.borrow().clone()
224 }
225
226 pub fn read_only(&self) -> bool {
227 true
228 }
229
230 pub fn root_transparent_readonly(self: &Arc<Self>) -> Arc<Self> {
231 match &self.parent {
232 Some(weak) => weak
233 .upgrade()
234 .map(|parent| parent.root_transparent_readonly())
235 .unwrap_or_else(|| self.clone()),
236 None => self.clone(),
237 }
238 }
239
240 pub fn enter<T>(self: &Arc<Self>, f: impl FnOnce() -> T) -> T {
241 let previous = current_snapshot();
242
243 if let Some(ref prev_snapshot) = previous {
244 if prev_snapshot.is_same_transparent_readonly(self) {
245 return f();
246 }
247 }
248
249 set_current_snapshot(Some(AnySnapshot::TransparentReadonly(self.clone())));
250 let result = f();
251 set_current_snapshot(previous);
252 result
253 }
254
255 pub fn take_nested_snapshot(
256 &self,
257 read_observer: Option<ReadObserver>,
258 ) -> Arc<TransparentObserverSnapshot> {
259 let merged_observer = merge_read_observers(read_observer, self.state.read_observer.clone());
260 TransparentObserverSnapshot::new(
261 self.state.id.get(),
262 self.state.invalid.borrow().clone(),
263 merged_observer,
264 self.parent.clone(),
265 )
266 }
267
268 pub fn has_pending_changes(&self) -> bool {
269 false
270 }
271
272 pub fn dispose(&self) {
273 self.state.dispose();
274 }
275
276 pub fn record_read(&self, state: &dyn StateObject) {
277 self.state.record_read(state);
278 }
279
280 pub fn record_write(&self, _state: Arc<dyn StateObject>) {
281 panic!("Cannot write to a read-only snapshot");
282 }
283
284 pub fn close(&self) {
285 self.state.disposed.set(true);
286 }
287
288 pub fn is_disposed(&self) -> bool {
289 self.state.disposed.get()
290 }
291}
292
293#[cfg(test)]
294mod tests {
295 use super::*;
296 use crate::snapshot_v2::runtime::TestRuntimeGuard;
297
298 fn reset_runtime() -> TestRuntimeGuard {
299 reset_runtime_for_tests()
300 }
301
302 #[test]
303 fn test_transparent_observer_mutable_snapshot() {
304 let _guard = reset_runtime();
305 let snapshot =
306 TransparentObserverMutableSnapshot::new(1, SnapshotIdSet::new(), None, None, None);
307
308 assert_eq!(snapshot.snapshot_id(), 1);
309 assert!(!snapshot.read_only());
310 assert!(snapshot.can_reuse());
311 }
312
313 #[test]
314 fn test_transparent_observer_mutable_apply() {
315 let _guard = reset_runtime();
316 let snapshot =
317 TransparentObserverMutableSnapshot::new(1, SnapshotIdSet::new(), None, None, None);
318
319 let result = snapshot.apply();
320 assert!(result.is_success());
321 }
322
323 #[test]
324 fn test_transparent_observer_snapshot() {
325 let _guard = reset_runtime();
326 let snapshot = TransparentObserverSnapshot::new(1, SnapshotIdSet::new(), None, None);
327
328 assert_eq!(snapshot.snapshot_id(), 1);
329 assert!(snapshot.read_only());
330 assert!(snapshot.can_reuse());
331 }
332
333 #[test]
334 #[should_panic(expected = "Cannot write to a read-only snapshot")]
335 fn test_transparent_observer_snapshot_write_panics() {
336 use crate::state::StateObject;
337 use std::cell::Cell;
338
339 let _guard = reset_runtime();
340
341 #[allow(dead_code)]
342 struct MockState {
343 value: Cell<i32>,
344 }
345
346 impl StateObject for MockState {
347 fn object_id(&self) -> crate::state::ObjectId {
348 crate::state::ObjectId(0)
349 }
350
351 fn first_record(&self) -> Arc<crate::state::StateRecord> {
352 unimplemented!("Not needed for tests")
353 }
354
355 fn readable_record(
356 &self,
357 _snapshot_id: crate::snapshot_id_set::SnapshotId,
358 _invalid: &SnapshotIdSet,
359 ) -> Arc<crate::state::StateRecord> {
360 unimplemented!("Not needed for tests")
361 }
362
363 fn prepend_state_record(&self, _record: Arc<crate::state::StateRecord>) {
364 unimplemented!("Not needed for tests")
365 }
366
367 fn promote_record(
368 &self,
369 _child_id: crate::snapshot_id_set::SnapshotId,
370 ) -> Result<(), &'static str> {
371 unimplemented!("Not needed for tests")
372 }
373
374 fn as_any(&self) -> &dyn std::any::Any {
375 self
376 }
377 }
378
379 let snapshot = TransparentObserverSnapshot::new(1, SnapshotIdSet::new(), None, None);
380
381 let mock_state = Arc::new(MockState {
382 value: Cell::new(42),
383 });
384 snapshot.record_write(mock_state);
385 }
386
387 #[test]
388 fn test_transparent_observer_mutable_nested() {
389 let _guard = reset_runtime();
390 let parent =
391 TransparentObserverMutableSnapshot::new(1, SnapshotIdSet::new(), None, None, None);
392
393 let nested = parent.take_nested_mutable_snapshot(None, None);
394 assert!(nested.snapshot_id() > parent.snapshot_id());
395 }
396
397 #[test]
398 fn test_transparent_observer_snapshot_nested() {
399 let _guard = reset_runtime();
400 let parent = TransparentObserverSnapshot::new(1, SnapshotIdSet::new(), None, None);
401
402 let nested = parent.take_nested_snapshot(None);
403 assert_eq!(nested.snapshot_id(), parent.snapshot_id());
404 assert!(nested.read_only());
405 }
406}