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