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