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 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 #[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 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 #[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
308pub(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
322pub(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#[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
514struct 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 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 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 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
626trait PendingWrite {
629 fn matches(&self, record: &StateRecord) -> bool;
631 fn store(&mut self, record: &StateRecord);
634 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#[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 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#[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 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", ¤t));
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
1038struct 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
1065fn 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 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 fn register_current_scope(&self) {
1124 register_current_state_scope(&self.watchers, &self.state.subscribers);
1125 }
1126}
1127
1128impl StateWatchers {
1129 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 fn invalidate(&self, subscribers: &Subscribers, type_name: &'static str) {
1197 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#[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
1289pub struct State<T: Clone + 'static> {
1291 id: StateId,
1292 runtime_id: runtime::RuntimeId,
1293 derived: bool,
1296 _marker: PhantomData<fn() -> T>,
1297}
1298
1299pub struct MutableState<T: Clone + 'static> {
1305 id: StateId,
1306 runtime_id: runtime::RuntimeId,
1307 _marker: PhantomData<fn() -> T>,
1308}
1309
1310#[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
1332impl<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 pub fn is_alive(&self) -> bool {
1372 self.try_with_inner(|_| ()).is_some()
1373 }
1374
1375 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 pub fn try_value(&self) -> Option<T> {
1384 self.try_with_fresh_inner(|inner| inner.state.try_get())?
1385 }
1386
1387 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 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 pub fn value(&self) -> T {
1406 self.read_fresh_subscribed(|inner| inner.state.get())
1407 }
1408
1409 pub fn get(&self) -> T {
1411 self.value()
1412 }
1413
1414 pub fn get_non_reactive(&self) -> T {
1418 self.with_fresh_inner(|inner| inner.state.get())
1419 }
1420
1421 fn of_derived(self) -> Self {
1423 Self {
1424 derived: true,
1425 ..self
1426 }
1427 }
1428
1429 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 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 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 pub fn has_subscribers(&self) -> bool {
1465 self.with_inner(MutableStateInner::has_subscribers)
1466 }
1467
1468 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 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
1503pub 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#[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 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 pub fn is_alive(&self) -> bool {
1558 self.try_with_inner(|_| ()).is_some()
1559 }
1560
1561 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 pub fn try_value(&self) -> Option<T> {
1570 self.try_with_inner(|inner| inner.state.try_get())?
1571 }
1572
1573 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 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 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 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 pub fn read<R>(&self, f: impl FnOnce(&T) -> R) -> R {
1616 self.read_subscribed(|inner| inner.state.with_value(f))
1617 }
1618
1619 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 pub fn replace(&self, value: T) {
1641 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 pub fn set_value(&self, value: T) {
1657 self.replace(value);
1658 }
1659
1660 pub fn set(&self, value: T) {
1662 self.replace(value);
1663 }
1664
1665 pub fn value(&self) -> T {
1668 self.read_subscribed(|inner| inner.state.get())
1669 }
1670
1671 pub fn get(&self) -> T {
1673 self.value()
1674 }
1675
1676 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 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 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 pub fn handle(&self) -> MutableState<T> {
1752 self.state
1753 }
1754
1755 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#[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 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 pub fn as_state(&self) -> State<HashMap<K, V>> {
1829 self.state.as_state()
1830 }
1831
1832 pub fn as_mutable_state(&self) -> MutableState<HashMap<K, V>> {
1834 self.state.handle()
1835 }
1836
1837 pub fn len(&self) -> usize {
1839 self.state.with(HashMap::len)
1840 }
1841
1842 pub fn is_empty(&self) -> bool {
1844 self.state.with(HashMap::is_empty)
1845 }
1846
1847 pub fn contains_key(&self, key: &K) -> bool {
1849 self.state.with(|map| map.contains_key(key))
1850 }
1851
1852 pub fn get(&self, key: &K) -> Option<V> {
1854 self.state.with(|map| map.get(key).cloned())
1855 }
1856
1857 pub fn to_hash_map(&self) -> HashMap<K, V> {
1859 self.state.with(Clone::clone)
1860 }
1861
1862 pub fn insert(&self, key: K, value: V) -> Option<V> {
1864 self.state.update(|map| map.insert(key, value))
1865 }
1866
1867 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 pub fn remove(&self, key: &K) -> Option<V> {
1877 self.state.update(|map| map.remove(key))
1878 }
1879
1880 pub fn clear(&self) {
1882 self.state.replace(HashMap::default());
1883 }
1884
1885 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;