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