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