1use std::{
2 any::{Any, TypeId},
3 cell::{Cell, RefCell},
4 fmt,
5 hash::Hash,
6 marker::PhantomData,
7 ops::Deref,
8 rc::{Rc, Weak as RcWeak},
9 sync::{Arc, Mutex, MutexGuard, PoisonError, Weak},
10};
11
12use smallvec::SmallVec;
13
14use crate::{
15 RecomposeScope, RecomposeScopeInner, RuntimeHandle, ScopeId, StateId,
16 collections::map::{HashMap, HashSet},
17 debug_trace::debug_record_scope_invalidation,
18 runtime,
19 snapshot_id_set::{SnapshotId, SnapshotIdSet},
20 snapshot_pinning::lowest_pinned_snapshot,
21 snapshot_v2::{
22 AnySnapshot, GlobalSnapshot, advance_global_snapshot, allocate_record_id, current_snapshot,
23 },
24 with_current_composer_opt,
25};
26
27pub(crate) const PREEXISTING_SNAPSHOT_ID: SnapshotId = 1;
28
29const INVALID_SNAPSHOT_ID: SnapshotId = 0;
30
31const SNAPSHOT_ID_MAX: SnapshotId = usize::MAX;
32
33#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug, Default)]
34pub struct ObjectId(pub(crate) usize);
35
36impl ObjectId {
37 pub(crate) fn new<T: ?Sized + 'static>(object: &Arc<T>) -> Self {
38 Self(Arc::as_ptr(object) as *const () as usize)
39 }
40
41 #[inline]
42 pub(crate) fn as_usize(self) -> usize {
43 self.0
44 }
45}
46
47pub struct StateRecord {
48 snapshot_id: Cell<SnapshotId>,
49 tombstone: Cell<bool>,
50 next: Cell<Option<Rc<StateRecord>>>,
51 value: RefCell<Option<Box<dyn RecordValue>>>,
52}
53
54pub(crate) trait RecordValue: Any {
55 fn clone_boxed(&self) -> Box<dyn RecordValue>;
56 fn assign_into(&self, target: &mut Option<Box<dyn RecordValue>>);
57}
58
59impl<T: Any + Clone> RecordValue for T {
60 fn clone_boxed(&self) -> Box<dyn RecordValue> {
61 Box::new(self.clone())
62 }
63
64 fn assign_into(&self, target: &mut Option<Box<dyn RecordValue>>) {
65 match target
66 .as_mut()
67 .and_then(|value| (&mut **value as &mut dyn Any).downcast_mut::<T>())
68 {
69 Some(slot) => slot.clone_from(self),
70 None => *target = Some(Box::new(self.clone())),
71 }
72 }
73}
74
75#[derive(Debug)]
76struct StateReadFailure {
77 state_id: ObjectId,
78 snapshot_id: SnapshotId,
79 fresh_snapshot_id: SnapshotId,
80 fresh_invalid: SnapshotIdSet,
81 record_chain: Vec<(SnapshotId, bool)>,
82}
83
84impl std::fmt::Display for StateReadFailure {
85 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86 write!(
87 f,
88 "Reading a state that was created after the snapshot was taken or in a snapshot that has not yet been applied\n\
89 state={:?}, snapshot_id={}, fresh_snapshot_id={}, fresh_invalid={:?}\n\
90 record_chain={:?}",
91 self.state_id,
92 self.snapshot_id,
93 self.fresh_snapshot_id,
94 self.fresh_invalid,
95 self.record_chain
96 )
97 }
98}
99
100#[derive(Debug, Clone, Copy, Eq, PartialEq)]
101pub(crate) enum StateRecordValueError {
102 Missing,
103}
104
105impl StateRecord {
106 pub(crate) fn new<T: Any + Clone>(
107 snapshot_id: SnapshotId,
108 value: T,
109 next: Option<Rc<StateRecord>>,
110 ) -> Rc<Self> {
111 Self::with_boxed(snapshot_id, Box::new(value), next)
112 }
113
114 fn with_boxed(
115 snapshot_id: SnapshotId,
116 value: Box<dyn RecordValue>,
117 next: Option<Rc<StateRecord>>,
118 ) -> Rc<Self> {
119 Rc::new(Self {
120 snapshot_id: Cell::new(snapshot_id),
121 tombstone: Cell::new(false),
122 next: Cell::new(next),
123 value: RefCell::new(Some(value)),
124 })
125 }
126
127 #[inline]
128 pub(crate) fn snapshot_id(&self) -> SnapshotId {
129 self.snapshot_id.get()
130 }
131
132 #[inline]
133 pub(crate) fn set_snapshot_id(&self, id: SnapshotId) {
134 self.snapshot_id.set(id);
135 }
136
137 #[inline]
138 pub(crate) fn next(&self) -> Option<Rc<StateRecord>> {
139 self.next.take().inspect(|record| {
140 self.next.set(Some(Rc::clone(record)));
141 })
142 }
143
144 #[inline]
145 pub(crate) fn set_next(&self, next: Option<Rc<StateRecord>>) {
146 self.next.set(next);
147 }
148
149 #[inline]
150 pub(crate) fn is_tombstone(&self) -> bool {
151 self.tombstone.get()
152 }
153
154 #[inline]
155 pub(crate) fn set_tombstone(&self, tombstone: bool) {
156 self.tombstone.set(tombstone);
157 }
158
159 #[must_use = "drop the cleared value once the record chain is consistent"]
162 pub(crate) fn clear_value(&self) -> Option<Box<dyn RecordValue>> {
163 self.value.borrow_mut().take()
164 }
165
166 pub(crate) fn tombstone_retiring_value(&self) {
169 self.set_tombstone(true);
170 if let Some(value) = self.clear_value() {
171 retire_record_value(value);
172 }
173 }
174
175 #[must_use = "drop the displaced value once the write is published"]
179 pub(crate) fn replace_value<T: Any + Clone>(&self, new_value: T) -> Option<T> {
180 let mut value = self.value.borrow_mut();
181 if let Some(slot) = value
182 .as_mut()
183 .and_then(|current| (&mut **current as &mut dyn Any).downcast_mut::<T>())
184 {
185 return Some(std::mem::replace(slot, new_value));
186 }
187 let placeholder = value.replace(Box::new(new_value));
188 drop(value);
189 drop(placeholder);
190 None
191 }
192
193 fn cloned_value(&self) -> Option<Box<dyn RecordValue>> {
194 self.value
195 .borrow()
196 .as_ref()
197 .map(|value| (**value).clone_boxed())
198 }
199
200 fn cloned_value_of(&self, expected: TypeId) -> Option<Box<dyn RecordValue>> {
201 self.value
202 .borrow()
203 .as_ref()
204 .filter(|value| (&***value as &dyn Any).type_id() == expected)
205 .map(|value| (**value).clone_boxed())
206 }
207
208 fn set_boxed_value(&self, value: Box<dyn RecordValue>) {
209 let displaced = self.value.borrow_mut().replace(value);
210 if let Some(displaced) = displaced {
211 retire_record_value(displaced);
212 }
213 }
214
215 pub(crate) fn with_value<T: Any, R>(&self, f: impl FnOnce(&T) -> R) -> R {
216 self.try_with_value(f)
217 .unwrap_or_else(|| panic!("StateRecord value missing or wrong type"))
218 }
219
220 pub(crate) fn try_with_value<T: Any, R>(&self, f: impl FnOnce(&T) -> R) -> Option<R> {
221 let guard = self.value.borrow();
222 let value = guard
223 .as_ref()
224 .and_then(|boxed| (&**boxed as &dyn Any).downcast_ref::<T>())?;
225 Some(f(value))
226 }
227
228 #[cfg(test)]
229 pub(crate) fn clear_for_reuse(&self) {
230 drop(self.clear_value());
231 }
232
233 pub(crate) fn assign_value(&self, source: &StateRecord) -> Result<(), StateRecordValueError> {
234 if std::ptr::eq(self, source) {
235 return match self.value.borrow().is_some() {
236 true => Ok(()),
237 false => Err(StateRecordValueError::Missing),
238 };
239 }
240 let source_value = source.value.borrow();
241 let value = source_value
242 .as_ref()
243 .ok_or(StateRecordValueError::Missing)?;
244 (**value).assign_into(&mut self.value.borrow_mut());
245 Ok(())
246 }
247}
248
249impl Drop for StateRecord {
250 fn drop(&mut self) {
251 let mut next = self.next.take();
252 while let Some(node) = next {
253 match Rc::try_unwrap(node) {
254 Ok(record) => {
255 next = record.next.take();
256 }
257 Err(_) => {
258 break;
259 }
260 }
261 }
262 }
263}
264
265struct CurrentRecord {
266 head: RefCell<Rc<StateRecord>>,
267}
268
269impl CurrentRecord {
270 fn new(head: Rc<StateRecord>) -> Self {
271 Self {
272 head: RefCell::new(head),
273 }
274 }
275
276 fn clone_head(&self) -> Rc<StateRecord> {
277 self.head.borrow().clone()
278 }
279
280 fn replace(&self, new_head: Rc<StateRecord>) {
281 *self.head.borrow_mut() = new_head;
282 }
283
284 fn prepend(&self, record: Rc<StateRecord>) {
285 let current_head = self.clone_head();
286 record.set_next(Some(current_head));
287 self.replace(record);
288 }
289}
290
291#[inline]
292fn record_is_valid_for(
293 record: &Rc<StateRecord>,
294 snapshot_id: SnapshotId,
295 invalid: &SnapshotIdSet,
296) -> bool {
297 if record.is_tombstone() {
298 return false;
299 }
300
301 let candidate = record.snapshot_id();
302 if candidate == INVALID_SNAPSHOT_ID || candidate > snapshot_id {
303 return false;
304 }
305
306 candidate == snapshot_id || !invalid.get(candidate)
307}
308
309pub(crate) fn readable_record_for(
310 head: &Rc<StateRecord>,
311 snapshot_id: SnapshotId,
312 invalid: &SnapshotIdSet,
313) -> Option<Rc<StateRecord>> {
314 let mut best: Option<Rc<StateRecord>> = None;
315 let mut cursor = Some(Rc::clone(head));
316
317 while let Some(record) = cursor {
318 cursor = record.next();
319 if record_is_valid_for(&record, snapshot_id, invalid)
320 && best
321 .as_ref()
322 .is_none_or(|current| current.snapshot_id() < record.snapshot_id())
323 {
324 best = Some(record);
325 }
326 }
327
328 best
329}
330
331pub(crate) fn used_locked(head: &Rc<StateRecord>) -> Option<Rc<StateRecord>> {
332 let mut current = Some(Rc::clone(head));
333 let mut valid_record: Option<Rc<StateRecord>> = None;
334
335 let reuse_limit = lowest_pinned_snapshot().map_or_else(
336 || allocate_record_id().saturating_sub(1),
337 |lowest| lowest.saturating_sub(1),
338 );
339
340 let invalid = SnapshotIdSet::EMPTY;
341
342 while let Some(record) = current {
343 let current_id = record.snapshot_id();
344
345 if current_id == PREEXISTING_SNAPSHOT_ID {
346 current = record.next();
347 continue;
348 }
349
350 if current_id == INVALID_SNAPSHOT_ID {
351 return Some(record);
352 }
353
354 if record.is_tombstone() && current_id < reuse_limit {
355 return Some(record);
356 }
357
358 if record_is_valid_for(&record, reuse_limit, &invalid) {
359 if let Some(ref existing) = valid_record {
360 return Some(if current_id < existing.snapshot_id() {
361 record
362 } else {
363 Rc::clone(existing)
364 });
365 } else {
366 valid_record = Some(record.clone());
367 }
368 }
369
370 current = record.next();
371 }
372
373 None
374}
375
376pub(crate) fn new_overwritable_record_locked(state: &dyn StateObject) -> Rc<StateRecord> {
377 let state_head = state.first_record();
378
379 if let Some(reusable) = used_locked(&state_head) {
380 reusable.set_snapshot_id(SNAPSHOT_ID_MAX);
381 return reusable;
382 }
383
384 let new_record = StateRecord::new(SNAPSHOT_ID_MAX, (), None);
385
386 state.prepend_state_record(Rc::clone(&new_record));
387
388 new_record
389}
390
391pub(crate) fn new_overwritable_record_as_head_locked(state: &dyn StateObject) -> Rc<StateRecord> {
392 let head = state.first_record();
393
394 if let Some(reusable) = used_locked(&head) {
395 reusable.set_snapshot_id(SNAPSHOT_ID_MAX);
396
397 if !Rc::ptr_eq(&head, &reusable) {
398 let mut cursor = Some(Rc::clone(&head));
399 let mut unlinked = false;
400
401 while let Some(node) = cursor {
402 let next = node.next();
403 if let Some(next_record) = next {
404 if Rc::ptr_eq(&next_record, &reusable) {
405 node.set_next(reusable.next());
406 unlinked = true;
407 break;
408 }
409 cursor = Some(next_record);
410 } else {
411 break;
412 }
413 }
414
415 if !unlinked {
416 debug_assert!(
417 false,
418 "new_overwritable_record_as_head_locked: reusable record not found in chain"
419 );
420 let new_record = StateRecord::new(SNAPSHOT_ID_MAX, (), None);
421 state.prepend_state_record(Rc::clone(&new_record));
422 return new_record;
423 }
424
425 state.prepend_state_record(Rc::clone(&reusable));
426 }
427
428 return reusable;
429 }
430
431 let new_record = StateRecord::new(SNAPSHOT_ID_MAX, (), None);
432 state.prepend_state_record(Rc::clone(&new_record));
433 new_record
434}
435
436#[cold]
437fn log_merge_value_missing(which: &str, state: ObjectId, record: &StateRecord) {
438 log::error!(
439 "SnapshotMutableState::merge_records {which} record value missing or wrong type (state {state:?}, {which}_id={})",
440 record.snapshot_id()
441 );
442}
443
444fn install_copy_as_head(
445 state: &dyn StateObject,
446 source: &StateRecord,
447 expected: TypeId,
448) -> Option<SnapshotId> {
449 let value = source.cloned_value_of(expected)?;
450 let new_id = allocate_record_id();
451 let record = new_overwritable_record_as_head_locked(state);
452 record.set_boxed_value(value);
453 record.set_tombstone(false);
454 record.set_snapshot_id(new_id);
455 advance_global_snapshot(new_id);
456 Some(new_id)
457}
458
459fn promote_record_locked(
460 state: &dyn StateObject,
461 child_id: SnapshotId,
462 expected: TypeId,
463) -> Result<(), &'static str> {
464 let mut cursor = Some(state.first_record());
465 while let Some(record) = cursor {
466 if record.snapshot_id() == child_id {
467 if install_copy_as_head(state, &record, expected).is_none() {
468 log::error!(
469 "SnapshotMutableState::promote_record child record value missing or wrong type (state {:?}, child_id={})",
470 state.object_id(),
471 child_id
472 );
473 return Err("child record value missing or wrong type");
474 }
475 return Ok(());
476 }
477 cursor = record.next();
478 }
479 log::error!(
480 "SnapshotMutableState::promote_record missing child record (state {:?}, child_id={})",
481 state.object_id(),
482 child_id
483 );
484 Err("missing child record")
485}
486
487fn commit_merged_record_locked(
488 state: &dyn StateObject,
489 merged: &StateRecord,
490 expected: TypeId,
491) -> Result<SnapshotId, &'static str> {
492 install_copy_as_head(state, merged, expected).ok_or_else(|| {
493 log::error!(
494 "SnapshotMutableState::commit_merged_record merged record value missing or wrong type (state {:?}, merged_id={})",
495 state.object_id(),
496 merged.snapshot_id()
497 );
498 "merged record value missing or wrong type"
499 })
500}
501
502std::thread_local! {
503 static RETIRED_RECORD_VALUES: RefCell<Vec<Box<dyn RecordValue>>> =
506 const { RefCell::new(Vec::new()) };
507 static RETIRE_DEPTH: Cell<usize> = const { Cell::new(0) };
508}
509
510pub(crate) fn retire_record_value(value: Box<dyn RecordValue>) {
514 if RETIRE_DEPTH.with(Cell::get) == 0 {
515 drop(value);
516 } else {
517 RETIRED_RECORD_VALUES.with(|retired| retired.borrow_mut().push(value));
518 }
519}
520
521pub(crate) struct RetiredValuesScope(());
524
525impl RetiredValuesScope {
526 pub(crate) fn enter() -> Self {
527 RETIRE_DEPTH.with(|depth| depth.set(depth.get() + 1));
528 Self(())
529 }
530}
531
532impl Drop for RetiredValuesScope {
533 fn drop(&mut self) {
534 let outermost = RETIRE_DEPTH.with(|depth| {
535 depth.set(depth.get() - 1);
536 depth.get() == 0
537 });
538 if outermost {
539 let retired =
540 RETIRED_RECORD_VALUES.with(|retired| std::mem::take(&mut *retired.borrow_mut()));
541 drop(retired);
542 }
543 }
544}
545
546pub(crate) fn overwrite_unused_records_locked(state: &dyn StateObject) -> bool {
550 let mut current = Some(state.first_record());
551 let mut valid_record: Option<Rc<StateRecord>> = None;
552
553 let reuse_limit =
554 lowest_pinned_snapshot().unwrap_or_else(crate::snapshot_v2::peek_next_snapshot_id);
555
556 let mut retained_records = 0;
557
558 while let Some(record) = current {
559 let current_id = record.snapshot_id();
560
561 if current_id == INVALID_SNAPSHOT_ID {
562 } else if current_id < reuse_limit {
563 match valid_record.as_ref() {
564 None => {
565 valid_record = Some(Rc::clone(&record));
566 retained_records += 1;
567 }
568 Some(valid) => {
569 let record_to_overwrite = if current_id < valid.snapshot_id() {
570 Rc::clone(&record)
571 } else {
572 let to_overwrite = Rc::clone(valid);
573 valid_record = Some(Rc::clone(&record));
574 to_overwrite
575 };
576 record_to_overwrite.set_snapshot_id(INVALID_SNAPSHOT_ID);
577 if let Some(value) = record_to_overwrite.clear_value() {
578 retire_record_value(value);
579 }
580 }
581 }
582 } else {
583 retained_records += 1;
584 }
585
586 current = record.next();
587 }
588
589 retained_records > 1
590}
591
592fn active_snapshot() -> AnySnapshot {
593 current_snapshot().unwrap_or_else(|| AnySnapshot::Global(GlobalSnapshot::get_or_create()))
594}
595
596pub(crate) trait MutationPolicy<T>: Send + Sync {
597 fn equivalent(&self, a: &T, b: &T) -> bool;
598 fn merge(&self, _previous: &T, _current: &T, _applied: &T) -> Option<T> {
599 None
600 }
601}
602
603pub(crate) struct NeverEqual;
604
605impl<T> MutationPolicy<T> for NeverEqual {
606 fn equivalent(&self, _a: &T, _b: &T) -> bool {
607 false
608 }
609}
610
611pub(crate) struct StructuralEqual;
612
613impl<T: PartialEq> MutationPolicy<T> for StructuralEqual {
614 fn equivalent(&self, a: &T, b: &T) -> bool {
615 a == b
616 }
617}
618
619pub trait StateObject: Any {
620 fn object_id(&self) -> ObjectId;
621 fn first_record(&self) -> Rc<StateRecord>;
622 fn try_readable_record(
623 &self,
624 snapshot_id: SnapshotId,
625 invalid: &SnapshotIdSet,
626 ) -> Option<Rc<StateRecord>>;
627 fn readable_record(&self, snapshot_id: SnapshotId, invalid: &SnapshotIdSet) -> Rc<StateRecord>;
628
629 fn prepend_state_record(&self, record: Rc<StateRecord>);
630
631 fn merge_records(
632 &self,
633 _previous: Rc<StateRecord>,
634 _current: Rc<StateRecord>,
635 _applied: Rc<StateRecord>,
636 ) -> Option<Rc<StateRecord>> {
637 None
638 }
639
640 fn commit_merged_record(&self, _merged: Rc<StateRecord>) -> Result<SnapshotId, &'static str> {
641 Err("StateObject does not support merged record commits")
642 }
643 fn promote_record(&self, child_id: SnapshotId) -> Result<(), &'static str>;
644
645 fn overwrite_unused_records(&self) -> bool {
646 false
647 }
648
649 fn observation_lease(&self) -> Option<Rc<dyn Any>> {
650 None
651 }
652
653 fn as_any(&self) -> &dyn Any;
654}
655
656pub(crate) struct SnapshotMutableState<T> {
657 head: CurrentRecord,
658 policy: Arc<dyn MutationPolicy<T>>,
659 id: ObjectId,
660 weak_self: Mutex<Option<Weak<Self>>>,
661 apply_observers: ApplyObservers,
662 read_observation_lease: Rc<()>,
663 scope_observation_count: Cell<usize>,
664 subscriber_callbacks: RefCell<Vec<Rc<dyn Fn()>>>,
665}
666
667#[inline(always)]
668fn assert_record_chain(
669 head: &CurrentRecord,
670 id: ObjectId,
671 caller: &str,
672 snapshot_context: Option<SnapshotId>,
673) {
674 if should_check_chain_integrity() {
675 check_chain_integrity(&head.clone_head(), id, caller, snapshot_context);
676 }
677}
678
679enum Merge<'a, T> {
680 KeepCurrent,
681 Value(Option<T>),
682 Missing(&'static str, &'a Rc<StateRecord>),
683}
684
685type ApplyObservers = Mutex<Vec<Box<dyn Fn() + 'static>>>;
686
687fn lock_apply_observers(
688 observers: &ApplyObservers,
689) -> MutexGuard<'_, Vec<Box<dyn Fn() + 'static>>> {
690 observers.lock().unwrap_or_else(PoisonError::into_inner)
691}
692
693fn notify_applied(observers: &ApplyObservers) {
694 for observer in lock_apply_observers(observers).iter() {
695 observer();
696 }
697}
698
699fn finish_apply(
700 observers: &ApplyObservers,
701 head: &CurrentRecord,
702 id: ObjectId,
703 caller: &str,
704 snapshot_id: SnapshotId,
705) {
706 notify_applied(observers);
707 assert_record_chain(head, id, caller, Some(snapshot_id));
708}
709
710struct WriteTarget<'a> {
713 head: &'a CurrentRecord,
714 id: ObjectId,
715 state: &'a dyn StateObject,
716}
717
718struct GlobalWrite {
719 record: Rc<StateRecord>,
720 new_id: SnapshotId,
721 written: Option<Arc<dyn StateObject>>,
722}
723
724impl WriteTarget<'_> {
725 fn assert_chain_integrity(&self, caller: &str, snapshot_context: Option<SnapshotId>) {
726 assert_record_chain(self.head, self.id, caller, snapshot_context);
727 }
728
729 fn begin_global_write(
730 &self,
731 snapshot: &AnySnapshot,
732 global: &GlobalSnapshot,
733 snapshot_id: SnapshotId,
734 written: Option<Arc<dyn StateObject>>,
735 ) -> GlobalWrite {
736 assert!(
737 !global.has_pending_children(),
738 "SnapshotMutableState::set attempted global write while pending children {:?} exist (state {:?}, snapshot_id={})",
739 global.pending_children(),
740 self.id,
741 snapshot_id
742 );
743 if let Some(state) = &written {
744 snapshot.record_write(Arc::clone(state));
745 }
746 mark_update_write(self.id);
747 let new_id = allocate_record_id();
748 let record = new_overwritable_record_as_head_locked(self.state);
749 GlobalWrite {
750 record,
751 new_id,
752 written,
753 }
754 }
755
756 fn finish_global_write(
757 &self,
758 global: &GlobalSnapshot,
759 write: GlobalWrite,
760 snapshot_id: SnapshotId,
761 ) {
762 write.record.set_snapshot_id(write.new_id);
765 write.record.set_tombstone(false);
766 advance_global_snapshot(write.new_id);
767 self.assert_chain_integrity("set(global-push)", Some(snapshot_id));
768
769 let mut cleared: SmallVec<[Box<dyn RecordValue>; 2]> = SmallVec::new();
770 if !global.has_pending_children() {
771 let mut cursor = write.record.next();
772 while let Some(node) = cursor {
773 if !node.is_tombstone() && node.snapshot_id() != PREEXISTING_SNAPSHOT_ID {
774 cleared.extend(node.clear_value());
775 node.set_tombstone(true);
776 }
777 cursor = node.next();
778 }
779 self.assert_chain_integrity("set(global-tombstone)", Some(snapshot_id));
780 }
781
782 if let Some(modified) = write.written.as_ref() {
783 crate::snapshot_v2::notify_apply_observers(
784 std::slice::from_ref(modified),
785 write.new_id,
786 );
787 }
788 drop(cleared);
789 }
790
791 fn begin_child_write(
792 &self,
793 snapshot: &AnySnapshot,
794 snapshot_id: SnapshotId,
795 invalid: &SnapshotIdSet,
796 written: Option<Arc<dyn StateObject>>,
797 ) -> Rc<StateRecord> {
798 if let Some(state) = written {
799 snapshot.record_write(state);
800 }
801 mark_update_write(self.id);
802 self.writable_record(snapshot_id, invalid)
803 }
804
805 fn writable_record(&self, snapshot_id: SnapshotId, invalid: &SnapshotIdSet) -> Rc<StateRecord> {
806 let Some(readable) = readable_record_for(&self.head.clone_head(), snapshot_id, invalid)
807 else {
808 let current_head = self.head.clone_head();
809 let refreshed = readable_record_for(¤t_head, snapshot_id, invalid);
810 let source = refreshed.unwrap_or_else(|| current_head.clone());
811
812 let cloned_value = source
813 .cloned_value()
814 .unwrap_or_else(|| panic!("StateRecord value missing or wrong type"));
815 let new_head = StateRecord::with_boxed(snapshot_id, cloned_value, Some(current_head));
816 self.head.replace(new_head.clone());
817 self.assert_chain_integrity("writable_record(recover)", Some(snapshot_id));
818 return new_head;
819 };
820
821 if readable.snapshot_id() == snapshot_id {
822 return readable;
823 }
824
825 let refreshed = {
826 let current_head = self.head.clone_head();
827 let refreshed = readable_record_for(¤t_head, snapshot_id, invalid).unwrap_or_else(
828 || {
829 panic!(
830 "SnapshotMutableState::writable_record failed to locate refreshed readable record (state {:?}, snapshot_id={}, invalid={:?})",
831 self.id, snapshot_id, invalid
832 )
833 },
834 );
835
836 if refreshed.snapshot_id() == snapshot_id {
837 return refreshed;
838 }
839
840 Rc::clone(&refreshed)
841 };
842
843 let overwritable = new_overwritable_record_locked(self.state);
844 if let Err(error) = overwritable.assign_value(&refreshed) {
845 log::error!(
846 "snapshot writable record could not copy refreshed value for state {:?}: {:?}",
847 self.id,
848 error
849 );
850 }
851 overwritable.set_snapshot_id(snapshot_id);
852 overwritable.set_tombstone(false);
853
854 self.assert_chain_integrity("writable_record(reuse)", Some(snapshot_id));
855
856 overwritable
857 }
858}
859
860fn check_chain_integrity(
861 head: &Rc<StateRecord>,
862 id: ObjectId,
863 caller: &str,
864 snapshot_context: Option<SnapshotId>,
865) {
866 let mut cursor = Some(Rc::clone(head));
867 let mut seen: HashSet<usize> = HashSet::default();
868 let mut ids = Vec::new();
869
870 while let Some(record) = cursor {
871 let addr = Rc::as_ptr(&record) as usize;
872 assert!(
873 seen.insert(addr),
874 "SnapshotMutableState::{caller} detected duplicate/cycle at record {:p} for state {id:?} (snapshot_context={snapshot_context:?}, chain_ids={ids:?})",
875 Rc::as_ptr(&record),
876 );
877 ids.push(record.snapshot_id());
878 cursor = record.next();
879 }
880
881 assert!(
882 !ids.is_empty(),
883 "SnapshotMutableState::{caller} finished integrity scan with empty id list for state {id:?} (snapshot_context={snapshot_context:?})"
884 );
885}
886
887fn should_check_chain_integrity() -> bool {
888 #[cfg(debug_assertions)]
889 {
890 true
891 }
892
893 #[cfg(not(debug_assertions))]
894 {
895 crate::env_flag!("CRANPOSE_ASSERT_STATE_CHAIN")
896 }
897}
898
899impl<T: Clone + 'static> SnapshotMutableState<T> {
900 fn record_chain_debug(&self) -> Vec<(SnapshotId, bool)> {
901 let mut chain_ids = Vec::new();
902 let mut cursor = Some(self.first_record());
903 while let Some(record) = cursor {
904 chain_ids.push((record.snapshot_id(), record.is_tombstone()));
905 cursor = record.next();
906 }
907 chain_ids
908 }
909
910 fn readable_record_for_active_snapshot(&self) -> Result<Rc<StateRecord>, StateReadFailure> {
911 let snapshot = active_snapshot();
912 snapshot.record_read(self);
913
914 let snapshot_id = snapshot.snapshot_id();
915 if let Some(record) =
916 snapshot.with_invalid(|invalid| self.readable_for(snapshot_id, invalid))
917 {
918 return Ok(record);
919 }
920
921 let fresh_snapshot = active_snapshot();
922 let fresh_id = fresh_snapshot.snapshot_id();
923 let fresh_invalid = fresh_snapshot.invalid();
924
925 if let Some(record) = self.readable_for(fresh_id, &fresh_invalid) {
926 return Ok(record);
927 }
928
929 let global = GlobalSnapshot::get_or_create();
930 let global_id = global.snapshot_id();
931 let global_invalid = global.invalid();
932
933 if let Some(record) = self.readable_for(global_id, &global_invalid) {
934 return Ok(record);
935 }
936
937 Err(StateReadFailure {
938 state_id: self.id,
939 snapshot_id,
940 fresh_snapshot_id: fresh_id,
941 fresh_invalid,
942 record_chain: self.record_chain_debug(),
943 })
944 }
945
946 fn readable_for(
947 &self,
948 snapshot_id: SnapshotId,
949 invalid: &SnapshotIdSet,
950 ) -> Option<Rc<StateRecord>> {
951 let head = self.first_record();
952 readable_record_for(&head, snapshot_id, invalid)
953 }
954
955 fn is_equivalent_to(&self, readable: Option<Rc<StateRecord>>, new_value: &T) -> bool {
956 readable.is_some_and(|record| {
957 record.with_value(|current: &T| self.policy.equivalent(current, new_value))
958 })
959 }
960
961 pub(crate) fn new_in_arc(initial: T, policy: Arc<dyn MutationPolicy<T>>) -> Arc<Self> {
962 let snapshot = active_snapshot();
963 let snapshot_id = snapshot.snapshot_id();
964
965 let tail = StateRecord::new(PREEXISTING_SNAPSHOT_ID, initial.clone(), None);
966 let head = StateRecord::new(snapshot_id, initial, Some(tail));
967
968 let mut state = Arc::new(Self {
969 head: CurrentRecord::new(head),
970 policy,
971 id: ObjectId::default(),
972 weak_self: Mutex::new(None),
973 apply_observers: Mutex::new(Vec::new()),
974 read_observation_lease: Rc::new(()),
975 scope_observation_count: Cell::new(0),
976 subscriber_callbacks: RefCell::new(Vec::new()),
977 });
978
979 let id = ObjectId::new(&state);
980 if let Some(state_inner) = Arc::get_mut(&mut state) {
981 state_inner.id = id;
982 }
983
984 *state.lock_weak_self() = Some(Arc::downgrade(&state));
985
986 state
987 }
988
989 pub(crate) fn add_apply_observer(&self, observer: Box<dyn Fn() + 'static>) {
990 self.lock_apply_observers().push(observer);
991 }
992
993 fn acquire_observation_lease(&self) -> Option<Rc<dyn Any>> {
994 let was_empty = !self.has_subscribers();
995 let lease = Rc::clone(&self.read_observation_lease);
996 if was_empty {
997 notify_subscriber_callbacks(&self.subscriber_callbacks);
998 }
999 Some(lease)
1000 }
1001
1002 fn add_scope_observer(&self) -> bool {
1003 let was_empty = !self.has_subscribers();
1004 let count = self
1005 .scope_observation_count
1006 .get()
1007 .checked_add(1)
1008 .expect("state scope observation count overflow");
1009 self.scope_observation_count.set(count);
1010 was_empty
1011 }
1012
1013 fn remove_scope_observers(&self, count: usize) {
1014 if count == 0 {
1015 return;
1016 }
1017 let remaining = self
1018 .scope_observation_count
1019 .get()
1020 .checked_sub(count)
1021 .expect("state scope observation count underflow");
1022 self.scope_observation_count.set(remaining);
1023 }
1024
1025 fn has_subscribers(&self) -> bool {
1026 Rc::strong_count(&self.read_observation_lease) > 1 || self.scope_observation_count.get() > 0
1027 }
1028
1029 fn subscriber_callback(&self, callback: Rc<dyn Fn()>, notify: bool) {
1030 self.subscriber_callbacks
1031 .borrow_mut()
1032 .push(Rc::clone(&callback));
1033 if notify {
1034 callback();
1035 }
1036 }
1037
1038 fn notify_subscribers(&self) {
1039 notify_subscriber_callbacks(&self.subscriber_callbacks);
1040 }
1041
1042 fn lock_weak_self(&self) -> MutexGuard<'_, Option<Weak<Self>>> {
1043 self.weak_self
1044 .lock()
1045 .unwrap_or_else(PoisonError::into_inner)
1046 }
1047
1048 fn lock_apply_observers(&self) -> MutexGuard<'_, Vec<Box<dyn Fn() + 'static>>> {
1049 lock_apply_observers(&self.apply_observers)
1050 }
1051
1052 fn finish_apply(&self, caller: &str, snapshot_id: SnapshotId) {
1053 finish_apply(
1054 &self.apply_observers,
1055 &self.head,
1056 self.id,
1057 caller,
1058 snapshot_id,
1059 );
1060 }
1061
1062 fn upgrade_self(&self) -> Option<Arc<Self>> {
1063 self.lock_weak_self().as_ref().and_then(Weak::upgrade)
1064 }
1065
1066 fn written_state(&self) -> Option<Arc<dyn StateObject>> {
1067 self.upgrade_self()
1068 .map(|state| -> Arc<dyn StateObject> { state })
1069 }
1070
1071 #[inline]
1072 pub(crate) fn id(&self) -> ObjectId {
1073 self.id
1074 }
1075
1076 pub(crate) fn try_with_value<R>(&self, f: impl FnOnce(&T) -> R) -> Option<R> {
1077 let record = self.readable_record_for_active_snapshot().ok()?;
1078 record.try_with_value(f)
1079 }
1080
1081 pub(crate) fn try_get(&self) -> Option<T> {
1082 self.try_with_value(Clone::clone)
1083 }
1084
1085 pub(crate) fn with_value<R>(&self, f: impl FnOnce(&T) -> R) -> R {
1086 let record = self
1087 .readable_record_for_active_snapshot()
1088 .unwrap_or_else(|failure| panic!("{failure}"));
1089 record.with_value(f)
1090 }
1091
1092 pub(crate) fn get(&self) -> T {
1093 self.with_value(Clone::clone)
1094 }
1095
1096 pub(crate) fn set(&self, new_value: T) -> bool {
1097 #[cfg(debug_assertions)]
1098 {
1099 let in_handler = crate::in_event_handler();
1100 let in_snapshot = crate::in_applied_snapshot();
1101 if in_handler && !in_snapshot {
1102 log::warn!(
1103 target: "cranpose::state",
1104 "State modified in event handler without run_in_mutable_snapshot; \
1105 this can make updates invisible to other contexts. Wrap the handler \
1106 in run_in_mutable_snapshot() or dispatch_ui_event(). State: {:?}",
1107 self.id
1108 );
1109 }
1110 }
1111
1112 let snapshot = active_snapshot();
1113 let snapshot_id = snapshot.snapshot_id();
1114 let target = WriteTarget {
1115 head: &self.head,
1116 id: self.id,
1117 state: self,
1118 };
1119
1120 match &snapshot {
1121 AnySnapshot::Global(global) => {
1122 let readable =
1123 snapshot.with_invalid(|invalid| self.readable_for(snapshot_id, invalid));
1124 if self.is_equivalent_to(readable, &new_value) {
1125 return false;
1126 }
1127 let write =
1128 target.begin_global_write(&snapshot, global, snapshot_id, self.written_state());
1129 let displaced = write.record.replace_value(new_value);
1130 target.finish_global_write(global, write, snapshot_id);
1131 drop(displaced);
1132 }
1133 AnySnapshot::Mutable(_)
1134 | AnySnapshot::NestedMutable(_)
1135 | AnySnapshot::TransparentMutable(_) => {
1136 let invalid = snapshot.invalid();
1137 if self.is_equivalent_to(self.readable_for(snapshot_id, &invalid), &new_value) {
1138 return false;
1139 }
1140 let record = target.begin_child_write(
1141 &snapshot,
1142 snapshot_id,
1143 &invalid,
1144 self.written_state(),
1145 );
1146 let displaced = record.replace_value(new_value);
1147 target.assert_chain_integrity("set(child-writable)", Some(snapshot_id));
1148 drop(displaced);
1149 }
1150 AnySnapshot::Readonly(_)
1151 | AnySnapshot::NestedReadonly(_)
1152 | AnySnapshot::TransparentReadonly(_) => {
1153 panic!("Cannot write to a read-only snapshot");
1154 }
1155 }
1156
1157 true
1158 }
1159}
1160
1161thread_local! {
1162 static ACTIVE_UPDATES: RefCell<HashSet<ObjectId>> = RefCell::new(HashSet::default());
1163 static PENDING_WRITES: RefCell<HashSet<ObjectId>> = RefCell::new(HashSet::default());
1164}
1165
1166pub(crate) struct UpdateScope {
1167 id: ObjectId,
1168 finished: bool,
1169}
1170
1171impl UpdateScope {
1172 pub(crate) fn new(id: ObjectId) -> Self {
1173 ACTIVE_UPDATES.with(|active| {
1174 active.borrow_mut().insert(id);
1175 });
1176 PENDING_WRITES.with(|pending| {
1177 pending.borrow_mut().remove(&id);
1178 });
1179 Self {
1180 id,
1181 finished: false,
1182 }
1183 }
1184
1185 pub(crate) fn finish(mut self) -> bool {
1186 self.finished = true;
1187 ACTIVE_UPDATES.with(|active| {
1188 active.borrow_mut().remove(&self.id);
1189 });
1190 PENDING_WRITES.with(|pending| pending.borrow_mut().remove(&self.id))
1191 }
1192}
1193
1194impl Drop for UpdateScope {
1195 fn drop(&mut self) {
1196 if self.finished {
1197 return;
1198 }
1199 ACTIVE_UPDATES.with(|active| {
1200 active.borrow_mut().remove(&self.id);
1201 });
1202 PENDING_WRITES.with(|pending| {
1203 pending.borrow_mut().remove(&self.id);
1204 });
1205 }
1206}
1207
1208fn mark_update_write(id: ObjectId) {
1209 ACTIVE_UPDATES.with(|active| {
1210 if active.borrow().contains(&id) {
1211 PENDING_WRITES.with(|pending| {
1212 pending.borrow_mut().insert(id);
1213 });
1214 }
1215 });
1216}
1217
1218impl<T: Clone + 'static> SnapshotMutableState<T> {
1219 fn try_readable_record(
1220 &self,
1221 snapshot_id: SnapshotId,
1222 invalid: &SnapshotIdSet,
1223 ) -> Option<Rc<StateRecord>> {
1224 self.readable_for(snapshot_id, invalid)
1225 }
1226}
1227
1228impl<T: Clone + 'static> StateObject for SnapshotMutableState<T> {
1229 fn object_id(&self) -> ObjectId {
1230 self.id
1231 }
1232
1233 fn first_record(&self) -> Rc<StateRecord> {
1234 self.head.clone_head()
1235 }
1236
1237 fn try_readable_record(
1238 &self,
1239 snapshot_id: SnapshotId,
1240 invalid: &SnapshotIdSet,
1241 ) -> Option<Rc<StateRecord>> {
1242 self.try_readable_record(snapshot_id, invalid)
1243 }
1244
1245 fn readable_record(&self, snapshot_id: SnapshotId, invalid: &SnapshotIdSet) -> Rc<StateRecord> {
1246 self.try_readable_record(snapshot_id, invalid)
1247 .unwrap_or_else(|| {
1248 panic!(
1249 "SnapshotMutableState::readable_record returned null (state={:?}, snapshot_id={})",
1250 self.id, snapshot_id
1251 )
1252 })
1253 }
1254
1255 fn prepend_state_record(&self, record: Rc<StateRecord>) {
1256 self.head.prepend(record);
1257 }
1258
1259 fn observation_lease(&self) -> Option<Rc<dyn Any>> {
1260 self.acquire_observation_lease()
1261 }
1262
1263 fn merge_records(
1264 &self,
1265 previous: Rc<StateRecord>,
1266 current: Rc<StateRecord>,
1267 applied: Rc<StateRecord>,
1268 ) -> Option<Rc<StateRecord>> {
1269 let outcome = current
1270 .try_with_value(|current_value: &T| {
1271 applied
1272 .try_with_value(|applied_value: &T| {
1273 if self.policy.equivalent(current_value, applied_value) {
1274 return Merge::KeepCurrent;
1275 }
1276 previous
1277 .try_with_value(|previous_value: &T| {
1278 Merge::Value(self.policy.merge(
1279 previous_value,
1280 current_value,
1281 applied_value,
1282 ))
1283 })
1284 .unwrap_or(Merge::Missing("previous", &previous))
1285 })
1286 .unwrap_or(Merge::Missing("applied", &applied))
1287 })
1288 .unwrap_or(Merge::Missing("current", ¤t));
1289 match outcome {
1290 Merge::KeepCurrent => Some(current),
1291 Merge::Value(merged) => {
1292 merged.map(|value| StateRecord::new(applied.snapshot_id(), value, None))
1293 }
1294 Merge::Missing(which, record) => {
1295 log_merge_value_missing(which, self.id, record);
1296 None
1297 }
1298 }
1299 }
1300
1301 fn promote_record(&self, child_id: SnapshotId) -> Result<(), &'static str> {
1302 promote_record_locked(self, child_id, TypeId::of::<T>())?;
1303 self.finish_apply("promote_record", child_id);
1304 Ok(())
1305 }
1306
1307 fn commit_merged_record(&self, merged: Rc<StateRecord>) -> Result<SnapshotId, &'static str> {
1308 let new_id = commit_merged_record_locked(self, &merged, TypeId::of::<T>())?;
1309 self.finish_apply("commit_merged_record", new_id);
1310 Ok(new_id)
1311 }
1312
1313 fn overwrite_unused_records(&self) -> bool {
1314 overwrite_unused_records_locked(self)
1315 }
1316
1317 fn as_any(&self) -> &dyn Any {
1318 self
1319 }
1320}
1321
1322pub(crate) struct MutableStateInner<T: Clone + 'static> {
1323 pub(crate) state: Arc<SnapshotMutableState<T>>,
1324 pub(crate) watchers: RefCell<HashMap<ScopeId, RcWeak<RecomposeScopeInner>>>,
1325 runtime: RuntimeHandle,
1326 state_id: Cell<Option<StateId>>,
1327}
1328
1329fn notify_subscriber_callbacks(callbacks: &RefCell<Vec<Rc<dyn Fn()>>>) {
1330 let registered = callbacks.borrow().len();
1331 for index in 0..registered {
1332 let callback = callbacks.borrow().get(index).map(Rc::clone);
1333 if let Some(callback) = callback {
1334 callback();
1335 }
1336 }
1337}
1338
1339fn shrink_watchers_if_sparse(watchers: &mut HashMap<ScopeId, RcWeak<RecomposeScopeInner>>) {
1340 let len = watchers.len();
1341 let capacity = watchers.capacity();
1342 if capacity > len.saturating_mul(4).max(32) {
1343 watchers.shrink_to_fit();
1344 }
1345}
1346
1347impl<T: Clone + 'static> MutableStateInner<T> {
1348 pub(crate) fn new_with_policy(
1349 value: T,
1350 runtime: RuntimeHandle,
1351 policy: Arc<dyn MutationPolicy<T>>,
1352 ) -> Self {
1353 Self {
1354 state: SnapshotMutableState::new_in_arc(value, policy),
1355 watchers: RefCell::new(HashMap::default()),
1356 runtime,
1357 state_id: Cell::new(None),
1358 }
1359 }
1360
1361 pub(crate) fn install_snapshot_observer(&self, state_id: StateId) {
1362 self.state_id.set(Some(state_id));
1363 let runtime_handle = self.runtime.clone();
1364 self.state.add_apply_observer(Box::new(move || {
1365 let runtime = runtime_handle.clone();
1366 runtime_handle.enqueue_ui_task(Box::new(move || {
1367 runtime.with_state_arena(|arena| {
1368 let _ = arena.with_typed_opt::<T, _>(state_id, |inner| {
1369 inner.invalidate_watchers();
1370 });
1371 });
1372 }));
1373 }));
1374 }
1375
1376 fn register_scope(&self, scope: &RecomposeScope) -> (bool, bool) {
1386 let mut watchers = self.watchers.borrow_mut();
1387 let id = scope.id();
1388 match watchers.get(&id) {
1389 Some(existing) if existing.strong_count() > 0 => return (false, false),
1390 Some(_) => {
1391 watchers.remove(&id);
1392 self.state.remove_scope_observers(1);
1393 }
1394 None => {}
1395 }
1396 let any_live = watchers.values().any(|watcher| watcher.strong_count() > 0);
1397 if !any_live || watchers.len() >= watchers.capacity() {
1398 let before = watchers.len();
1399 watchers.retain(|_, watcher| watcher.strong_count() > 0);
1400 self.state.remove_scope_observers(before - watchers.len());
1401 }
1402 watchers.insert(id, scope.downgrade());
1403 drop(watchers);
1404 (true, self.state.add_scope_observer())
1405 }
1406
1407 fn has_subscribers(&self) -> bool {
1408 let mut watchers = self.watchers.borrow_mut();
1409 let before = watchers.len();
1410 watchers.retain(|_, existing| existing.upgrade().is_some());
1411 self.state.remove_scope_observers(before - watchers.len());
1412 self.state.has_subscribers()
1413 }
1414
1415 pub(crate) fn unregister_scope(&self, scope_id: ScopeId) {
1416 let mut watchers = self.watchers.borrow_mut();
1417 let removed = if watchers
1418 .get(&scope_id)
1419 .is_some_and(|weak| weak.upgrade().is_none())
1420 {
1421 watchers.remove(&scope_id);
1422 shrink_watchers_if_sparse(&mut watchers);
1423 true
1424 } else {
1425 false
1426 };
1427 drop(watchers);
1428 self.state.remove_scope_observers(usize::from(removed));
1429 }
1430
1431 fn state_id(&self) -> Option<StateId> {
1432 self.state_id.get()
1433 }
1434
1435 fn invalidate_watchers(&self) {
1436 let (watchers, removed_count): (Vec<RecomposeScope>, usize) = {
1437 let mut watchers = self.watchers.borrow_mut();
1438 let before = watchers.len();
1439 let mut live = Vec::with_capacity(watchers.len());
1440 watchers.retain(|_, scope| {
1441 if let Some(inner) = scope.upgrade() {
1442 live.push(RecomposeScope { inner });
1443 true
1444 } else {
1445 false
1446 }
1447 });
1448 let removed_count = before - watchers.len();
1449 shrink_watchers_if_sparse(&mut watchers);
1450 (live, removed_count)
1451 };
1452 self.state.remove_scope_observers(removed_count);
1453
1454 for watcher in watchers {
1455 debug_record_scope_invalidation(
1456 watcher.id(),
1457 self.state_id.get(),
1458 std::any::type_name::<T>(),
1459 );
1460 if let Some(state_id) = self.state_id.get() {
1461 watcher.invalidate_from_state(state_id);
1462 } else {
1463 watcher.invalidate();
1464 }
1465 }
1466 }
1467}
1468
1469impl<T: Clone + 'static> Drop for MutableStateInner<T> {
1470 fn drop(&mut self) {
1471 self.state
1472 .remove_scope_observers(self.watchers.get_mut().len());
1473 }
1474}
1475
1476fn register_current_state_scope<T: Clone + 'static>(inner: &MutableStateInner<T>) {
1477 let Some(Some(scope)) =
1478 with_current_composer_opt(super::composer::Composer::current_state_invalidation_scope)
1479 else {
1480 return;
1481 };
1482 let (registered, became_subscribed) = inner.register_scope(&scope);
1483 if registered {
1484 if let Some(state_id) = inner.state_id() {
1485 scope.record_state_subscription(state_id);
1486 }
1487 if became_subscribed {
1488 inner.state.notify_subscribers();
1489 }
1490 }
1491}
1492
1493trait StateArenaHandle<T: Clone + 'static> {
1494 fn state_id(&self) -> StateId;
1495 fn runtime_id(&self) -> runtime::RuntimeId;
1496
1497 fn runtime_handle(&self) -> RuntimeHandle {
1498 runtime::runtime_handle_by_id(self.runtime_id())
1499 .unwrap_or_else(|| panic!("runtime {:?} dropped", self.runtime_id()))
1500 }
1501
1502 fn runtime_handle_opt(&self) -> Option<RuntimeHandle> {
1503 runtime::runtime_handle_by_id(self.runtime_id())
1504 }
1505
1506 fn with_inner<R>(&self, f: impl FnOnce(&MutableStateInner<T>) -> R) -> R {
1507 runtime::with_state_arena_by_id(self.runtime_id(), |arena| {
1508 arena.with_typed::<T, R>(self.state_id(), f)
1509 })
1510 .unwrap_or_else(|| panic!("runtime {:?} dropped", self.runtime_id()))
1511 }
1512
1513 fn try_with_inner<R>(&self, f: impl FnOnce(&MutableStateInner<T>) -> R) -> Option<R> {
1514 runtime::with_state_arena_by_id(self.runtime_id(), |arena| {
1515 arena.with_typed_opt::<T, R>(self.state_id(), f)
1516 })?
1517 }
1518
1519 fn read_subscribed<R>(&self, read: impl FnOnce(&MutableStateInner<T>) -> R) -> R {
1520 self.with_inner(|inner| {
1521 let result = read(inner);
1522 register_current_state_scope(inner);
1523 result
1524 })
1525 }
1526}
1527
1528pub struct State<T: Clone + 'static> {
1530 id: StateId,
1531 runtime_id: runtime::RuntimeId,
1532 _marker: PhantomData<fn() -> T>,
1533}
1534
1535pub struct MutableState<T: Clone + 'static> {
1541 id: StateId,
1542 runtime_id: runtime::RuntimeId,
1543 _marker: PhantomData<fn() -> T>,
1544}
1545
1546#[derive(Clone)]
1548pub struct OwnedMutableState<T: Clone + 'static> {
1549 state: MutableState<T>,
1550 _lease: Rc<runtime::StateHandleLease>,
1551 _marker: PhantomData<fn() -> T>,
1552}
1553
1554impl<T: Clone + 'static> PartialEq for State<T> {
1555 fn eq(&self, other: &Self) -> bool {
1556 self.state_id() == other.state_id() && self.runtime_id() == other.runtime_id()
1557 }
1558}
1559
1560impl<T: Clone + 'static> Eq for State<T> {}
1561
1562impl<T: Clone + 'static> PartialEq for MutableState<T> {
1563 fn eq(&self, other: &Self) -> bool {
1564 self.state_id() == other.state_id() && self.runtime_id() == other.runtime_id()
1565 }
1566}
1567
1568impl<T: Clone + 'static> Eq for MutableState<T> {}
1569
1570impl<T: Clone + 'static> Copy for State<T> {}
1571
1572impl<T: Clone + 'static> Clone for State<T> {
1573 fn clone(&self) -> Self {
1574 *self
1575 }
1576}
1577
1578impl<T: Clone + 'static> Copy for MutableState<T> {}
1579
1580impl<T: Clone + 'static> Clone for MutableState<T> {
1581 fn clone(&self) -> Self {
1582 *self
1583 }
1584}
1585
1586impl<T: Clone + 'static> StateArenaHandle<T> for State<T> {
1587 fn state_id(&self) -> StateId {
1588 self.id
1589 }
1590
1591 fn runtime_id(&self) -> runtime::RuntimeId {
1592 self.runtime_id
1593 }
1594}
1595
1596impl<T: Clone + 'static> State<T> {
1597 pub fn is_alive(&self) -> bool {
1598 self.try_with_inner(|_| ()).is_some()
1599 }
1600
1601 pub fn try_with<R>(&self, f: impl FnOnce(&T) -> R) -> Option<R> {
1602 self.try_with_inner(|inner| inner.state.try_with_value(f))?
1603 }
1604
1605 pub fn try_value(&self) -> Option<T> {
1606 self.try_with_inner(|inner| inner.state.try_get())?
1607 }
1608
1609 pub fn with<R>(&self, f: impl FnOnce(&T) -> R) -> R {
1613 let value = self.read_subscribed(|inner| inner.state.get());
1614 f(&value)
1615 }
1616
1617 pub fn read<R>(&self, f: impl FnOnce(&T) -> R) -> R {
1622 self.read_subscribed(|inner| inner.state.with_value(f))
1623 }
1624
1625 pub fn value(&self) -> T {
1626 self.read_subscribed(|inner| inner.state.get())
1627 }
1628
1629 pub fn get(&self) -> T {
1630 self.value()
1631 }
1632
1633 pub fn has_subscribers(&self) -> bool {
1634 self.with_inner(MutableStateInner::has_subscribers)
1635 }
1636
1637 pub fn on_subscriber(&self, callback: impl Fn() + 'static) {
1643 let callback: Rc<dyn Fn()> = Rc::new(callback);
1644 self.with_inner(|inner| {
1645 inner
1646 .state
1647 .subscriber_callback(callback, inner.has_subscribers());
1648 });
1649 }
1650
1651 pub fn subscription_hold(&self) -> StateSubscriptionHold {
1663 StateSubscriptionHold {
1664 _lease: self
1665 .try_with_inner(|inner| inner.state.observation_lease())
1666 .flatten(),
1667 }
1668 }
1669}
1670
1671pub struct StateSubscriptionHold {
1674 _lease: Option<Rc<dyn Any>>,
1675}
1676
1677impl<T: Clone + 'static> StateArenaHandle<T> for MutableState<T> {
1678 fn state_id(&self) -> StateId {
1679 self.id
1680 }
1681
1682 fn runtime_id(&self) -> runtime::RuntimeId {
1683 self.runtime_id
1684 }
1685}
1686
1687impl<T: Clone + 'static> MutableState<T> {
1688 pub fn with_runtime(value: T, runtime: RuntimeHandle) -> Self {
1689 runtime.alloc_persistent_state(value)
1690 }
1691
1692 fn from_parts(id: StateId, runtime_id: runtime::RuntimeId) -> Self {
1693 Self {
1694 id,
1695 runtime_id,
1696 _marker: PhantomData,
1697 }
1698 }
1699
1700 pub(crate) fn from_lease(lease: &Rc<runtime::StateHandleLease>) -> Self {
1701 Self::from_parts(lease.id(), lease.runtime().id())
1702 }
1703
1704 pub fn is_alive(&self) -> bool {
1705 self.try_with_inner(|_| ()).is_some()
1706 }
1707
1708 pub fn try_with<R>(&self, f: impl FnOnce(&T) -> R) -> Option<R> {
1709 self.try_with_inner(|inner| inner.state.try_with_value(f))?
1710 }
1711
1712 pub fn try_value(&self) -> Option<T> {
1713 self.try_with_inner(|inner| inner.state.try_get())?
1714 }
1715
1716 pub fn as_state(&self) -> State<T> {
1717 State {
1718 id: self.id,
1719 runtime_id: self.runtime_id,
1720 _marker: PhantomData,
1721 }
1722 }
1723
1724 pub fn try_retain(&self) -> Option<OwnedMutableState<T>> {
1725 let lease = self
1726 .runtime_handle_opt()?
1727 .retain_state_lease(self.state_id())?;
1728 Some(OwnedMutableState {
1729 state: *self,
1730 _lease: lease,
1731 _marker: PhantomData,
1732 })
1733 }
1734
1735 pub fn retain(&self) -> OwnedMutableState<T> {
1736 self.try_retain()
1737 .unwrap_or_else(|| panic!("state {:?} is no longer alive", self.state_id()))
1738 }
1739
1740 pub fn with<R>(&self, f: impl FnOnce(&T) -> R) -> R {
1744 let value = self.read_subscribed(|inner| inner.state.get());
1745 f(&value)
1746 }
1747
1748 pub fn read<R>(&self, f: impl FnOnce(&T) -> R) -> R {
1753 self.read_subscribed(|inner| inner.state.with_value(f))
1754 }
1755
1756 pub fn update<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
1757 let runtime = self.runtime_handle();
1758 runtime.assert_ui_thread();
1759 runtime.with_state_arena(|arena| {
1760 arena.with_typed::<T, R>(self.state_id(), |inner| {
1761 let mut value = inner.state.get();
1762 let tracker = UpdateScope::new(inner.state.id());
1763 let result = f(&mut value);
1764 let wrote_elsewhere = tracker.finish();
1765 if !wrote_elsewhere && inner.state.set(value) {
1766 inner.invalidate_watchers();
1767 }
1768 result
1769 })
1770 })
1771 }
1772
1773 pub fn replace(&self, value: T) {
1774 let Some(runtime) = self.runtime_handle_opt() else {
1775 log::debug!(
1776 "MutableState::replace skipped: runtime {:?} dropped",
1777 self.runtime_id()
1778 );
1779 return;
1780 };
1781 runtime.assert_ui_thread();
1782 let replaced = runtime
1783 .try_with_state_arena(|arena| {
1784 arena.with_typed_opt::<T, ()>(self.state_id(), |inner| {
1785 if inner.state.set(value) {
1786 inner.invalidate_watchers();
1787 }
1788 })
1789 })
1790 .flatten();
1791 if replaced.is_none() {
1792 log::debug!(
1793 "MutableState::replace skipped: state cell released (slot={}, gen={})",
1794 self.state_id().slot(),
1795 self.state_id().generation(),
1796 );
1797 }
1798 }
1799
1800 pub fn set_value(&self, value: T) {
1801 self.replace(value);
1802 }
1803
1804 pub fn set(&self, value: T) {
1805 self.replace(value);
1806 }
1807
1808 pub fn value(&self) -> T {
1809 self.read_subscribed(|inner| inner.state.get())
1810 }
1811
1812 pub fn get(&self) -> T {
1813 self.value()
1814 }
1815
1816 pub fn get_non_reactive(&self) -> T {
1817 self.with_inner(|inner| inner.state.get())
1818 }
1819
1820 #[doc(hidden)]
1821 pub fn runtime_state_id(&self) -> StateId {
1822 self.state_id()
1823 }
1824
1825 #[doc(hidden)]
1826 pub fn subscribe_current_scope_only(&self) {
1827 self.subscribe_current_scope();
1828 }
1829
1830 fn subscribe_current_scope(&self) {
1831 self.with_inner(register_current_state_scope::<T>);
1832 }
1833
1834 #[cfg(test)]
1835 pub(crate) fn watcher_count(&self) -> usize {
1836 self.with_inner(|inner| inner.watchers.borrow().len())
1837 }
1838
1839 #[cfg(test)]
1840 pub(crate) fn watcher_capacity(&self) -> usize {
1841 self.with_inner(|inner| inner.watchers.borrow().capacity())
1842 }
1843
1844 #[cfg(test)]
1845 pub(crate) fn state_id_for_test(&self) -> StateId {
1846 self.state_id()
1847 }
1848
1849 #[cfg(test)]
1850 pub(crate) fn subscribe_scope_for_test(&self, scope: &RecomposeScope) {
1851 self.as_state().subscribe_scope_for_test(scope);
1852 }
1853}
1854
1855impl<T: Clone + 'static> OwnedMutableState<T> {
1856 pub fn with_runtime(value: T, runtime: RuntimeHandle) -> Self {
1857 let lease = runtime.alloc_state(value);
1858 Self {
1859 state: MutableState::from_lease(&lease),
1860 _lease: lease,
1861 _marker: PhantomData,
1862 }
1863 }
1864
1865 pub fn with_runtime_structural_eq(value: T, runtime: RuntimeHandle) -> Self
1866 where
1867 T: PartialEq,
1868 {
1869 Self::with_runtime_and_policy(value, runtime, Arc::new(StructuralEqual))
1870 }
1871
1872 pub(crate) fn with_runtime_and_policy(
1873 value: T,
1874 runtime: RuntimeHandle,
1875 policy: Arc<dyn MutationPolicy<T>>,
1876 ) -> Self {
1877 let lease = runtime.alloc_state_with_policy(value, policy);
1878 Self {
1879 state: MutableState::from_lease(&lease),
1880 _lease: lease,
1881 _marker: PhantomData,
1882 }
1883 }
1884
1885 pub fn handle(&self) -> MutableState<T> {
1886 self.state
1887 }
1888
1889 pub fn as_state(&self) -> State<T> {
1890 self.state.as_state()
1891 }
1892}
1893
1894impl<T: Clone + 'static> Deref for OwnedMutableState<T> {
1895 type Target = MutableState<T>;
1896
1897 fn deref(&self) -> &Self::Target {
1898 &self.state
1899 }
1900}
1901
1902#[cfg(test)]
1903impl<T: Clone + 'static> State<T> {
1904 pub(crate) fn subscribe_scope_for_test(&self, scope: &RecomposeScope) {
1905 self.with_inner(|inner| {
1906 let (registered, became_subscribed) = inner.register_scope(scope);
1907 if registered {
1908 if let Some(state_id) = inner.state_id() {
1909 scope.record_state_subscription(state_id);
1910 }
1911 if became_subscribed {
1912 inner.state.notify_subscribers();
1913 }
1914 }
1915 });
1916 }
1917}
1918
1919impl<T: fmt::Debug + Clone + 'static> fmt::Debug for MutableState<T> {
1920 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1921 if let Some(value) = self.try_value() {
1922 f.debug_struct("MutableState")
1923 .field("value", &value)
1924 .finish()
1925 } else {
1926 f.write_str("MutableState { value: <unavailable> }")
1927 }
1928 }
1929}
1930
1931#[derive(Clone)]
1932pub struct SnapshotStateList<T: Clone + 'static> {
1933 state: OwnedMutableState<Vec<T>>,
1934}
1935
1936impl<T: Clone + 'static> SnapshotStateList<T> {
1937 pub fn with_runtime<I>(values: I, runtime: RuntimeHandle) -> Self
1938 where
1939 I: IntoIterator<Item = T>,
1940 {
1941 let initial: Vec<T> = values.into_iter().collect();
1942 Self {
1943 state: OwnedMutableState::with_runtime(initial, runtime),
1944 }
1945 }
1946
1947 pub fn as_state(&self) -> State<Vec<T>> {
1948 self.state.as_state()
1949 }
1950
1951 pub fn as_mutable_state(&self) -> MutableState<Vec<T>> {
1952 self.state.handle()
1953 }
1954
1955 pub fn len(&self) -> usize {
1956 self.state.with(Vec::len)
1957 }
1958
1959 pub fn is_empty(&self) -> bool {
1960 self.len() == 0
1961 }
1962
1963 pub fn to_vec(&self) -> Vec<T> {
1964 self.state.with(Clone::clone)
1965 }
1966
1967 pub fn iter(&self) -> Vec<T> {
1968 self.to_vec()
1969 }
1970
1971 pub fn get(&self, index: usize) -> T {
1972 self.state.with(|values| values[index].clone())
1973 }
1974
1975 pub fn get_opt(&self, index: usize) -> Option<T> {
1976 self.state.with(|values| values.get(index).cloned())
1977 }
1978
1979 pub fn first(&self) -> Option<T> {
1980 self.get_opt(0)
1981 }
1982
1983 pub fn last(&self) -> Option<T> {
1984 self.state.with(|values| values.last().cloned())
1985 }
1986
1987 pub fn push(&self, value: T) {
1988 self.state.update(|values| values.push(value));
1989 }
1990
1991 pub fn extend<I>(&self, iter: I)
1992 where
1993 I: IntoIterator<Item = T>,
1994 {
1995 self.state.update(|values| values.extend(iter));
1996 }
1997
1998 pub fn insert(&self, index: usize, value: T) {
1999 self.state.update(|values| values.insert(index, value));
2000 }
2001
2002 pub fn set(&self, index: usize, value: T) -> T {
2003 self.state
2004 .update(|values| std::mem::replace(&mut values[index], value))
2005 }
2006
2007 pub fn remove(&self, index: usize) -> T {
2008 self.state.update(|values| values.remove(index))
2009 }
2010
2011 pub fn pop(&self) -> Option<T> {
2012 self.state.update(Vec::pop)
2013 }
2014
2015 pub fn clear(&self) {
2016 self.state.replace(Vec::new());
2017 }
2018
2019 pub fn retain<F>(&self, mut predicate: F)
2020 where
2021 F: FnMut(&T) -> bool,
2022 {
2023 self.state
2024 .update(|values| values.retain(|value| predicate(value)));
2025 }
2026
2027 pub fn replace_with<I>(&self, iter: I)
2028 where
2029 I: IntoIterator<Item = T>,
2030 {
2031 self.state.replace(iter.into_iter().collect());
2032 }
2033}
2034
2035impl<T: fmt::Debug + Clone + 'static> fmt::Debug for SnapshotStateList<T> {
2036 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2037 let contents = self.to_vec();
2038 f.debug_struct("SnapshotStateList")
2039 .field("values", &contents)
2040 .finish()
2041 }
2042}
2043
2044#[derive(Clone)]
2045pub struct SnapshotStateMap<K, V>
2046where
2047 K: Clone + Eq + Hash + 'static,
2048 V: Clone + 'static,
2049{
2050 state: OwnedMutableState<HashMap<K, V>>,
2051}
2052
2053impl<K, V> SnapshotStateMap<K, V>
2054where
2055 K: Clone + Eq + Hash + 'static,
2056 V: Clone + 'static,
2057{
2058 pub fn with_runtime<I>(pairs: I, runtime: RuntimeHandle) -> Self
2059 where
2060 I: IntoIterator<Item = (K, V)>,
2061 {
2062 let map: HashMap<K, V> = pairs.into_iter().collect();
2063 Self {
2064 state: OwnedMutableState::with_runtime(map, runtime),
2065 }
2066 }
2067
2068 pub fn as_state(&self) -> State<HashMap<K, V>> {
2069 self.state.as_state()
2070 }
2071
2072 pub fn as_mutable_state(&self) -> MutableState<HashMap<K, V>> {
2073 self.state.handle()
2074 }
2075
2076 pub fn len(&self) -> usize {
2077 self.state.with(std::collections::HashMap::len)
2078 }
2079
2080 pub fn is_empty(&self) -> bool {
2081 self.state.with(std::collections::HashMap::is_empty)
2082 }
2083
2084 pub fn contains_key(&self, key: &K) -> bool {
2085 self.state.with(|map| map.contains_key(key))
2086 }
2087
2088 pub fn get(&self, key: &K) -> Option<V> {
2089 self.state.with(|map| map.get(key).cloned())
2090 }
2091
2092 pub fn to_hash_map(&self) -> HashMap<K, V> {
2093 self.state.with(Clone::clone)
2094 }
2095
2096 pub fn insert(&self, key: K, value: V) -> Option<V> {
2097 self.state.update(|map| map.insert(key, value))
2098 }
2099
2100 pub fn extend<I>(&self, iter: I)
2101 where
2102 I: IntoIterator<Item = (K, V)>,
2103 {
2104 self.state.update(|map| map.extend(iter));
2105 }
2106
2107 pub fn remove(&self, key: &K) -> Option<V> {
2108 self.state.update(|map| map.remove(key))
2109 }
2110
2111 pub fn clear(&self) {
2112 self.state.replace(HashMap::default());
2113 }
2114
2115 pub fn retain<F>(&self, mut predicate: F)
2116 where
2117 F: FnMut(&K, &mut V) -> bool,
2118 {
2119 self.state.update(|map| map.retain(|k, v| predicate(k, v)));
2120 }
2121}
2122
2123impl<K, V> fmt::Debug for SnapshotStateMap<K, V>
2124where
2125 K: Clone + Eq + Hash + fmt::Debug + 'static,
2126 V: Clone + fmt::Debug + 'static,
2127{
2128 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2129 let contents = self.to_hash_map();
2130 f.debug_struct("SnapshotStateMap")
2131 .field("entries", &contents)
2132 .finish()
2133 }
2134}
2135
2136pub(crate) struct DerivedState<T: Clone + PartialEq + 'static> {
2137 compute: Rc<dyn Fn() -> T>,
2138 pub(crate) state: OwnedMutableState<T>,
2139}
2140
2141impl<T: Clone + PartialEq + 'static> DerivedState<T> {
2142 pub(crate) fn new(runtime: RuntimeHandle, compute: Rc<dyn Fn() -> T>) -> Self {
2143 let initial = compute();
2144 Self {
2145 compute,
2146 state: OwnedMutableState::with_runtime_structural_eq(initial, runtime),
2147 }
2148 }
2149
2150 pub(crate) fn set_compute(&mut self, compute: Rc<dyn Fn() -> T>) {
2151 self.compute = compute;
2152 }
2153
2154 pub(crate) fn recompute(&self) {
2155 let value = (self.compute)();
2156 self.state.set_value(value);
2157 }
2158}
2159
2160impl<T: fmt::Debug + Clone + 'static> fmt::Debug for State<T> {
2161 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2162 if let Some(value) = self.try_value() {
2163 f.debug_struct("State").field("value", &value).finish()
2164 } else {
2165 f.write_str("State { value: <unavailable> }")
2166 }
2167 }
2168}
2169
2170#[cfg(test)]
2171#[path = "tests/state_tests.rs"]
2172mod tests;