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