Skip to main content

cranpose_core/
state.rs

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    /// Takes the value out, for the caller to drop once the operation that
160    /// cleared it is done: its destructor may read or write state.
161    #[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    /// Marks the record dead and retires its value, for an operation that
167    /// holds a [`RetiredValuesScope`].
168    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    /// Stores `new_value` and returns the value it displaced, for the caller
176    /// to drop once the write is published: its destructor may read or write
177    /// state.
178    #[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    // Record values displaced inside snapshot bookkeeping, and how many
504    // operations that hold them back are running.
505    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
510/// Drops `value`, a record value displaced inside snapshot bookkeeping, once
511/// the outermost [`RetiredValuesScope`] ends, or now when none is open: its
512/// destructor may read or write state.
513pub(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
521/// Holds back the drop of retired record values until the outermost scope
522/// ends, so no destructor runs while snapshot bookkeeping is half done.
523pub(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
546/// Marks the records of `state` that no open snapshot can read as free for
547/// reuse, retiring their values, and reports whether the state still keeps
548/// more than one record.
549pub(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
710// What a write does that does not depend on the state's value type, so it
711// is compiled once instead of once per state type.
712struct 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        // Published only now that its value is stored: nothing may read the
763        // record while the store runs.
764        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(&current_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(&current_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", &current));
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    /// Adds `scope` to the state's watchers, saying whether it was new and
1377    /// whether the state thereby gained its first subscriber.
1378    ///
1379    /// Dead watchers still count as subscribers until pruned. They are
1380    /// pruned whenever no live one is left, so a reader arriving after every
1381    /// earlier one died still makes the state newly subscribed, and
1382    /// otherwise only when the map is full, before the insert would grow
1383    /// it: a state read by thousands of scopes, such as the density, must
1384    /// not scan them all for every new reader.
1385    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
1528/// Cheap copyable read-only view of a state cell.
1529pub struct State<T: Clone + 'static> {
1530    id: StateId,
1531    runtime_id: runtime::RuntimeId,
1532    _marker: PhantomData<fn() -> T>,
1533}
1534
1535/// Cheap copyable mutable view of a state cell.
1536///
1537/// Ownership lives elsewhere: a composition slot, an [`OwnedMutableState`], or
1538/// the runtime for states created with [`crate::mutableStateOf`] /
1539/// [`MutableState::with_runtime`].
1540pub struct MutableState<T: Clone + 'static> {
1541    id: StateId,
1542    runtime_id: runtime::RuntimeId,
1543    _marker: PhantomData<fn() -> T>,
1544}
1545
1546/// Owning state handle for reclaimable state cells.
1547#[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    /// Reads a copy of the value through `f` and subscribes the current
1610    /// scope. `f` may write this state; see [`Self::read`] for a read that
1611    /// borrows instead of copying.
1612    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    /// Reads the value in place through `f` and subscribes the current
1618    /// scope. Nothing is cloned, so a read of a large value costs nothing
1619    /// beyond `f`; in return `f` borrows the stored value and must not write
1620    /// this state.
1621    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    /// Runs `callback` each time this state gains its first subscriber, and
1638    /// right away when it already has one.
1639    ///
1640    /// The state owns `callback` for as long as the state lives, so nothing
1641    /// has to be kept alive on the caller's side.
1642    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    /// Counts this state as subscribed for as long as the returned guard
1652    /// lives, without observing it from any scope.
1653    ///
1654    /// Snapshot observers subscribe reads made under composition or the
1655    /// draw phase, and producers gated on [`State::has_subscribers`] — an
1656    /// infinite transition, for one — stop themselves when the last such
1657    /// subscriber leaves. A consumer that reads the value from a polling
1658    /// context (a frame effect stepping it into a derived state, a
1659    /// background task) is invisible to that accounting and would starve
1660    /// the producer it depends on. Holding this guard keeps the producer
1661    /// alive; dropping it releases the count.
1662    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
1671/// Keeps a [`State`] counted as subscribed while alive; see
1672/// [`State::subscription_hold`].
1673pub 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    /// Reads a copy of the value through `f` and subscribes the current
1741    /// scope. `f` may write this state; see [`Self::read`] for a read that
1742    /// borrows instead of copying.
1743    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    /// Reads the value in place through `f` and subscribes the current
1749    /// scope. Nothing is cloned, so a read of a large value costs nothing
1750    /// beyond `f`; in return `f` borrows the stored value and must not write
1751    /// this state.
1752    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;