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 std::rc::Rc;
302
303 use super::*;
304 use crate::{
305 snapshot_v2::runtime::TestRuntimeGuard,
306 state::{ObjectId, StateObject, StateRecord, PREEXISTING_SNAPSHOT_ID},
307 };
308
309 fn reset_runtime() -> TestRuntimeGuard {
310 reset_runtime_for_tests()
311 }
312
313 fn mock_state_record() -> Rc<StateRecord> {
314 StateRecord::new(PREEXISTING_SNAPSHOT_ID, (), None)
315 }
316
317 struct MockState(usize);
318
319 impl StateObject for MockState {
320 fn object_id(&self) -> ObjectId {
321 ObjectId(self.0)
322 }
323
324 fn first_record(&self) -> Rc<StateRecord> {
325 mock_state_record()
326 }
327
328 fn try_readable_record(
329 &self,
330 snapshot_id: SnapshotId,
331 invalid: &SnapshotIdSet,
332 ) -> Option<Rc<StateRecord>> {
333 Some(self.readable_record(snapshot_id, invalid))
334 }
335
336 fn readable_record(
337 &self,
338 _snapshot_id: SnapshotId,
339 _invalid: &SnapshotIdSet,
340 ) -> Rc<StateRecord> {
341 mock_state_record()
342 }
343
344 fn prepend_state_record(&self, _record: Rc<StateRecord>) {}
345
346 fn promote_record(&self, _child_id: SnapshotId) -> Result<(), &'static str> {
347 Ok(())
348 }
349
350 fn as_any(&self) -> &dyn std::any::Any {
351 self
352 }
353 }
354
355 #[test]
356 fn test_transparent_observer_mutable_snapshot() {
357 let _guard = reset_runtime();
358 let snapshot =
359 TransparentObserverMutableSnapshot::new(1, SnapshotIdSet::new(), None, None, None);
360
361 assert_eq!(snapshot.snapshot_id(), 1);
362 assert!(!snapshot.read_only());
363 assert!(snapshot.can_reuse());
364 }
365
366 #[test]
367 fn test_transparent_observer_mutable_apply() {
368 let _guard = reset_runtime();
369 let snapshot =
370 TransparentObserverMutableSnapshot::new(1, SnapshotIdSet::new(), None, None, None);
371
372 let result = snapshot.apply();
373 assert!(result.is_success());
374 }
375
376 #[test]
377 fn test_transparent_observer_snapshot() {
378 let _guard = reset_runtime();
379 let snapshot = TransparentObserverSnapshot::new(1, SnapshotIdSet::new(), None, None);
380
381 assert_eq!(snapshot.snapshot_id(), 1);
382 assert!(snapshot.read_only());
383 assert!(snapshot.can_reuse());
384 }
385
386 #[test]
387 #[should_panic(expected = "Cannot write to a read-only snapshot")]
388 fn test_transparent_observer_snapshot_write_panics() {
389 let _guard = reset_runtime();
390
391 let snapshot = TransparentObserverSnapshot::new(1, SnapshotIdSet::new(), None, None);
392
393 let mock_state = Arc::new(MockState(0));
394 snapshot.record_write(mock_state);
395 }
396
397 #[test]
398 fn transparent_mutable_set_read_observer_replaces_observer() {
399 let _guard = reset_runtime();
400 let initial_reads = Rc::new(Cell::new(0));
401 let replacement_reads = Rc::new(Cell::new(0));
402 let snapshot = TransparentObserverMutableSnapshot::new(
403 1,
404 SnapshotIdSet::new(),
405 Some(Arc::new({
406 let initial_reads = Rc::clone(&initial_reads);
407 move |_| initial_reads.set(initial_reads.get() + 1)
408 })),
409 None,
410 None,
411 );
412
413 snapshot.set_read_observer(Some(Arc::new({
414 let replacement_reads = Rc::clone(&replacement_reads);
415 move |_| replacement_reads.set(replacement_reads.get() + 1)
416 })));
417 snapshot.record_read(&MockState(1));
418
419 assert_eq!(initial_reads.get(), 0);
420 assert_eq!(replacement_reads.get(), 1);
421 }
422
423 #[test]
424 fn transparent_mutable_set_write_observer_replaces_observer() {
425 let _guard = reset_runtime();
426 let initial_writes = Rc::new(Cell::new(0));
427 let replacement_writes = Rc::new(Cell::new(0));
428 let snapshot = TransparentObserverMutableSnapshot::new(
429 1,
430 SnapshotIdSet::new(),
431 None,
432 Some(Arc::new({
433 let initial_writes = Rc::clone(&initial_writes);
434 move |_| initial_writes.set(initial_writes.get() + 1)
435 })),
436 None,
437 );
438
439 snapshot.set_write_observer(Some(Arc::new({
440 let replacement_writes = Rc::clone(&replacement_writes);
441 move |_| replacement_writes.set(replacement_writes.get() + 1)
442 })));
443 snapshot.record_write(Arc::new(MockState(2)));
444
445 assert_eq!(initial_writes.get(), 0);
446 assert_eq!(replacement_writes.get(), 1);
447 }
448
449 #[test]
450 fn transparent_mutable_nested_snapshot_inherits_replaced_observers() {
451 let _guard = reset_runtime();
452 let parent_reads = Rc::new(Cell::new(0));
453 let parent_writes = Rc::new(Cell::new(0));
454 let snapshot =
455 TransparentObserverMutableSnapshot::new(1, SnapshotIdSet::new(), None, None, None);
456 snapshot.set_read_observer(Some(Arc::new({
457 let parent_reads = Rc::clone(&parent_reads);
458 move |_| parent_reads.set(parent_reads.get() + 1)
459 })));
460 snapshot.set_write_observer(Some(Arc::new({
461 let parent_writes = Rc::clone(&parent_writes);
462 move |_| parent_writes.set(parent_writes.get() + 1)
463 })));
464
465 let nested = snapshot.take_nested_mutable_snapshot(None, None);
466 nested.record_read(&MockState(3));
467 nested.record_write(Arc::new(MockState(4)));
468
469 assert_eq!(parent_reads.get(), 1);
470 assert_eq!(parent_writes.get(), 1);
471 }
472
473 #[test]
474 fn transparent_readonly_set_read_observer_replaces_observer() {
475 let _guard = reset_runtime();
476 let initial_reads = Rc::new(Cell::new(0));
477 let replacement_reads = Rc::new(Cell::new(0));
478 let snapshot = TransparentObserverSnapshot::new(
479 1,
480 SnapshotIdSet::new(),
481 Some(Arc::new({
482 let initial_reads = Rc::clone(&initial_reads);
483 move |_| initial_reads.set(initial_reads.get() + 1)
484 })),
485 None,
486 );
487
488 snapshot.set_read_observer(Some(Arc::new({
489 let replacement_reads = Rc::clone(&replacement_reads);
490 move |_| replacement_reads.set(replacement_reads.get() + 1)
491 })));
492 snapshot.record_read(&MockState(5));
493
494 assert_eq!(initial_reads.get(), 0);
495 assert_eq!(replacement_reads.get(), 1);
496 }
497
498 #[test]
499 fn test_transparent_observer_mutable_nested() {
500 let _guard = reset_runtime();
501 let parent =
502 TransparentObserverMutableSnapshot::new(1, SnapshotIdSet::new(), None, None, None);
503
504 let nested = parent.take_nested_mutable_snapshot(None, None);
505 assert!(nested.snapshot_id() > parent.snapshot_id());
506 }
507
508 #[test]
509 fn test_transparent_observer_snapshot_nested() {
510 let _guard = reset_runtime();
511 let parent = TransparentObserverSnapshot::new(1, SnapshotIdSet::new(), None, None);
512
513 let nested = parent.take_nested_snapshot(None);
514 assert_eq!(nested.snapshot_id(), parent.snapshot_id());
515 assert!(nested.read_only());
516 }
517}