Skip to main content

cranpose_core/
state.rs

1use std::{
2    any::{Any, TypeId},
3    cell::{Cell, OnceCell, RefCell},
4    fmt,
5    hash::Hash,
6    marker::PhantomData,
7    ops::Deref,
8    rc::{Rc, Weak},
9};
10
11use smallvec::{SmallVec, smallvec};
12
13use crate::{
14    RecomposeScope, RecomposeScopeInner, RuntimeHandle, ScopeId, StateId,
15    collections::map::HashMap,
16    debug_trace::debug_record_scope_invalidation,
17    runtime,
18    snapshot_id_set::{SnapshotId, SnapshotIdSet},
19    snapshot_v2::{
20        AnySnapshot, GlobalSnapshot, advance_global_snapshot, allocate_record_id, current_snapshot,
21    },
22    with_current_composer_opt,
23};
24
25mod derived_state;
26mod readable_record;
27mod record_chain;
28mod snapshot_state_list;
29
30pub(crate) use derived_state::DerivedState;
31use readable_record::{ReadNotice, StateReadFailure, readable_record_for_active_snapshot};
32pub(crate) use record_chain::RecordChain;
33pub use snapshot_state_list::SnapshotStateList;
34
35pub(crate) const PREEXISTING_SNAPSHOT_ID: SnapshotId = SnapshotId(1);
36
37const INVALID_SNAPSHOT_ID: SnapshotId = SnapshotId(0);
38
39const SNAPSHOT_ID_MAX: SnapshotId = SnapshotId(usize::MAX);
40
41#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug, Default)]
42pub struct ObjectId(pub(crate) usize);
43
44impl ObjectId {
45    #[cfg(test)]
46    pub(crate) fn new<T: ?Sized + 'static>(object: &Rc<T>) -> Self {
47        Self(Rc::as_ptr(object) as *const () as usize)
48    }
49}
50
51pub struct StateRecord {
52    snapshot_id: Cell<SnapshotId>,
53    tombstone: Cell<bool>,
54    value: RefCell<Option<Box<dyn RecordValue>>>,
55}
56
57pub(crate) trait RecordValue: Any {
58    fn clone_boxed(&self) -> Box<dyn RecordValue>;
59    fn assign_into(&self, target: &mut Option<Box<dyn RecordValue>>);
60    /// Whether dropping the value releases anything beyond its box.
61    fn holds_resources(&self) -> bool;
62}
63
64impl<T: Any + Clone> RecordValue for T {
65    fn holds_resources(&self) -> bool {
66        std::mem::needs_drop::<T>()
67    }
68
69    fn clone_boxed(&self) -> Box<dyn RecordValue> {
70        Box::new(self.clone())
71    }
72
73    fn assign_into(&self, target: &mut Option<Box<dyn RecordValue>>) {
74        match target
75            .as_mut()
76            .and_then(|value| (&mut **value as &mut dyn Any).downcast_mut::<T>())
77        {
78            Some(slot) => slot.clone_from(self),
79            None => *target = Some(Box::new(self.clone())),
80        }
81    }
82}
83
84#[derive(Debug, Clone, Copy, Eq, PartialEq)]
85pub(crate) enum StateRecordValueError {
86    Missing,
87}
88
89impl StateRecord {
90    pub(crate) fn new<T: Any + Clone>(snapshot_id: SnapshotId, value: T) -> Rc<Self> {
91        Self::with_boxed(snapshot_id, Box::new(value))
92    }
93
94    fn with_boxed(snapshot_id: SnapshotId, value: Box<dyn RecordValue>) -> Rc<Self> {
95        Rc::new(Self {
96            snapshot_id: Cell::new(snapshot_id),
97            tombstone: Cell::new(false),
98            value: RefCell::new(Some(value)),
99        })
100    }
101
102    #[inline]
103    pub(crate) fn snapshot_id(&self) -> SnapshotId {
104        self.snapshot_id.get()
105    }
106
107    #[inline]
108    pub(crate) fn set_snapshot_id(&self, id: SnapshotId) {
109        self.snapshot_id.set(id);
110    }
111
112    #[inline]
113    pub(crate) fn is_tombstone(&self) -> bool {
114        self.tombstone.get()
115    }
116
117    #[inline]
118    pub(crate) fn set_tombstone(&self, tombstone: bool) {
119        self.tombstone.set(tombstone);
120    }
121
122    /// Takes the value out of a record that no read reaches any more, for
123    /// the caller to drop once the operation that cleared it is done: its
124    /// destructor may read or write state. A value without drop glue holds
125    /// nothing to release and stays, so the record's next write stores over
126    /// it in place instead of boxing a new value.
127    #[must_use = "drop the cleared value once the record chain is consistent"]
128    pub(crate) fn clear_value(&self) -> Option<Box<dyn RecordValue>> {
129        let mut value = self.value.borrow_mut();
130        if value
131            .as_ref()
132            .is_some_and(|value| (**value).holds_resources())
133        {
134            value.take()
135        } else {
136            None
137        }
138    }
139
140    /// Marks the record dead and retires its value, for an operation that
141    /// holds a [`RetiredValuesScope`].
142    pub(crate) fn tombstone_retiring_value(&self) {
143        self.set_tombstone(true);
144        if let Some(value) = self.clear_value() {
145            retire_record_value(value);
146        }
147    }
148
149    /// Stores `new_value` and returns the value it displaced, for the caller
150    /// to drop once the write is published: its destructor may read or write
151    /// state.
152    #[must_use = "drop the displaced value once the write is published"]
153    pub(crate) fn replace_value<T: Any + Clone>(&self, new_value: T) -> Option<T> {
154        let mut value = self.value.borrow_mut();
155        if let Some(slot) = value
156            .as_mut()
157            .and_then(|current| (&mut **current as &mut dyn Any).downcast_mut::<T>())
158        {
159            return Some(std::mem::replace(slot, new_value));
160        }
161        let placeholder = value.replace(Box::new(new_value));
162        drop(value);
163        drop(placeholder);
164        None
165    }
166
167    fn cloned_value(&self) -> Option<Box<dyn RecordValue>> {
168        self.value
169            .borrow()
170            .as_ref()
171            .map(|value| (**value).clone_boxed())
172    }
173
174    fn cloned_value_of(&self, expected: TypeId) -> Option<Box<dyn RecordValue>> {
175        self.value
176            .borrow()
177            .as_ref()
178            .filter(|value| (&***value as &dyn Any).type_id() == expected)
179            .map(|value| (**value).clone_boxed())
180    }
181
182    fn set_boxed_value(&self, value: Box<dyn RecordValue>) {
183        let displaced = self.value.borrow_mut().replace(value);
184        if let Some(displaced) = displaced {
185            retire_record_value(displaced);
186        }
187    }
188
189    pub(crate) fn with_value<T: Any, R>(&self, f: impl FnOnce(&T) -> R) -> R {
190        self.try_with_value(f)
191            .unwrap_or_else(|| panic!("StateRecord value missing or wrong type"))
192    }
193
194    pub(crate) fn try_with_value<T: Any, R>(&self, f: impl FnOnce(&T) -> R) -> Option<R> {
195        let guard = self.value.borrow();
196        let value = guard
197            .as_ref()
198            .and_then(|boxed| (&**boxed as &dyn Any).downcast_ref::<T>())?;
199        Some(f(value))
200    }
201
202    #[cfg(test)]
203    pub(crate) fn clear_for_reuse(&self) {
204        drop(self.value.borrow_mut().take());
205    }
206
207    pub(crate) fn assign_value(&self, source: &Self) -> Result<(), StateRecordValueError> {
208        if std::ptr::eq(self, source) {
209            return match self.value.borrow().is_some() {
210                true => Ok(()),
211                false => Err(StateRecordValueError::Missing),
212            };
213        }
214        let source_value = source.value.borrow();
215        let value = source_value
216            .as_ref()
217            .ok_or(StateRecordValueError::Missing)?;
218        (**value).assign_into(&mut self.value.borrow_mut());
219        Ok(())
220    }
221}
222
223#[cold]
224fn log_merge_value_missing(which: &str, state: ObjectId, record: &StateRecord) {
225    log::error!(
226        "SnapshotMutableState::merge_records {which} record value missing or wrong type (state {state:?}, {which}_id={})",
227        record.snapshot_id()
228    );
229}
230
231fn install_copy_as_head(
232    state: &dyn StateObject,
233    source: &StateRecord,
234    expected: TypeId,
235) -> Option<SnapshotId> {
236    let value = source.cloned_value_of(expected)?;
237    let new_id = allocate_record_id();
238    let record = state.records().overwritable_head();
239    record.set_boxed_value(value);
240    record.set_tombstone(false);
241    record.set_snapshot_id(new_id);
242    advance_global_snapshot(new_id);
243    Some(new_id)
244}
245
246fn promote_record_locked(
247    state: &dyn StateObject,
248    child_id: SnapshotId,
249    expected: TypeId,
250) -> Result<(), &'static str> {
251    let Some(record) = state.records().at(child_id) else {
252        log::error!(
253            "SnapshotMutableState::promote_record missing child record (state {:?}, child_id={})",
254            state.object_id(),
255            child_id
256        );
257        return Err("missing child record");
258    };
259    if install_copy_as_head(state, &record, expected).is_none() {
260        log::error!(
261            "SnapshotMutableState::promote_record child record value missing or wrong type (state {:?}, child_id={})",
262            state.object_id(),
263            child_id
264        );
265        return Err("child record value missing or wrong type");
266    }
267    Ok(())
268}
269
270fn commit_merged_record_locked(
271    state: &dyn StateObject,
272    merged: &StateRecord,
273    expected: TypeId,
274) -> Result<SnapshotId, &'static str> {
275    install_copy_as_head(state, merged, expected).ok_or_else(|| {
276        log::error!(
277            "SnapshotMutableState::commit_merged_record merged record value missing or wrong type (state {:?}, merged_id={})",
278            state.object_id(),
279            merged.snapshot_id()
280        );
281        "merged record value missing or wrong type"
282    })
283}
284
285/// Drops `value`, a record value displaced inside snapshot bookkeeping, once
286/// the outermost [`RetiredValuesScope`] ends, or now when none is open: its
287/// destructor may read or write state.
288pub(crate) fn retire_record_value(value: Box<dyn RecordValue>) {
289    let held = crate::thread_state::try_snapshots(|state| {
290        if state.retire_depth.get() == 0 {
291            return Some(value);
292        }
293        state.retired_record_values.borrow_mut().push(value);
294        None
295    });
296    drop(held);
297}
298
299/// Holds back the drop of retired record values until the outermost scope
300/// ends, so no destructor runs while snapshot bookkeeping is half done.
301pub(crate) struct RetiredValuesScope(());
302
303impl RetiredValuesScope {
304    pub(crate) fn enter() -> Self {
305        crate::thread_state::snapshots(|state| {
306            state.retire_depth.set(state.retire_depth.get() + 1);
307        });
308        Self(())
309    }
310}
311
312impl Drop for RetiredValuesScope {
313    fn drop(&mut self) {
314        let retired = crate::thread_state::snapshots(|state| {
315            let depth = state.retire_depth.get() - 1;
316            state.retire_depth.set(depth);
317            (depth == 0).then(|| state.retired_record_values.take())
318        });
319        drop(retired);
320    }
321}
322
323fn active_snapshot() -> AnySnapshot {
324    current_snapshot().unwrap_or_else(|| AnySnapshot::Global(GlobalSnapshot::get_or_create()))
325}
326
327pub(crate) trait MutationPolicy<T>: Send + Sync {
328    fn equivalent(&self, a: &T, b: &T) -> bool;
329    fn merge(&self, _previous: &T, _current: &T, _applied: &T) -> Option<T> {
330        None
331    }
332}
333
334pub(crate) struct NeverEqual;
335
336impl<T> MutationPolicy<T> for NeverEqual {
337    fn equivalent(&self, _a: &T, _b: &T) -> bool {
338        false
339    }
340}
341
342pub(crate) struct StructuralEqual;
343
344impl<T: PartialEq> MutationPolicy<T> for StructuralEqual {
345    fn equivalent(&self, a: &T, b: &T) -> bool {
346        a == b
347    }
348}
349
350pub trait StateObject: Any {
351    fn object_id(&self) -> ObjectId;
352    fn records(&self) -> &RecordChain;
353    fn try_readable_record(
354        &self,
355        snapshot_id: SnapshotId,
356        invalid: &SnapshotIdSet,
357    ) -> Option<Rc<StateRecord>>;
358    fn readable_record(&self, snapshot_id: SnapshotId, invalid: &SnapshotIdSet) -> Rc<StateRecord>;
359
360    fn merge_records(
361        &self,
362        _previous: Rc<StateRecord>,
363        _current: Rc<StateRecord>,
364        _applied: Rc<StateRecord>,
365    ) -> Option<Rc<StateRecord>> {
366        None
367    }
368
369    fn commit_merged_record(&self, _merged: Rc<StateRecord>) -> Result<SnapshotId, &'static str> {
370        Err("StateObject does not support merged record commits")
371    }
372    fn promote_record(&self, child_id: SnapshotId) -> Result<(), &'static str>;
373
374    fn overwrite_unused_records(&self) -> bool {
375        false
376    }
377
378    fn observation_lease(&self) -> Option<Rc<dyn Any>> {
379        None
380    }
381
382    fn as_any(&self) -> &dyn Any;
383}
384
385pub(crate) struct SnapshotMutableState<T> {
386    records: RecordChain,
387    policy: Rc<dyn MutationPolicy<T>>,
388    id: ObjectId,
389    weak_self: Weak<Self>,
390    apply_observer: ApplyObserver,
391    subscribers: Subscribers,
392}
393
394// Who subscribes to a state, whatever its value's type: the leases on its
395// reads, the scopes that observe it and the callbacks to run when it gains
396// its first subscriber. Kept apart from the value's type, so its code is
397// compiled once for every state type.
398#[derive(Default)]
399pub(crate) struct Subscribers {
400    lease: Rc<()>,
401    scopes: Cell<usize>,
402    callbacks: RefCell<Vec<Rc<dyn Fn()>>>,
403}
404
405impl Subscribers {
406    fn acquire_observation_lease(&self) -> Option<Rc<dyn Any>> {
407        let was_empty = !self.has_subscribers();
408        let lease = Rc::clone(&self.lease);
409        if was_empty {
410            notify_subscriber_callbacks(&self.callbacks);
411        }
412        Some(lease)
413    }
414
415    fn add_scope_observer(&self) -> bool {
416        let was_empty = !self.has_subscribers();
417        let count = self
418            .scopes
419            .get()
420            .checked_add(1)
421            .expect("state scope observation count overflow");
422        self.scopes.set(count);
423        was_empty
424    }
425
426    fn remove_scope_observers(&self, count: usize) {
427        if count == 0 {
428            return;
429        }
430        let remaining = self
431            .scopes
432            .get()
433            .checked_sub(count)
434            .expect("state scope observation count underflow");
435        self.scopes.set(remaining);
436    }
437
438    fn has_subscribers(&self) -> bool {
439        Rc::strong_count(&self.lease) > 1 || self.scopes.get() > 0
440    }
441
442    fn subscriber_callback(&self, callback: Rc<dyn Fn()>, notify: bool) {
443        self.callbacks.borrow_mut().push(Rc::clone(&callback));
444        if notify {
445            callback();
446        }
447    }
448
449    fn notify_subscribers(&self) {
450        notify_subscriber_callbacks(&self.callbacks);
451    }
452}
453
454#[inline(always)]
455fn assert_record_chain(
456    records: &RecordChain,
457    id: ObjectId,
458    caller: &str,
459    snapshot_context: Option<SnapshotId>,
460) {
461    if should_check_chain_integrity() {
462        records.check_integrity(id, caller, snapshot_context);
463    }
464}
465
466enum Merge<'a, T> {
467    KeepCurrent,
468    Value(Option<T>),
469    Missing(&'static str, &'a Rc<StateRecord>),
470}
471
472type ApplyObserver = OnceCell<Box<dyn Fn() + 'static>>;
473
474fn notify_applied(observer: &ApplyObserver) {
475    if let Some(observer) = observer.get() {
476        observer();
477    }
478}
479
480fn finish_apply(
481    observer: &ApplyObserver,
482    records: &RecordChain,
483    id: ObjectId,
484    caller: &str,
485    snapshot_id: SnapshotId,
486) {
487    notify_applied(observer);
488    assert_record_chain(records, id, caller, Some(snapshot_id));
489}
490
491// What a write does that does not depend on the state's value type, so it
492// is compiled once instead of once per state type.
493struct WriteTarget<'a> {
494    records: &'a RecordChain,
495    id: ObjectId,
496}
497
498impl WriteTarget<'_> {
499    fn assert_chain_integrity(&self, caller: &str, snapshot_context: Option<SnapshotId>) {
500        assert_record_chain(self.records, self.id, caller, snapshot_context);
501    }
502
503    fn begin_global_write(&self, global: &GlobalSnapshot, snapshot_id: SnapshotId) {
504        assert!(
505            !global.has_pending_children(),
506            "SnapshotMutableState::set attempted global write while pending children {:?} exist (state {:?}, snapshot_id={})",
507            global.pending_children(),
508            self.id,
509            snapshot_id
510        );
511        mark_update_write(self.id);
512    }
513
514    /// Returns a head record for a global write and the id under which
515    /// [`Self::publish_global_record`] publishes it.
516    fn push_global_record(&self) -> (Rc<StateRecord>, SnapshotId) {
517        let new_id = allocate_record_id();
518        (self.records.overwritable_head(), new_id)
519    }
520
521    /// Publishes a pushed record once its value is stored: nothing may read
522    /// the record while the store runs.
523    fn publish_global_record(
524        &self,
525        record: &StateRecord,
526        new_id: SnapshotId,
527        snapshot_id: SnapshotId,
528    ) {
529        record.set_snapshot_id(new_id);
530        record.set_tombstone(false);
531        advance_global_snapshot(new_id);
532        self.assert_chain_integrity("set(global-push)", Some(snapshot_id));
533    }
534
535    /// Finishes a global write that stored its value in `record`, the record
536    /// at the global snapshot's current id.
537    fn finish_global_write(
538        &self,
539        record: &StateRecord,
540        written: Option<Rc<dyn StateObject>>,
541        snapshot_id: SnapshotId,
542    ) {
543        let mut cleared: SmallVec<[Box<dyn RecordValue>; 2]> = SmallVec::new();
544        self.records.clear_hidden_after(record, &mut cleared);
545        self.assert_chain_integrity("set(global-tombstone)", Some(snapshot_id));
546        if let Some(modified) = written.as_ref() {
547            crate::snapshot_v2::notify_apply_observers(
548                std::slice::from_ref(modified),
549                record.snapshot_id(),
550            );
551        }
552        drop(cleared);
553    }
554
555    fn begin_child_write(
556        &self,
557        snapshot: &AnySnapshot,
558        snapshot_id: SnapshotId,
559        invalid: &SnapshotIdSet,
560        written: Option<Rc<dyn StateObject>>,
561    ) -> Rc<StateRecord> {
562        if let Some(state) = written {
563            snapshot.record_write(state);
564        }
565        mark_update_write(self.id);
566        self.writable_record(snapshot_id, invalid)
567    }
568
569    fn writable_record(&self, snapshot_id: SnapshotId, invalid: &SnapshotIdSet) -> Rc<StateRecord> {
570        let Some(readable) = self.records.readable(snapshot_id, invalid) else {
571            let cloned_value = self
572                .records
573                .head()
574                .cloned_value()
575                .unwrap_or_else(|| panic!("StateRecord value missing or wrong type"));
576            let new_head = StateRecord::with_boxed(snapshot_id, cloned_value);
577            self.records.prepend(Rc::clone(&new_head));
578            self.assert_chain_integrity("writable_record(recover)", Some(snapshot_id));
579            return new_head;
580        };
581
582        if readable.snapshot_id() == snapshot_id {
583            return readable;
584        }
585
586        let overwritable = self.records.overwritable();
587        if let Err(error) = overwritable.assign_value(&readable) {
588            log::error!(
589                "snapshot writable record could not copy the readable value for state {:?}: {:?}",
590                self.id,
591                error
592            );
593        }
594        overwritable.set_snapshot_id(snapshot_id);
595        overwritable.set_tombstone(false);
596
597        self.assert_chain_integrity("writable_record(reuse)", Some(snapshot_id));
598
599        overwritable
600    }
601}
602
603// The steps of a write that depend on the state's value type; `write_value`
604// takes the rest, compiled once for every state type.
605trait PendingWrite {
606    // Whether `record` holds a value the state's policy deems the new one.
607    fn matches(&self, record: &StateRecord) -> bool;
608    // Moves the new value into `record` and keeps the value it displaced, to
609    // drop once the write is published.
610    fn store(&mut self, record: &StateRecord);
611    // The state written, for the snapshots to report.
612    fn written(&self) -> Option<Rc<dyn StateObject>>;
613}
614
615struct TypedWrite<'a, T> {
616    state: &'a SnapshotMutableState<T>,
617    value: Option<T>,
618    displaced: Option<T>,
619}
620
621impl<T: Clone + 'static> PendingWrite for TypedWrite<'_, T> {
622    fn matches(&self, record: &StateRecord) -> bool {
623        self.value.as_ref().is_some_and(|value| {
624            record.with_value(|current: &T| self.state.policy.equivalent(current, value))
625        })
626    }
627
628    fn store(&mut self, record: &StateRecord) {
629        if let Some(value) = self.value.take() {
630            self.displaced = record.replace_value(value);
631        }
632    }
633
634    fn written(&self) -> Option<Rc<dyn StateObject>> {
635        self.state.written_state()
636    }
637}
638
639// Writes the value `write` holds to the state `target` names, in the active
640// snapshot, and returns whether it changed the value that snapshot reads.
641// Out of line, one function for every state type.
642#[inline(never)]
643fn write_value(target: &WriteTarget<'_>, write: &mut dyn PendingWrite) -> bool {
644    #[cfg(debug_assertions)]
645    {
646        let in_handler = crate::in_event_handler();
647        let in_snapshot = crate::in_applied_snapshot();
648        if in_handler && !in_snapshot {
649            log::warn!(
650                target: "cranpose::state",
651                "State modified in event handler without run_in_mutable_snapshot; \
652                 this can make updates invisible to other contexts. Wrap the handler \
653                 in run_in_mutable_snapshot() or dispatch_ui_event(). State: {:?}",
654                target.id
655            );
656        }
657    }
658
659    let snapshot = active_snapshot();
660    let snapshot_id = snapshot.snapshot_id();
661    let readable_for =
662        |snapshot_id, invalid: &SnapshotIdSet| target.records.readable(snapshot_id, invalid);
663
664    match &snapshot {
665        AnySnapshot::Global(global) => {
666            let readable = snapshot.with_invalid(|invalid| readable_for(snapshot_id, invalid));
667            if readable
668                .as_deref()
669                .is_some_and(|record| write.matches(record))
670            {
671                return false;
672            }
673            target.begin_global_write(global, snapshot_id);
674            // A record the global snapshot wrote at its current id is
675            // seen by no other snapshot: one taken since would have moved
676            // the global to a new id. The write replaces its value there,
677            // as Compose overwrites the record of the snapshot it writes.
678            if let Some(record) = readable.filter(|record| record.snapshot_id() == snapshot_id) {
679                write.store(&record);
680                target.finish_global_write(&record, write.written(), snapshot_id);
681            } else {
682                let (record, new_id) = target.push_global_record();
683                write.store(&record);
684                target.publish_global_record(&record, new_id, snapshot_id);
685                target.finish_global_write(&record, write.written(), snapshot_id);
686            }
687        }
688        AnySnapshot::Mutable(_)
689        | AnySnapshot::NestedMutable(_)
690        | AnySnapshot::TransparentMutable(_) => {
691            let invalid = snapshot.invalid();
692            if readable_for(snapshot_id, &invalid)
693                .as_deref()
694                .is_some_and(|record| write.matches(record))
695            {
696                return false;
697            }
698            let record =
699                target.begin_child_write(&snapshot, snapshot_id, &invalid, write.written());
700            write.store(&record);
701            target.assert_chain_integrity("set(child-writable)", Some(snapshot_id));
702        }
703        AnySnapshot::Readonly(_)
704        | AnySnapshot::NestedReadonly(_)
705        | AnySnapshot::TransparentReadonly(_) => {
706            panic!("Cannot write to a read-only snapshot");
707        }
708    }
709
710    true
711}
712
713fn should_check_chain_integrity() -> bool {
714    #[cfg(debug_assertions)]
715    {
716        true
717    }
718
719    #[cfg(not(debug_assertions))]
720    {
721        crate::DIAGNOSTICS.assert_state_chain.is_set()
722    }
723}
724
725impl<T: Clone + 'static> SnapshotMutableState<T> {
726    fn readable_record_for_active_snapshot(&self) -> Result<Rc<StateRecord>, StateReadFailure> {
727        readable_record_for_active_snapshot(ReadNotice::Observers(self), &self.records, self.id)
728    }
729
730    fn readable_for(
731        &self,
732        snapshot_id: SnapshotId,
733        invalid: &SnapshotIdSet,
734    ) -> Option<Rc<StateRecord>> {
735        self.records.readable(snapshot_id, invalid)
736    }
737
738    pub(crate) fn new_in_rc(initial: T, policy: Rc<dyn MutationPolicy<T>>) -> Rc<Self> {
739        let snapshot = active_snapshot();
740        let snapshot_id = snapshot.snapshot_id();
741
742        let tail = StateRecord::new(PREEXISTING_SNAPSHOT_ID, initial.clone());
743        let head = StateRecord::new(snapshot_id, initial);
744
745        Rc::new_cyclic(|weak_self| Self {
746            records: RecordChain::new(smallvec![head, tail]),
747            policy,
748            id: ObjectId(weak_self.as_ptr() as usize),
749            weak_self: Weak::clone(weak_self),
750            apply_observer: OnceCell::new(),
751            subscribers: Subscribers::default(),
752        })
753    }
754
755    pub(crate) fn set_apply_observer(&self, observer: Box<dyn Fn() + 'static>) {
756        assert!(
757            self.apply_observer.set(observer).is_ok(),
758            "state observer already installed"
759        );
760    }
761
762    fn finish_apply(&self, caller: &str, snapshot_id: SnapshotId) {
763        finish_apply(
764            &self.apply_observer,
765            &self.records,
766            self.id,
767            caller,
768            snapshot_id,
769        );
770    }
771
772    fn upgrade_self(&self) -> Option<Rc<Self>> {
773        self.weak_self.upgrade()
774    }
775
776    fn written_state(&self) -> Option<Rc<dyn StateObject>> {
777        self.upgrade_self()
778            .map(|state| -> Rc<dyn StateObject> { state })
779    }
780
781    #[inline]
782    pub(crate) fn id(&self) -> ObjectId {
783        self.id
784    }
785
786    pub(crate) fn try_with_value<R>(&self, f: impl FnOnce(&T) -> R) -> Option<R> {
787        let record = self.readable_record_for_active_snapshot().ok()?;
788        record.try_with_value(f)
789    }
790
791    pub(crate) fn try_get(&self) -> Option<T> {
792        self.try_with_value(Clone::clone)
793    }
794
795    pub(crate) fn with_value<R>(&self, f: impl FnOnce(&T) -> R) -> R {
796        let record = self
797            .readable_record_for_active_snapshot()
798            .unwrap_or_else(|failure| panic!("{failure}"));
799        record.with_value(f)
800    }
801
802    pub(crate) fn get(&self) -> T {
803        self.with_value(Clone::clone)
804    }
805
806    pub(crate) fn set(&self, new_value: T) -> bool {
807        let target = WriteTarget {
808            records: &self.records,
809            id: self.id,
810        };
811        let mut write = TypedWrite {
812            state: self,
813            value: Some(new_value),
814            displaced: None,
815        };
816        // The value the write displaced drops with `write`, once the write
817        // is published.
818        write_value(&target, &mut write)
819    }
820
821    fn try_readable_record(
822        &self,
823        snapshot_id: SnapshotId,
824        invalid: &SnapshotIdSet,
825    ) -> Option<Rc<StateRecord>> {
826        self.readable_for(snapshot_id, invalid)
827    }
828}
829
830pub(crate) struct UpdateScope {
831    id: ObjectId,
832    finished: bool,
833}
834
835impl UpdateScope {
836    pub(crate) fn new(id: ObjectId) -> Self {
837        crate::thread_state::snapshots(|state| {
838            state.active_updates.borrow_mut().insert(id);
839            state.pending_writes.borrow_mut().remove(&id);
840        });
841        Self {
842            id,
843            finished: false,
844        }
845    }
846
847    pub(crate) fn finish(mut self) -> bool {
848        self.finished = true;
849        crate::thread_state::snapshots(|state| {
850            state.active_updates.borrow_mut().remove(&self.id);
851            state.pending_writes.borrow_mut().remove(&self.id)
852        })
853    }
854}
855
856impl Drop for UpdateScope {
857    fn drop(&mut self) {
858        if self.finished {
859            return;
860        }
861        crate::thread_state::snapshots(|state| {
862            state.active_updates.borrow_mut().remove(&self.id);
863            state.pending_writes.borrow_mut().remove(&self.id);
864        });
865    }
866}
867
868fn mark_update_write(id: ObjectId) {
869    crate::thread_state::snapshots(|state| {
870        if state.active_updates.borrow().contains(&id) {
871            state.pending_writes.borrow_mut().insert(id);
872        }
873    });
874}
875
876impl<T: Clone + 'static> StateObject for SnapshotMutableState<T> {
877    fn object_id(&self) -> ObjectId {
878        self.id
879    }
880
881    fn records(&self) -> &RecordChain {
882        &self.records
883    }
884
885    fn try_readable_record(
886        &self,
887        snapshot_id: SnapshotId,
888        invalid: &SnapshotIdSet,
889    ) -> Option<Rc<StateRecord>> {
890        self.try_readable_record(snapshot_id, invalid)
891    }
892
893    fn readable_record(&self, snapshot_id: SnapshotId, invalid: &SnapshotIdSet) -> Rc<StateRecord> {
894        self.try_readable_record(snapshot_id, invalid)
895            .unwrap_or_else(|| {
896                panic!(
897                    "SnapshotMutableState::readable_record returned null (state={:?}, snapshot_id={})",
898                    self.id, snapshot_id
899                )
900            })
901    }
902
903    fn observation_lease(&self) -> Option<Rc<dyn Any>> {
904        self.subscribers.acquire_observation_lease()
905    }
906
907    fn merge_records(
908        &self,
909        previous: Rc<StateRecord>,
910        current: Rc<StateRecord>,
911        applied: Rc<StateRecord>,
912    ) -> Option<Rc<StateRecord>> {
913        let outcome = current
914            .try_with_value(|current_value: &T| {
915                applied
916                    .try_with_value(|applied_value: &T| {
917                        if self.policy.equivalent(current_value, applied_value) {
918                            return Merge::KeepCurrent;
919                        }
920                        previous
921                            .try_with_value(|previous_value: &T| {
922                                Merge::Value(self.policy.merge(
923                                    previous_value,
924                                    current_value,
925                                    applied_value,
926                                ))
927                            })
928                            .unwrap_or(Merge::Missing("previous", &previous))
929                    })
930                    .unwrap_or(Merge::Missing("applied", &applied))
931            })
932            .unwrap_or(Merge::Missing("current", &current));
933        match outcome {
934            Merge::KeepCurrent => Some(current),
935            Merge::Value(merged) => {
936                merged.map(|value| StateRecord::new(applied.snapshot_id(), value))
937            }
938            Merge::Missing(which, record) => {
939                log_merge_value_missing(which, self.id, record);
940                None
941            }
942        }
943    }
944
945    fn promote_record(&self, child_id: SnapshotId) -> Result<(), &'static str> {
946        promote_record_locked(self, child_id, TypeId::of::<T>())?;
947        self.finish_apply("promote_record", child_id);
948        Ok(())
949    }
950
951    fn commit_merged_record(&self, merged: Rc<StateRecord>) -> Result<SnapshotId, &'static str> {
952        let new_id = commit_merged_record_locked(self, &merged, TypeId::of::<T>())?;
953        self.finish_apply("commit_merged_record", new_id);
954        Ok(new_id)
955    }
956
957    fn overwrite_unused_records(&self) -> bool {
958        self.records.overwrite_unused()
959    }
960
961    fn as_any(&self) -> &dyn Any {
962        self
963    }
964}
965
966pub(crate) struct MutableStateInner<T: Clone + 'static> {
967    pub(crate) state: Rc<SnapshotMutableState<T>>,
968    watchers: StateWatchers,
969}
970
971// The scopes that read a state and the runtime they recompose in, whatever
972// the state's value type, so that registering a reader and invalidating the
973// readers are compiled once for every state type.
974struct StateWatchers {
975    scopes: RefCell<HashMap<ScopeId, Weak<RecomposeScopeInner>>>,
976    runtime: RuntimeHandle,
977    state_id: Cell<Option<StateId>>,
978}
979
980fn notify_subscriber_callbacks(callbacks: &RefCell<Vec<Rc<dyn Fn()>>>) {
981    let registered = callbacks.borrow().len();
982    for index in 0..registered {
983        let callback = callbacks.borrow().get(index).map(Rc::clone);
984        if let Some(callback) = callback {
985            callback();
986        }
987    }
988}
989
990fn shrink_watchers_if_sparse(watchers: &mut HashMap<ScopeId, Weak<RecomposeScopeInner>>) {
991    let len = watchers.len();
992    let capacity = watchers.capacity();
993    if capacity > len.saturating_mul(4).max(32) {
994        watchers.shrink_to_fit();
995    }
996}
997
998// What a state's apply observer runs: invalidates the scopes that read the
999// state, on the UI thread. The arena finds the readers by the state's id, so
1000// the closure is one function for every state type.
1001fn watcher_invalidation(runtime: RuntimeHandle, state_id: StateId) -> Box<dyn Fn()> {
1002    Box::new(move || {
1003        let ui_runtime = runtime.clone();
1004        runtime.enqueue_ui_task(Box::new(move || {
1005            ui_runtime.with_state_arena(|arena| arena.invalidate_watchers(state_id));
1006        }));
1007    })
1008}
1009
1010impl<T: Clone + 'static> MutableStateInner<T> {
1011    pub(crate) fn new_with_policy(
1012        value: T,
1013        runtime: RuntimeHandle,
1014        policy: Rc<dyn MutationPolicy<T>>,
1015    ) -> Self {
1016        Self {
1017            state: SnapshotMutableState::new_in_rc(value, policy),
1018            watchers: StateWatchers {
1019                scopes: RefCell::new(HashMap::default()),
1020                runtime,
1021                state_id: Cell::new(None),
1022            },
1023        }
1024    }
1025
1026    pub(crate) fn install_snapshot_observer(&self, state_id: StateId) {
1027        self.watchers.state_id.set(Some(state_id));
1028        self.state.set_apply_observer(watcher_invalidation(
1029            self.watchers.runtime.clone(),
1030            state_id,
1031        ));
1032    }
1033
1034    fn has_subscribers(&self) -> bool {
1035        self.watchers.has_subscribers(&self.state.subscribers)
1036    }
1037
1038    /// Removes the live scope `scope_id` from the watchers: its last body did
1039    /// not read the state.
1040    pub(crate) fn forget_scope(&self, scope_id: ScopeId) {
1041        self.watchers
1042            .forget_scope(&self.state.subscribers, scope_id);
1043    }
1044
1045    pub(crate) fn unregister_scope(&self, scope_id: ScopeId) {
1046        self.watchers
1047            .unregister_scope(&self.state.subscribers, scope_id);
1048    }
1049
1050    pub(crate) fn invalidate_watchers(&self) {
1051        self.watchers
1052            .invalidate(&self.state.subscribers, std::any::type_name::<T>());
1053    }
1054
1055    // Subscribes the scope that is composing to this state.
1056    fn register_current_scope(&self) {
1057        register_current_state_scope(&self.watchers, &self.state.subscribers);
1058    }
1059}
1060
1061impl StateWatchers {
1062    /// Adds `scope` to the state's watchers, saying whether it was new and
1063    /// whether the state thereby gained its first subscriber.
1064    ///
1065    /// Dead watchers still count as subscribers until pruned. They are
1066    /// pruned whenever no live one is left, so a reader arriving after every
1067    /// earlier one died still makes the state newly subscribed, and
1068    /// otherwise only when the map is full, before the insert would grow
1069    /// it: a state read by thousands of scopes, such as the density, must
1070    /// not scan them all for every new reader.
1071    fn register_scope(&self, subscribers: &Subscribers, scope: &RecomposeScope) -> (bool, bool) {
1072        let mut watchers = self.scopes.borrow_mut();
1073        let id = scope.id();
1074        match watchers.get(&id) {
1075            Some(existing) if existing.strong_count() > 0 => return (false, false),
1076            Some(_) => {
1077                watchers.remove(&id);
1078                subscribers.remove_scope_observers(1);
1079            }
1080            None => {}
1081        }
1082        let any_live = watchers.values().any(|watcher| watcher.strong_count() > 0);
1083        if !any_live || watchers.len() >= watchers.capacity() {
1084            let before = watchers.len();
1085            watchers.retain(|_, watcher| watcher.strong_count() > 0);
1086            subscribers.remove_scope_observers(before - watchers.len());
1087        }
1088        watchers.insert(id, scope.downgrade());
1089        drop(watchers);
1090        (true, subscribers.add_scope_observer())
1091    }
1092
1093    fn has_subscribers(&self, subscribers: &Subscribers) -> bool {
1094        let mut watchers = self.scopes.borrow_mut();
1095        let before = watchers.len();
1096        watchers.retain(|_, existing| existing.upgrade().is_some());
1097        subscribers.remove_scope_observers(before - watchers.len());
1098        subscribers.has_subscribers()
1099    }
1100
1101    fn forget_scope(&self, subscribers: &Subscribers, scope_id: ScopeId) {
1102        let mut watchers = self.scopes.borrow_mut();
1103        let removed = watchers.remove(&scope_id).is_some();
1104        if removed {
1105            shrink_watchers_if_sparse(&mut watchers);
1106        }
1107        drop(watchers);
1108        subscribers.remove_scope_observers(usize::from(removed));
1109    }
1110
1111    fn unregister_scope(&self, subscribers: &Subscribers, scope_id: ScopeId) {
1112        let mut watchers = self.scopes.borrow_mut();
1113        let removed = if watchers
1114            .get(&scope_id)
1115            .is_some_and(|weak| weak.upgrade().is_none())
1116        {
1117            watchers.remove(&scope_id);
1118            shrink_watchers_if_sparse(&mut watchers);
1119            true
1120        } else {
1121            false
1122        };
1123        drop(watchers);
1124        subscribers.remove_scope_observers(usize::from(removed));
1125    }
1126
1127    // Invalidates the live scopes that read the state, whose value type is
1128    // named `type_name`, and drops the dead ones.
1129    fn invalidate(&self, subscribers: &Subscribers, type_name: &'static str) {
1130        // A state has few watchers: their copy stays inline.
1131        let (watchers, removed_count): (SmallVec<[RecomposeScope; 4]>, usize) = {
1132            let mut watchers = self.scopes.borrow_mut();
1133            let before = watchers.len();
1134            let mut live = SmallVec::new();
1135            watchers.retain(|_, scope| {
1136                if let Some(inner) = scope.upgrade() {
1137                    live.push(RecomposeScope { inner });
1138                    true
1139                } else {
1140                    false
1141                }
1142            });
1143            let removed_count = before - watchers.len();
1144            shrink_watchers_if_sparse(&mut watchers);
1145            (live, removed_count)
1146        };
1147        subscribers.remove_scope_observers(removed_count);
1148
1149        for watcher in watchers {
1150            debug_record_scope_invalidation(watcher.id(), self.state_id.get(), type_name);
1151            if let Some(state_id) = self.state_id.get() {
1152                watcher.invalidate_from_state(state_id);
1153            } else {
1154                watcher.invalidate();
1155            }
1156        }
1157    }
1158}
1159
1160impl<T: Clone + 'static> Drop for MutableStateInner<T> {
1161    fn drop(&mut self) {
1162        self.state
1163            .subscribers
1164            .remove_scope_observers(self.watchers.scopes.get_mut().len());
1165    }
1166}
1167
1168// Out of line, one function for every state type: each read of a state
1169// registers its reader here.
1170#[inline(never)]
1171fn register_current_state_scope(watchers: &StateWatchers, subscribers: &Subscribers) {
1172    let state_id = watchers.state_id.get();
1173    let Some(Some((scope, read))) =
1174        with_current_composer_opt(|composer| composer.note_state_read(state_id))
1175    else {
1176        return;
1177    };
1178    let (registered, became_subscribed) = watchers.register_scope(subscribers, &scope);
1179    if let (crate::ScopeRead::NotReading, true, Some(state_id)) = (read, registered, state_id) {
1180        scope.record_state_subscription(state_id);
1181    }
1182    if became_subscribed {
1183        subscribers.notify_subscribers();
1184    }
1185}
1186
1187trait StateArenaHandle<T: Clone + 'static> {
1188    fn state_id(&self) -> StateId;
1189    fn runtime_id(&self) -> runtime::RuntimeId;
1190
1191    fn runtime_handle(&self) -> RuntimeHandle {
1192        runtime::runtime_handle_by_id(self.runtime_id())
1193            .unwrap_or_else(|| panic!("runtime {:?} dropped", self.runtime_id()))
1194    }
1195
1196    fn runtime_handle_opt(&self) -> Option<RuntimeHandle> {
1197        runtime::runtime_handle_by_id(self.runtime_id())
1198    }
1199
1200    fn with_inner<R>(&self, f: impl FnOnce(&MutableStateInner<T>) -> R) -> R {
1201        runtime::with_state_arena_by_id(self.runtime_id(), |arena| {
1202            arena.with_typed::<T, R>(self.state_id(), f)
1203        })
1204        .unwrap_or_else(|| panic!("runtime {:?} dropped", self.runtime_id()))
1205    }
1206
1207    fn try_with_inner<R>(&self, f: impl FnOnce(&MutableStateInner<T>) -> R) -> Option<R> {
1208        runtime::with_state_arena_by_id(self.runtime_id(), |arena| {
1209            arena.with_typed_opt::<T, R>(self.state_id(), f)
1210        })?
1211    }
1212
1213    fn read_subscribed<R>(&self, read: impl FnOnce(&MutableStateInner<T>) -> R) -> R {
1214        self.with_inner(|inner| {
1215            let result = read(inner);
1216            inner.register_current_scope();
1217            result
1218        })
1219    }
1220}
1221
1222/// Cheap copyable read-only view of a state cell.
1223pub struct State<T: Clone + 'static> {
1224    id: StateId,
1225    runtime_id: runtime::RuntimeId,
1226    /// The cell holds a derived state's value, which a read brings up to
1227    /// date first.
1228    derived: bool,
1229    _marker: PhantomData<fn() -> T>,
1230}
1231
1232/// Cheap copyable mutable view of a state cell.
1233///
1234/// Ownership lives elsewhere: a composition slot, an [`OwnedMutableState`], or
1235/// the runtime for states created with [`crate::mutableStateOf`] /
1236/// [`MutableState::with_runtime`].
1237pub struct MutableState<T: Clone + 'static> {
1238    id: StateId,
1239    runtime_id: runtime::RuntimeId,
1240    _marker: PhantomData<fn() -> T>,
1241}
1242
1243/// Owning state handle for reclaimable state cells.
1244#[derive(Clone)]
1245pub struct OwnedMutableState<T: Clone + 'static> {
1246    state: MutableState<T>,
1247    _lease: Rc<runtime::StateHandleLease>,
1248    _marker: PhantomData<fn() -> T>,
1249}
1250
1251impl<T: Clone + 'static> PartialEq for State<T> {
1252    fn eq(&self, other: &Self) -> bool {
1253        self.state_id() == other.state_id() && self.runtime_id() == other.runtime_id()
1254    }
1255}
1256
1257impl<T: Clone + 'static> Eq for State<T> {}
1258
1259impl<T: Clone + 'static> PartialEq for MutableState<T> {
1260    fn eq(&self, other: &Self) -> bool {
1261        self.state_id() == other.state_id() && self.runtime_id() == other.runtime_id()
1262    }
1263}
1264
1265/// Two owning handles are equal when they hold the same state, as two
1266/// [`MutableState`] handles are.
1267impl<T: Clone + 'static> PartialEq for OwnedMutableState<T> {
1268    fn eq(&self, other: &Self) -> bool {
1269        self.state == other.state
1270    }
1271}
1272
1273impl<T: Clone + 'static> Eq for MutableState<T> {}
1274
1275impl<T: Clone + 'static> Copy for State<T> {}
1276
1277impl<T: Clone + 'static> Clone for State<T> {
1278    fn clone(&self) -> Self {
1279        *self
1280    }
1281}
1282
1283impl<T: Clone + 'static> Copy for MutableState<T> {}
1284
1285impl<T: Clone + 'static> Clone for MutableState<T> {
1286    fn clone(&self) -> Self {
1287        *self
1288    }
1289}
1290
1291impl<T: Clone + 'static> StateArenaHandle<T> for State<T> {
1292    fn state_id(&self) -> StateId {
1293        self.id
1294    }
1295
1296    fn runtime_id(&self) -> runtime::RuntimeId {
1297        self.runtime_id
1298    }
1299}
1300
1301impl<T: Clone + 'static> State<T> {
1302    /// Returns `true` while the state exists. It ends when its owner releases it or its runtime is
1303    /// dropped.
1304    pub fn is_alive(&self) -> bool {
1305        self.try_with_inner(|_| ()).is_some()
1306    }
1307
1308    /// Reads the value through `f` without subscribing the current scope. Returns `None` if the
1309    /// state was released or has no readable value.
1310    pub fn try_with<R>(&self, f: impl FnOnce(&T) -> R) -> Option<R> {
1311        self.try_with_fresh_inner(|inner| inner.state.try_with_value(f))?
1312    }
1313
1314    /// Returns a copy of the value without subscribing the current scope, or `None` if the state
1315    /// was released or has no readable value.
1316    pub fn try_value(&self) -> Option<T> {
1317        self.try_with_fresh_inner(|inner| inner.state.try_get())?
1318    }
1319
1320    /// Reads a copy of the value through `f` and subscribes the current
1321    /// scope. `f` may write this state; see [`Self::read`] for a read that
1322    /// borrows instead of copying.
1323    pub fn with<R>(&self, f: impl FnOnce(&T) -> R) -> R {
1324        let value = self.read_fresh_subscribed(|inner| inner.state.get());
1325        f(&value)
1326    }
1327
1328    /// Reads the value in place through `f` and subscribes the current
1329    /// scope. Nothing is cloned, so a read of a large value costs nothing
1330    /// beyond `f`; in return `f` borrows the stored value and must not write
1331    /// this state.
1332    pub fn read<R>(&self, f: impl FnOnce(&T) -> R) -> R {
1333        self.read_fresh_subscribed(|inner| inner.state.with_value(f))
1334    }
1335
1336    /// Returns a copy of the value and subscribes the current scope, which recomposes when the
1337    /// value changes. Panics if the state was released.
1338    pub fn value(&self) -> T {
1339        self.read_fresh_subscribed(|inner| inner.state.get())
1340    }
1341
1342    /// Same as `value`.
1343    pub fn get(&self) -> T {
1344        self.value()
1345    }
1346
1347    /// Reads the value without subscribing the current scope or telling a
1348    /// read observer, for a composition that shows it only through a layer
1349    /// or a draw that reads it again.
1350    pub fn get_non_reactive(&self) -> T {
1351        self.with_fresh_inner(|inner| inner.state.value_unobserved())
1352    }
1353
1354    /// The view a derived state hands out of its cell.
1355    fn of_derived(self) -> Self {
1356        Self {
1357            derived: true,
1358            ..self
1359        }
1360    }
1361
1362    /// Runs `f` on the cell, a derived state's once its value is up to date:
1363    /// a read derives the value again when a state it read changed since
1364    /// its derivation last ran, as Compose's `derivedStateOf` does. A plain
1365    /// state's read pays one branch. Panics if the state was released.
1366    fn with_fresh_inner<R>(&self, f: impl FnOnce(&MutableStateInner<T>) -> R) -> R {
1367        runtime::with_state_arena_by_id(self.runtime_id, |arena| {
1368            if self.derived {
1369                arena.refresh_derived(self.id);
1370            }
1371            arena.with_typed::<T, R>(self.id, f)
1372        })
1373        .unwrap_or_else(|| panic!("runtime {:?} dropped", self.runtime_id))
1374    }
1375
1376    /// [`Self::with_fresh_inner`], or `None` if the state was released.
1377    fn try_with_fresh_inner<R>(&self, f: impl FnOnce(&MutableStateInner<T>) -> R) -> Option<R> {
1378        runtime::with_state_arena_by_id(self.runtime_id, |arena| {
1379            if self.derived {
1380                arena.refresh_derived(self.id);
1381            }
1382            arena.with_typed_opt::<T, R>(self.id, f)
1383        })?
1384    }
1385
1386    /// Reads the up-to-date cell through `read` and subscribes the current
1387    /// scope.
1388    fn read_fresh_subscribed<R>(&self, read: impl FnOnce(&MutableStateInner<T>) -> R) -> R {
1389        self.with_fresh_inner(|inner| {
1390            let result = read(inner);
1391            inner.register_current_scope();
1392            result
1393        })
1394    }
1395
1396    /// Returns `true` if any scope or observer is subscribed to this state.
1397    pub fn has_subscribers(&self) -> bool {
1398        self.with_inner(MutableStateInner::has_subscribers)
1399    }
1400
1401    /// Runs `callback` each time this state gains its first subscriber, and
1402    /// right away when it already has one.
1403    ///
1404    /// The state owns `callback` for as long as the state lives, so nothing
1405    /// has to be kept alive on the caller's side.
1406    pub fn on_subscriber(&self, callback: impl Fn() + 'static) {
1407        let callback: Rc<dyn Fn()> = Rc::new(callback);
1408        self.with_inner(|inner| {
1409            inner
1410                .state
1411                .subscribers
1412                .subscriber_callback(callback, inner.has_subscribers());
1413        });
1414    }
1415
1416    /// Counts this state as subscribed for as long as the returned guard
1417    /// lives, without observing it from any scope.
1418    ///
1419    /// Snapshot observers subscribe reads made under composition or the
1420    /// draw phase, and producers gated on [`State::has_subscribers`] — an
1421    /// infinite transition, for one — stop themselves when the last such
1422    /// subscriber leaves. A consumer that reads the value from a polling
1423    /// context (a frame effect stepping it into a derived state, a
1424    /// background task) is invisible to that accounting and would starve
1425    /// the producer it depends on. Holding this guard keeps the producer
1426    /// alive; dropping it releases the count.
1427    pub fn subscription_hold(&self) -> StateSubscriptionHold {
1428        StateSubscriptionHold {
1429            _lease: self
1430                .try_with_inner(|inner| inner.state.observation_lease())
1431                .flatten(),
1432        }
1433    }
1434}
1435
1436/// Keeps a [`State`] counted as subscribed while alive; see
1437/// [`State::subscription_hold`].
1438pub struct StateSubscriptionHold {
1439    _lease: Option<Rc<dyn Any>>,
1440}
1441
1442impl<T: Clone + 'static> StateArenaHandle<T> for MutableState<T> {
1443    fn state_id(&self) -> StateId {
1444        self.id
1445    }
1446
1447    fn runtime_id(&self) -> runtime::RuntimeId {
1448        self.runtime_id
1449    }
1450}
1451
1452// Why a write to `state_id` of `runtime_id` stored nothing: its runtime
1453// was dropped, or the runtime lives and the state was released. Out of line,
1454// one function for every state type.
1455#[cold]
1456#[inline(never)]
1457fn log_skipped_replace(runtime_id: runtime::RuntimeId, state_id: StateId, runtime_alive: bool) {
1458    if runtime_alive {
1459        log::debug!(
1460            "MutableState::replace skipped: state cell released (slot={}, gen={})",
1461            state_id.slot(),
1462            state_id.generation(),
1463        );
1464    } else {
1465        log::debug!("MutableState::replace skipped: runtime {runtime_id:?} dropped");
1466    }
1467}
1468
1469impl<T: Clone + 'static> MutableState<T> {
1470    /// Creates a state holding `value` in `runtime`. Every write counts as a change, even of an
1471    /// equal value. Unless a `remember` owns the state, the runtime keeps it for its own lifetime.
1472    pub fn with_runtime(value: T, runtime: RuntimeHandle) -> Self {
1473        runtime.alloc_persistent_state(value)
1474    }
1475
1476    fn from_parts(id: StateId, runtime_id: runtime::RuntimeId) -> Self {
1477        Self {
1478            id,
1479            runtime_id,
1480            _marker: PhantomData,
1481        }
1482    }
1483
1484    pub(crate) fn from_lease(lease: &Rc<runtime::StateHandleLease>) -> Self {
1485        Self::from_parts(lease.id(), lease.runtime_id())
1486    }
1487
1488    /// Returns `true` while the state exists. It ends when its owner releases it or its runtime is
1489    /// dropped.
1490    pub fn is_alive(&self) -> bool {
1491        self.try_with_inner(|_| ()).is_some()
1492    }
1493
1494    /// Reads the value through `f` without subscribing the current scope. Returns `None` if the
1495    /// state was released or has no readable value.
1496    pub fn try_with<R>(&self, f: impl FnOnce(&T) -> R) -> Option<R> {
1497        self.try_with_inner(|inner| inner.state.try_with_value(f))?
1498    }
1499
1500    /// Returns a copy of the value without subscribing the current scope, or `None` if the state
1501    /// was released or has no readable value.
1502    pub fn try_value(&self) -> Option<T> {
1503        self.try_with_inner(|inner| inner.state.try_get())?
1504    }
1505
1506    /// Returns a read-only view of this state.
1507    pub fn as_state(&self) -> State<T> {
1508        State {
1509            id: self.id,
1510            runtime_id: self.runtime_id,
1511            derived: false,
1512            _marker: PhantomData,
1513        }
1514    }
1515
1516    /// Returns an [`OwnedMutableState`] that keeps this state alive until its last clone is
1517    /// dropped. Returns `None` if the state was already released.
1518    pub fn try_retain(&self) -> Option<OwnedMutableState<T>> {
1519        let lease = self
1520            .runtime_handle_opt()?
1521            .retain_state_lease(self.state_id())?;
1522        Some(OwnedMutableState {
1523            state: *self,
1524            _lease: lease,
1525            _marker: PhantomData,
1526        })
1527    }
1528
1529    /// Returns an [`OwnedMutableState`] that keeps this state alive until its last clone is
1530    /// dropped. Panics if the state was released.
1531    pub fn retain(&self) -> OwnedMutableState<T> {
1532        self.try_retain()
1533            .unwrap_or_else(|| panic!("state {:?} is no longer alive", self.state_id()))
1534    }
1535
1536    /// Reads a copy of the value through `f` and subscribes the current
1537    /// scope. `f` may write this state; see [`Self::read`] for a read that
1538    /// borrows instead of copying.
1539    pub fn with<R>(&self, f: impl FnOnce(&T) -> R) -> R {
1540        let value = self.read_subscribed(|inner| inner.state.get());
1541        f(&value)
1542    }
1543
1544    /// Reads the value in place through `f` and subscribes the current
1545    /// scope. Nothing is cloned, so a read of a large value costs nothing
1546    /// beyond `f`; in return `f` borrows the stored value and must not write
1547    /// this state.
1548    pub fn read<R>(&self, f: impl FnOnce(&T) -> R) -> R {
1549        self.read_subscribed(|inner| inner.state.with_value(f))
1550    }
1551
1552    /// Runs `f` on a copy of the value and stores the copy, unless `f` wrote this state itself.
1553    /// Scopes that read the state are notified if the value changed.
1554    pub fn update<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
1555        let runtime = self.runtime_handle();
1556        runtime.assert_ui_thread();
1557        runtime.with_state_arena(|arena| {
1558            arena.with_typed::<T, R>(self.state_id(), |inner| {
1559                let mut value = inner.state.get();
1560                let tracker = UpdateScope::new(inner.state.id());
1561                let result = f(&mut value);
1562                let wrote_elsewhere = tracker.finish();
1563                if !wrote_elsewhere && inner.state.set(value) {
1564                    inner.invalidate_watchers();
1565                }
1566                result
1567            })
1568        })
1569    }
1570
1571    /// Stores `value` and notifies the scopes that read the state, if the state's equality policy
1572    /// sees a change. Does nothing if the state was released.
1573    pub fn replace(&self, value: T) {
1574        // The runtimes this thread finds are its own, so a write found here
1575        // is on the runtime's UI thread.
1576        let replaced = runtime::with_state_arena_by_id(self.runtime_id(), |arena| {
1577            arena.with_typed_opt::<T, ()>(self.state_id(), |inner| {
1578                if inner.state.set(value) {
1579                    inner.invalidate_watchers();
1580                }
1581            })
1582        });
1583        if replaced != Some(Some(())) {
1584            log_skipped_replace(self.runtime_id(), self.state_id(), replaced.is_some());
1585        }
1586    }
1587
1588    /// Same as `replace`.
1589    pub fn set_value(&self, value: T) {
1590        self.replace(value);
1591    }
1592
1593    /// Same as `replace`.
1594    pub fn set(&self, value: T) {
1595        self.replace(value);
1596    }
1597
1598    /// Returns a copy of the value and subscribes the current scope, which recomposes when the
1599    /// value changes. Panics if the state was released.
1600    pub fn value(&self) -> T {
1601        self.read_subscribed(|inner| inner.state.get())
1602    }
1603
1604    /// Same as `value`.
1605    pub fn get(&self) -> T {
1606        self.value()
1607    }
1608
1609    /// Returns a copy of the value without subscribing a scope or observer.
1610    pub fn get_non_reactive(&self) -> T {
1611        self.with_inner(|inner| inner.state.value_unobserved())
1612    }
1613
1614    #[doc(hidden)]
1615    pub fn runtime_state_id(&self) -> StateId {
1616        self.state_id()
1617    }
1618
1619    #[doc(hidden)]
1620    pub fn subscribe_current_scope_only(&self) {
1621        self.subscribe_current_scope();
1622    }
1623
1624    fn subscribe_current_scope(&self) {
1625        self.with_inner(MutableStateInner::register_current_scope);
1626    }
1627
1628    #[cfg(test)]
1629    pub(crate) fn watcher_count(&self) -> usize {
1630        self.with_inner(|inner| inner.watchers.scopes.borrow().len())
1631    }
1632
1633    #[cfg(test)]
1634    pub(crate) fn watcher_capacity(&self) -> usize {
1635        self.with_inner(|inner| inner.watchers.scopes.borrow().capacity())
1636    }
1637
1638    #[cfg(test)]
1639    pub(crate) fn state_id_for_test(&self) -> StateId {
1640        self.state_id()
1641    }
1642
1643    #[cfg(test)]
1644    pub(crate) fn subscribe_scope_for_test(&self, scope: &RecomposeScope) {
1645        self.as_state().subscribe_scope_for_test(scope);
1646    }
1647}
1648
1649impl<T: Clone + 'static> OwnedMutableState<T> {
1650    /// Creates a state holding `value` in `runtime`. The state is released when the last clone of
1651    /// this handle is dropped. Every write counts as a change, even of an equal value.
1652    pub fn with_runtime(value: T, runtime: RuntimeHandle) -> Self {
1653        let lease = runtime.alloc_state(value);
1654        Self {
1655            state: MutableState::from_lease(&lease),
1656            _lease: lease,
1657            _marker: PhantomData,
1658        }
1659    }
1660
1661    /// Creates a state holding `value` in `runtime`. Writing a value equal to the current one is
1662    /// not a change.
1663    pub fn with_runtime_structural_eq(value: T, runtime: RuntimeHandle) -> Self
1664    where
1665        T: PartialEq,
1666    {
1667        Self::with_runtime_and_policy(value, runtime, Rc::new(StructuralEqual))
1668    }
1669
1670    pub(crate) fn with_runtime_and_policy(
1671        value: T,
1672        runtime: RuntimeHandle,
1673        policy: Rc<dyn MutationPolicy<T>>,
1674    ) -> Self {
1675        let lease = runtime.alloc_state_with_policy(value, policy);
1676        Self {
1677            state: MutableState::from_lease(&lease),
1678            _lease: lease,
1679            _marker: PhantomData,
1680        }
1681    }
1682
1683    /// Returns the copyable [`MutableState`] handle. It does not keep the state alive.
1684    pub fn handle(&self) -> MutableState<T> {
1685        self.state
1686    }
1687
1688    /// Returns a read-only view of the state.
1689    pub fn as_state(&self) -> State<T> {
1690        self.state.as_state()
1691    }
1692}
1693
1694impl<T: Clone + 'static> Deref for OwnedMutableState<T> {
1695    type Target = MutableState<T>;
1696
1697    fn deref(&self) -> &Self::Target {
1698        &self.state
1699    }
1700}
1701
1702#[cfg(test)]
1703impl<T: Clone + 'static> State<T> {
1704    pub(crate) fn subscribe_scope_for_test(&self, scope: &RecomposeScope) {
1705        self.with_inner(|inner| {
1706            let (registered, became_subscribed) = inner
1707                .watchers
1708                .register_scope(&inner.state.subscribers, scope);
1709            if registered {
1710                if let Some(state_id) = inner.watchers.state_id.get() {
1711                    scope.record_state_subscription(state_id);
1712                }
1713                if became_subscribed {
1714                    inner.state.subscribers.notify_subscribers();
1715                }
1716            }
1717        });
1718    }
1719}
1720
1721impl<T: fmt::Debug + Clone + 'static> fmt::Debug for MutableState<T> {
1722    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1723        if let Some(value) = self.try_value() {
1724            f.debug_struct("MutableState")
1725                .field("value", &value)
1726                .finish()
1727        } else {
1728            f.write_str("MutableState { value: <unavailable> }")
1729        }
1730    }
1731}
1732
1733/// A hash map whose reads subscribe the current scope and whose writes notify its readers, as
1734/// Jetpack Compose's `SnapshotStateMap`. Clones share the same map.
1735#[derive(Clone)]
1736pub struct SnapshotStateMap<K, V>
1737where
1738    K: Clone + Eq + Hash + 'static,
1739    V: Clone + 'static,
1740{
1741    state: OwnedMutableState<HashMap<K, V>>,
1742}
1743
1744impl<K, V> SnapshotStateMap<K, V>
1745where
1746    K: Clone + Eq + Hash + 'static,
1747    V: Clone + 'static,
1748{
1749    /// Creates a map holding `pairs` in `runtime`.
1750    pub fn with_runtime<I>(pairs: I, runtime: RuntimeHandle) -> Self
1751    where
1752        I: IntoIterator<Item = (K, V)>,
1753    {
1754        let map: HashMap<K, V> = pairs.into_iter().collect();
1755        Self {
1756            state: OwnedMutableState::with_runtime(map, runtime),
1757        }
1758    }
1759
1760    /// Returns a read-only view of the state that holds the map.
1761    pub fn as_state(&self) -> State<HashMap<K, V>> {
1762        self.state.as_state()
1763    }
1764
1765    /// Returns the writable state that holds the map.
1766    pub fn as_mutable_state(&self) -> MutableState<HashMap<K, V>> {
1767        self.state.handle()
1768    }
1769
1770    /// Returns the number of entries.
1771    pub fn len(&self) -> usize {
1772        self.state.with(HashMap::len)
1773    }
1774
1775    /// Returns `true` if the map has no entries.
1776    pub fn is_empty(&self) -> bool {
1777        self.state.with(HashMap::is_empty)
1778    }
1779
1780    /// Returns `true` if the map has an entry for `key`.
1781    pub fn contains_key(&self, key: &K) -> bool {
1782        self.state.with(|map| map.contains_key(key))
1783    }
1784
1785    /// Returns a copy of the value under `key`, or `None` if there is none.
1786    pub fn get(&self, key: &K) -> Option<V> {
1787        self.state.with(|map| map.get(key).cloned())
1788    }
1789
1790    /// Returns a copy of the whole map.
1791    pub fn to_hash_map(&self) -> HashMap<K, V> {
1792        self.state.with(Clone::clone)
1793    }
1794
1795    /// Stores `value` under `key` and returns the value it replaced, if any.
1796    pub fn insert(&self, key: K, value: V) -> Option<V> {
1797        self.state.update(|map| map.insert(key, value))
1798    }
1799
1800    /// Inserts all pairs from `iter` in one write, replacing the values of keys already present.
1801    pub fn extend<I>(&self, iter: I)
1802    where
1803        I: IntoIterator<Item = (K, V)>,
1804    {
1805        self.state.update(|map| map.extend(iter));
1806    }
1807
1808    /// Removes the entry under `key` and returns its value, or `None` if there was none.
1809    pub fn remove(&self, key: &K) -> Option<V> {
1810        self.state.update(|map| map.remove(key))
1811    }
1812
1813    /// Removes all entries.
1814    pub fn clear(&self) {
1815        self.state.replace(HashMap::default());
1816    }
1817
1818    /// Keeps the entries for which `predicate` returns `true`. The predicate may change the values
1819    /// it keeps.
1820    pub fn retain<F>(&self, mut predicate: F)
1821    where
1822        F: FnMut(&K, &mut V) -> bool,
1823    {
1824        self.state.update(|map| map.retain(|k, v| predicate(k, v)));
1825    }
1826}
1827
1828impl<K, V> fmt::Debug for SnapshotStateMap<K, V>
1829where
1830    K: Clone + Eq + Hash + fmt::Debug + 'static,
1831    V: Clone + fmt::Debug + 'static,
1832{
1833    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1834        let contents = self.to_hash_map();
1835        f.debug_struct("SnapshotStateMap")
1836            .field("entries", &contents)
1837            .finish()
1838    }
1839}
1840
1841impl<T: fmt::Debug + Clone + 'static> fmt::Debug for State<T> {
1842    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1843        if let Some(value) = self.try_value() {
1844            f.debug_struct("State").field("value", &value).finish()
1845        } else {
1846            f.write_str("State { value: <unavailable> }")
1847        }
1848    }
1849}
1850
1851#[cfg(test)]
1852#[path = "tests/state_tests.rs"]
1853mod tests;