1#![doc = r"Core runtime pieces for the Cranpose experiment."]
2
3pub extern crate self as cranpose_core;
4
5pub mod composer_context;
6pub mod frame_clock;
7mod launched_effect;
8pub mod owned;
9pub mod platform;
10pub mod runtime;
11pub mod snapshot_double_index_heap;
12pub mod snapshot_id_set;
13pub mod snapshot_pinning;
14pub mod snapshot_state_observer;
15pub mod snapshot_v2;
16mod snapshot_weak_set;
17mod state;
18pub mod subcompose;
19
20pub use frame_clock::{FrameCallbackRegistration, FrameClock};
21pub use launched_effect::{
22 CancelToken, LaunchedEffectScope, __launched_effect_async_impl, __launched_effect_impl,
23};
24pub use owned::Owned;
25pub use platform::{Clock, RuntimeScheduler};
26pub use runtime::{
27 current_runtime_handle, schedule_frame, schedule_node_update, DefaultScheduler, Runtime,
28 RuntimeHandle, StateId, TaskHandle,
29};
30pub use snapshot_state_observer::SnapshotStateObserver;
31
32pub fn run_in_mutable_snapshot<T>(block: impl FnOnce() -> T) -> Result<T, &'static str> {
57 let snapshot = snapshot_v2::take_mutable_snapshot(None, None);
58
59 IN_APPLIED_SNAPSHOT.with(|c| c.set(true));
61 let value = snapshot.enter(block);
62 IN_APPLIED_SNAPSHOT.with(|c| c.set(false));
63
64 match snapshot.apply() {
65 snapshot_v2::SnapshotApplyResult::Success => Ok(value),
66 snapshot_v2::SnapshotApplyResult::Failure => Err("Snapshot apply failed"),
67 }
68}
69
70pub fn dispatch_ui_event<T>(block: impl FnOnce() -> T) -> Option<T> {
85 run_in_mutable_snapshot(block).ok()
86}
87
88thread_local! {
95 pub(crate) static IN_EVENT_HANDLER: Cell<bool> = const { Cell::new(false) };
97 pub(crate) static IN_APPLIED_SNAPSHOT: Cell<bool> = const { Cell::new(false) };
99}
100
101pub fn enter_event_handler() {
105 IN_EVENT_HANDLER.with(|c| c.set(true));
106}
107
108pub fn exit_event_handler() {
110 IN_EVENT_HANDLER.with(|c| c.set(false));
111}
112
113pub fn in_event_handler() -> bool {
115 IN_EVENT_HANDLER.with(|c| c.get())
116}
117
118pub fn in_applied_snapshot() -> bool {
120 IN_APPLIED_SNAPSHOT.with(|c| c.get())
121}
122
123#[cfg(not(target_arch = "wasm32"))]
129fn compose_debug_enabled() -> bool {
130 use std::sync::OnceLock;
131 static COMPOSE_DEBUG: OnceLock<bool> = OnceLock::new();
132 *COMPOSE_DEBUG.get_or_init(|| std::env::var_os("COMPOSE_DEBUG").is_some())
133}
134
135#[cfg(target_arch = "wasm32")]
136fn compose_debug_enabled() -> bool {
137 false
138}
139
140#[cfg(test)]
141pub use runtime::{TestRuntime, TestScheduler};
142
143use crate::collections::map::HashMap;
144use crate::collections::map::HashSet;
145use crate::runtime::{runtime_handle_for, RuntimeId};
146use crate::state::{NeverEqual, SnapshotMutableState, UpdateScope};
147use std::any::Any;
148use std::cell::{Cell, Ref, RefCell, RefMut};
149use std::fmt;
150use std::hash::{Hash, Hasher};
151use std::marker::PhantomData;
152use std::ops::{Deref, DerefMut};
153use std::rc::{Rc, Weak}; use std::sync::atomic::{AtomicUsize, Ordering};
155use std::sync::Arc;
156
157pub type Key = u64;
158pub type NodeId = usize;
159
160#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Default)]
166pub struct AnchorId(usize);
167
168impl AnchorId {
169 pub(crate) const INVALID: AnchorId = AnchorId(0);
171
172 pub(crate) fn new(id: usize) -> Self {
174 Self(id)
175 }
176
177 pub fn is_valid(&self) -> bool {
179 self.0 != 0
180 }
181}
182
183pub(crate) type ScopeId = usize;
184type LocalKey = usize;
185pub(crate) type FrameCallbackId = u64;
186
187static NEXT_SCOPE_ID: AtomicUsize = AtomicUsize::new(1);
188static NEXT_LOCAL_KEY: AtomicUsize = AtomicUsize::new(1);
189
190fn next_scope_id() -> ScopeId {
191 NEXT_SCOPE_ID.fetch_add(1, Ordering::Relaxed)
192}
193
194fn next_local_key() -> LocalKey {
195 NEXT_LOCAL_KEY.fetch_add(1, Ordering::Relaxed)
196}
197
198pub(crate) struct RecomposeScopeInner {
199 id: ScopeId,
200 runtime: RuntimeHandle,
201 invalid: Cell<bool>,
202 enqueued: Cell<bool>,
203 active: Cell<bool>,
204 pending_recompose: Cell<bool>,
205 force_reuse: Cell<bool>,
206 force_recompose: Cell<bool>,
207 parent_hint: Cell<Option<NodeId>>,
208 recompose: RefCell<Option<RecomposeCallback>>,
209 local_stack: RefCell<Vec<LocalContext>>,
210}
211
212impl RecomposeScopeInner {
213 fn new(runtime: RuntimeHandle) -> Self {
214 Self {
215 id: next_scope_id(),
216 runtime,
217 invalid: Cell::new(false),
218 enqueued: Cell::new(false),
219 active: Cell::new(true),
220 pending_recompose: Cell::new(false),
221 force_reuse: Cell::new(false),
222 force_recompose: Cell::new(false),
223 parent_hint: Cell::new(None),
224 recompose: RefCell::new(None),
225 local_stack: RefCell::new(Vec::new()),
226 }
227 }
228}
229
230type RecomposeCallback = Box<dyn FnMut(&Composer) + 'static>;
231
232#[derive(Clone)]
233pub struct RecomposeScope {
234 inner: Rc<RecomposeScopeInner>, }
236
237impl PartialEq for RecomposeScope {
238 fn eq(&self, other: &Self) -> bool {
239 Rc::ptr_eq(&self.inner, &other.inner)
240 }
241}
242
243impl Eq for RecomposeScope {}
244
245impl RecomposeScope {
246 fn new(runtime: RuntimeHandle) -> Self {
247 Self {
248 inner: Rc::new(RecomposeScopeInner::new(runtime)),
249 }
250 }
251
252 pub fn id(&self) -> ScopeId {
253 self.inner.id
254 }
255
256 pub fn is_invalid(&self) -> bool {
257 self.inner.invalid.get()
258 }
259
260 pub fn is_active(&self) -> bool {
261 self.inner.active.get()
262 }
263
264 fn invalidate(&self) {
265 self.inner.invalid.set(true);
266 if !self.inner.active.get() {
267 return;
268 }
269 if !self.inner.enqueued.replace(true) {
270 self.inner
271 .runtime
272 .register_invalid_scope(self.inner.id, Rc::downgrade(&self.inner));
273 }
274 }
275
276 fn mark_recomposed(&self) {
277 self.inner.invalid.set(false);
278 self.inner.force_reuse.set(false);
279 self.inner.force_recompose.set(false);
280 if self.inner.enqueued.replace(false) {
281 self.inner.runtime.mark_scope_recomposed(self.inner.id);
282 }
283 let pending = self.inner.pending_recompose.replace(false);
284 if pending {
285 if self.inner.active.get() {
286 self.invalidate();
287 } else {
288 self.inner.invalid.set(true);
289 }
290 }
291 }
292
293 fn downgrade(&self) -> Weak<RecomposeScopeInner> {
294 Rc::downgrade(&self.inner)
295 }
296
297 fn set_recompose(&self, callback: RecomposeCallback) {
298 *self.inner.recompose.borrow_mut() = Some(callback);
299 }
300
301 fn run_recompose(&self, composer: &Composer) {
302 let mut callback_cell = self.inner.recompose.borrow_mut();
303 if let Some(mut callback) = callback_cell.take() {
304 drop(callback_cell);
305 callback(composer);
306 }
307 }
308
309 fn snapshot_locals(&self, stack: &[LocalContext]) {
310 *self.inner.local_stack.borrow_mut() = stack.to_vec();
311 }
312
313 fn local_stack(&self) -> Vec<LocalContext> {
314 self.inner.local_stack.borrow().clone()
315 }
316
317 fn set_parent_hint(&self, parent: Option<NodeId>) {
318 self.inner.parent_hint.set(parent);
319 }
320
321 fn parent_hint(&self) -> Option<NodeId> {
322 self.inner.parent_hint.get()
323 }
324
325 pub fn deactivate(&self) {
326 if !self.inner.active.replace(false) {
327 return;
328 }
329 if self.inner.enqueued.replace(false) {
330 self.inner.runtime.mark_scope_recomposed(self.inner.id);
331 }
332 }
333
334 pub fn reactivate(&self) {
335 if self.inner.active.replace(true) {
336 return;
337 }
338 if self.inner.invalid.get() && !self.inner.enqueued.replace(true) {
339 self.inner
340 .runtime
341 .register_invalid_scope(self.inner.id, Rc::downgrade(&self.inner));
342 }
343 }
344
345 pub fn force_reuse(&self) {
346 self.inner.force_reuse.set(true);
347 self.inner.force_recompose.set(false);
348 self.inner.pending_recompose.set(true);
349 }
350
351 pub fn force_recompose(&self) {
352 self.inner.force_recompose.set(true);
353 self.inner.force_reuse.set(false);
354 self.inner.pending_recompose.set(false);
355 }
356
357 pub fn should_recompose(&self) -> bool {
358 if self.inner.force_recompose.replace(false) {
359 self.inner.force_reuse.set(false);
360 return true;
361 }
362 if self.inner.force_reuse.replace(false) {
363 return false;
364 }
365 self.is_invalid()
366 }
367}
368
369#[cfg(test)]
370impl RecomposeScope {
371 pub(crate) fn new_for_test(runtime: RuntimeHandle) -> Self {
372 Self::new(runtime)
373 }
374}
375
376#[derive(Debug, Clone, Copy, Default)]
377pub struct RecomposeOptions {
378 pub force_reuse: bool,
379 pub force_recompose: bool,
380}
381
382#[derive(Debug, Clone, PartialEq, Eq)]
383pub enum NodeError {
384 Missing { id: NodeId },
385 TypeMismatch { id: NodeId, expected: &'static str },
386 MissingContext { id: NodeId, reason: &'static str },
387 AlreadyExists { id: NodeId },
388}
389
390impl std::fmt::Display for NodeError {
391 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
392 match self {
393 NodeError::Missing { id } => write!(f, "node {id} missing"),
394 NodeError::TypeMismatch { id, expected } => {
395 write!(f, "node {id} type mismatch; expected {expected}")
396 }
397 NodeError::MissingContext { id, reason } => {
398 write!(f, "missing context for node {id}: {reason}")
399 }
400 NodeError::AlreadyExists { id } => {
401 write!(f, "node {id} already exists")
402 }
403 }
404 }
405}
406
407impl std::error::Error for NodeError {}
408
409pub use subcompose::{
410 ContentTypeReusePolicy, DefaultSlotReusePolicy, SlotId, SlotReusePolicy, SubcomposeState,
411};
412
413#[derive(Copy, Clone, Debug, PartialEq, Eq)]
414pub enum Phase {
415 Compose,
416 Measure,
417 Layout,
418}
419
420pub use composer_context::with_composer as with_current_composer;
421
422#[allow(non_snake_case)]
423pub fn withCurrentComposer<R>(f: impl FnOnce(&Composer) -> R) -> R {
424 composer_context::with_composer(f)
425}
426
427fn with_current_composer_opt<R>(f: impl FnOnce(&Composer) -> R) -> Option<R> {
428 composer_context::try_with_composer(f)
429}
430
431pub fn with_key<K: Hash>(key: &K, content: impl FnOnce()) {
432 with_current_composer(|composer| composer.with_key(key, |_| content()));
433}
434
435#[allow(non_snake_case)]
436pub fn withKey<K: Hash>(key: &K, content: impl FnOnce()) {
437 with_key(key, content)
438}
439
440pub fn remember<T: 'static>(init: impl FnOnce() -> T) -> Owned<T> {
441 with_current_composer(|composer| composer.remember(init))
442}
443
444#[allow(non_snake_case)]
472pub fn rememberUpdatedState<T: Clone + 'static>(value: T) -> MutableState<T> {
473 let state = remember(|| mutableStateOf(value.clone()));
474 state.with(|s| {
475 s.set(value);
476 *s
477 })
478}
479
480#[allow(non_snake_case)]
481pub fn withFrameNanos(callback: impl FnOnce(u64) + 'static) -> FrameCallbackRegistration {
482 with_current_composer(|composer| {
483 composer
484 .runtime_handle()
485 .frame_clock()
486 .with_frame_nanos(callback)
487 })
488}
489
490#[allow(non_snake_case)]
491pub fn withFrameMillis(callback: impl FnOnce(u64) + 'static) -> FrameCallbackRegistration {
492 with_current_composer(|composer| {
493 composer
494 .runtime_handle()
495 .frame_clock()
496 .with_frame_millis(callback)
497 })
498}
499
500pub fn mutableStateOf<T: Clone + 'static>(initial: T) -> MutableState<T> {
531 let runtime = with_current_composer_opt(|composer| composer.runtime_handle())
536 .or_else(runtime::current_runtime_handle)
537 .expect("mutableStateOf requires an active runtime. Create state inside a composition or after a Runtime is created.");
538 MutableState::with_runtime(initial, runtime)
539}
540
541#[allow(non_snake_case)]
546pub fn try_mutableStateOf<T: Clone + 'static>(initial: T) -> Option<MutableState<T>> {
547 let runtime = with_current_composer_opt(|composer| composer.runtime_handle())
548 .or_else(runtime::current_runtime_handle)?;
549 Some(MutableState::with_runtime(initial, runtime))
550}
551
552#[allow(non_snake_case)]
553pub fn mutableStateListOf<T, I>(values: I) -> SnapshotStateList<T>
554where
555 T: Clone + 'static,
556 I: IntoIterator<Item = T>,
557{
558 with_current_composer(move |composer| composer.mutable_state_list_of(values))
559}
560
561#[allow(non_snake_case)]
562pub fn mutableStateList<T: Clone + 'static>() -> SnapshotStateList<T> {
563 mutableStateListOf(std::iter::empty::<T>())
564}
565
566#[allow(non_snake_case)]
567pub fn mutableStateMapOf<K, V, I>(pairs: I) -> SnapshotStateMap<K, V>
568where
569 K: Clone + Eq + Hash + 'static,
570 V: Clone + 'static,
571 I: IntoIterator<Item = (K, V)>,
572{
573 with_current_composer(move |composer| composer.mutable_state_map_of(pairs))
574}
575
576#[allow(non_snake_case)]
577pub fn mutableStateMap<K, V>() -> SnapshotStateMap<K, V>
578where
579 K: Clone + Eq + Hash + 'static,
580 V: Clone + 'static,
581{
582 mutableStateMapOf(std::iter::empty::<(K, V)>())
583}
584
585pub fn useState<T: Clone + 'static>(init: impl FnOnce() -> T) -> MutableState<T> {
611 remember(|| mutableStateOf(init())).with(|state| *state)
612}
613
614#[allow(deprecated)]
615#[deprecated(
616 since = "0.1.0",
617 note = "use useState(|| value) instead of use_state(|| value)"
618)]
619pub fn use_state<T: Clone + 'static>(init: impl FnOnce() -> T) -> MutableState<T> {
620 useState(init)
621}
622
623#[allow(non_snake_case)]
624pub fn derivedStateOf<T: 'static + Clone>(compute: impl Fn() -> T + 'static) -> State<T> {
625 with_current_composer(|composer| {
626 let key = location_key(file!(), line!(), column!());
627 composer.with_group(key, |composer| {
628 let should_recompute = composer
629 .current_recranpose_scope()
630 .map(|scope| scope.should_recompose())
631 .unwrap_or(true);
632 let runtime = composer.runtime_handle();
633 let compute_rc: Rc<dyn Fn() -> T> = Rc::new(compute); let derived =
635 composer.remember(|| DerivedState::new(runtime.clone(), compute_rc.clone()));
636 derived.update(|derived| {
637 derived.set_compute(compute_rc.clone());
638 if should_recompute {
639 derived.recompute();
640 }
641 });
642 derived.with(|derived| derived.state.as_state())
643 })
644 })
645}
646
647pub struct ProvidedValue {
648 key: LocalKey,
649 #[allow(clippy::type_complexity)] apply: Box<dyn Fn(&Composer) -> Rc<dyn Any>>, }
652
653impl ProvidedValue {
654 fn into_entry(self, composer: &Composer) -> (LocalKey, Rc<dyn Any>) {
655 let ProvidedValue { key, apply } = self;
657 let entry = apply(composer);
658 (key, entry)
659 }
660}
661
662#[allow(non_snake_case)]
663pub fn CompositionLocalProvider(
664 values: impl IntoIterator<Item = ProvidedValue>,
665 content: impl FnOnce(),
666) {
667 with_current_composer(|composer| {
668 let provided: Vec<ProvidedValue> = values.into_iter().collect(); composer.with_composition_locals(provided, |_composer| content());
670 })
671}
672
673struct LocalStateEntry<T: Clone + 'static> {
674 state: MutableState<T>,
675}
676
677impl<T: Clone + 'static> LocalStateEntry<T> {
678 fn new(initial: T, runtime: RuntimeHandle) -> Self {
679 Self {
680 state: MutableState::with_runtime(initial, runtime),
681 }
682 }
683
684 fn set(&self, value: T) {
685 self.state.replace(value);
686 }
687
688 fn value(&self) -> T {
689 self.state.value()
690 }
691}
692
693struct StaticLocalEntry<T: Clone + 'static> {
694 value: RefCell<T>,
695}
696
697impl<T: Clone + 'static> StaticLocalEntry<T> {
698 fn new(value: T) -> Self {
699 Self {
700 value: RefCell::new(value),
701 }
702 }
703
704 fn set(&self, value: T) {
705 *self.value.borrow_mut() = value;
706 }
707
708 fn value(&self) -> T {
709 self.value.borrow().clone()
710 }
711}
712
713#[derive(Clone)]
714pub struct CompositionLocal<T: Clone + 'static> {
715 key: LocalKey,
716 default: Rc<dyn Fn() -> T>, }
718
719impl<T: Clone + 'static> PartialEq for CompositionLocal<T> {
720 fn eq(&self, other: &Self) -> bool {
721 self.key == other.key
722 }
723}
724
725impl<T: Clone + 'static> Eq for CompositionLocal<T> {}
726
727impl<T: Clone + 'static> CompositionLocal<T> {
728 pub fn provides(&self, value: T) -> ProvidedValue {
729 let key = self.key;
730 ProvidedValue {
731 key,
732 apply: Box::new(move |composer: &Composer| {
733 let runtime = composer.runtime_handle();
734 let entry_ref = composer
735 .remember(|| Rc::new(LocalStateEntry::new(value.clone(), runtime.clone())));
736 entry_ref.update(|entry| entry.set(value.clone()));
737 entry_ref.with(|entry| entry.clone() as Rc<dyn Any>) }),
739 }
740 }
741
742 pub fn current(&self) -> T {
743 with_current_composer(|composer| composer.read_composition_local(self))
744 }
745
746 pub fn default_value(&self) -> T {
747 (self.default)()
748 }
749}
750
751#[allow(non_snake_case)]
752pub fn compositionLocalOf<T: Clone + 'static>(
753 default: impl Fn() -> T + 'static,
754) -> CompositionLocal<T> {
755 CompositionLocal {
756 key: next_local_key(),
757 default: Rc::new(default), }
759}
760
761#[derive(Clone)]
772pub struct StaticCompositionLocal<T: Clone + 'static> {
773 key: LocalKey,
774 default: Rc<dyn Fn() -> T>, }
776
777impl<T: Clone + 'static> PartialEq for StaticCompositionLocal<T> {
778 fn eq(&self, other: &Self) -> bool {
779 self.key == other.key
780 }
781}
782
783impl<T: Clone + 'static> Eq for StaticCompositionLocal<T> {}
784
785impl<T: Clone + 'static> StaticCompositionLocal<T> {
786 pub fn provides(&self, value: T) -> ProvidedValue {
787 let key = self.key;
788 ProvidedValue {
789 key,
790 apply: Box::new(move |composer: &Composer| {
791 let entry_ref = composer.remember(|| Rc::new(StaticLocalEntry::new(value.clone())));
794 entry_ref.update(|entry| entry.set(value.clone()));
795 entry_ref.with(|entry| entry.clone() as Rc<dyn Any>) }),
797 }
798 }
799
800 pub fn current(&self) -> T {
801 with_current_composer(|composer| composer.read_static_composition_local(self))
802 }
803
804 pub fn default_value(&self) -> T {
805 (self.default)()
806 }
807}
808
809#[allow(non_snake_case)]
810pub fn staticCompositionLocalOf<T: Clone + 'static>(
811 default: impl Fn() -> T + 'static,
812) -> StaticCompositionLocal<T> {
813 StaticCompositionLocal {
814 key: next_local_key(),
815 default: Rc::new(default), }
817}
818
819#[derive(Default)]
820struct DisposableEffectState {
821 key: Option<Key>,
822 cleanup: Option<Box<dyn FnOnce()>>,
823}
824
825impl DisposableEffectState {
826 fn should_run(&self, key: Key) -> bool {
827 match self.key {
828 Some(current) => current != key,
829 None => true,
830 }
831 }
832
833 fn set_key(&mut self, key: Key) {
834 self.key = Some(key);
835 }
836
837 fn set_cleanup(&mut self, cleanup: Option<Box<dyn FnOnce()>>) {
838 self.cleanup = cleanup;
839 }
840
841 fn run_cleanup(&mut self) {
842 if let Some(cleanup) = self.cleanup.take() {
843 cleanup();
844 }
845 }
846}
847
848impl Drop for DisposableEffectState {
849 fn drop(&mut self) {
850 self.run_cleanup();
851 }
852}
853
854#[derive(Clone, Copy, Debug, Default)]
855pub struct DisposableEffectScope;
856
857#[derive(Default)]
858pub struct DisposableEffectResult {
859 cleanup: Option<Box<dyn FnOnce()>>,
860}
861
862impl DisposableEffectScope {
863 pub fn on_dispose(&self, cleanup: impl FnOnce() + 'static) -> DisposableEffectResult {
864 DisposableEffectResult::new(cleanup)
865 }
866}
867
868impl DisposableEffectResult {
869 pub fn new(cleanup: impl FnOnce() + 'static) -> Self {
870 Self {
871 cleanup: Some(Box::new(cleanup)),
872 }
873 }
874
875 fn into_cleanup(self) -> Option<Box<dyn FnOnce()>> {
876 self.cleanup
877 }
878}
879
880#[allow(non_snake_case)]
881pub fn SideEffect(effect: impl FnOnce() + 'static) {
882 with_current_composer(|composer| composer.register_side_effect(effect));
883}
884
885pub fn __disposable_effect_impl<K, F>(group_key: Key, keys: K, effect: F)
886where
887 K: Hash,
888 F: FnOnce(DisposableEffectScope) -> DisposableEffectResult + 'static,
889{
890 with_current_composer(|composer| {
893 composer.with_group(group_key, |composer| {
894 let key_hash = hash_key(&keys);
895 let state = composer.remember(DisposableEffectState::default);
896 if state.with(|state| state.should_run(key_hash)) {
897 state.update(|state| {
898 state.run_cleanup();
899 state.set_key(key_hash);
900 });
901 let state_for_effect = state.clone();
902 let mut effect_opt = Some(effect);
903 composer.register_side_effect(move || {
904 if let Some(effect) = effect_opt.take() {
905 let result = effect(DisposableEffectScope);
906 state_for_effect.update(|state| state.set_cleanup(result.into_cleanup()));
907 }
908 });
909 }
910 });
911 });
912}
913
914#[macro_export]
915macro_rules! DisposableEffect {
916 ($keys:expr, $effect:expr) => {
917 $crate::__disposable_effect_impl(
918 $crate::location_key(file!(), line!(), column!()),
919 $keys,
920 $effect,
921 )
922 };
923}
924
925pub fn with_node_mut<N: Node + 'static, R>(
926 id: NodeId,
927 f: impl FnOnce(&mut N) -> R,
928) -> Result<R, NodeError> {
929 with_current_composer(|composer| composer.with_node_mut(id, f))
930}
931
932pub fn push_parent(id: NodeId) {
933 with_current_composer(|composer| composer.push_parent(id));
934}
935
936pub fn pop_parent() {
937 with_current_composer(|composer| composer.pop_parent());
938}
939
940mod slot_storage;
945pub use slot_storage::{GroupId, SlotStorage, StartGroup, ValueSlotId};
946
947pub mod chunked_slot_storage;
948pub mod hierarchical_slot_storage;
949pub mod slot_backend;
950pub mod split_slot_storage;
951pub use slot_backend::{make_backend, SlotBackend, SlotBackendKind};
952
953pub mod slot_table;
958pub use slot_table::SlotTable;
959
960pub trait Node: Any {
961 fn mount(&mut self) {}
962 fn update(&mut self) {}
963 fn unmount(&mut self) {}
964 fn insert_child(&mut self, _child: NodeId) {}
965 fn remove_child(&mut self, _child: NodeId) {}
966 fn move_child(&mut self, _from: usize, _to: usize) {}
967 fn update_children(&mut self, _children: &[NodeId]) {}
968 fn children(&self) -> Vec<NodeId> {
969 Vec::new()
970 }
971 fn set_node_id(&mut self, _id: NodeId) {}
974 fn on_attached_to_parent(&mut self, _parent: NodeId) {}
977 fn on_removed_from_parent(&mut self) {}
980 fn parent(&self) -> Option<NodeId> {
983 None
984 }
985 fn mark_needs_layout(&self) {}
988 fn needs_layout(&self) -> bool {
990 false
991 }
992 fn mark_needs_measure(&self) {}
995 fn needs_measure(&self) -> bool {
997 false
998 }
999 fn mark_needs_semantics(&self) {}
1001 fn needs_semantics(&self) -> bool {
1003 false
1004 }
1005 fn set_parent_for_bubbling(&mut self, parent: NodeId) {
1013 self.on_attached_to_parent(parent);
1014 }
1015}
1016
1017pub fn bubble_layout_dirty(applier: &mut dyn Applier, node_id: NodeId) {
1036 bubble_layout_dirty_applier(applier, node_id);
1037}
1038
1039pub fn bubble_measure_dirty(applier: &mut dyn Applier, node_id: NodeId) {
1050 bubble_measure_dirty_applier(applier, node_id);
1051}
1052
1053pub fn bubble_semantics_dirty(applier: &mut dyn Applier, node_id: NodeId) {
1059 bubble_semantics_dirty_applier(applier, node_id);
1060}
1061
1062pub fn queue_semantics_invalidation(node_id: NodeId) {
1067 let _ = composer_context::try_with_composer(|composer| {
1068 composer.enqueue_semantics_invalidation(node_id);
1069 });
1070}
1071
1072pub fn bubble_layout_dirty_in_composer<N: Node + 'static>(node_id: NodeId) {
1095 bubble_layout_dirty_composer::<N>(node_id);
1096}
1097
1098pub fn bubble_semantics_dirty_in_composer<N: Node + 'static>(node_id: NodeId) {
1105 bubble_semantics_dirty_composer::<N>(node_id);
1106}
1107
1108fn bubble_layout_dirty_applier(applier: &mut dyn Applier, mut node_id: NodeId) {
1110 if let Ok(node) = applier.get_mut(node_id) {
1113 node.mark_needs_layout();
1114 }
1115
1116 loop {
1118 let parent_id = match applier.get_mut(node_id) {
1120 Ok(node) => node.parent(),
1121 Err(_) => None,
1122 };
1123
1124 match parent_id {
1125 Some(pid) => {
1126 if let Ok(parent) = applier.get_mut(pid) {
1128 if !parent.needs_layout() {
1129 parent.mark_needs_layout();
1130 node_id = pid; } else {
1132 break; }
1134 } else {
1135 break;
1136 }
1137 }
1138 None => break, }
1140 }
1141}
1142
1143fn bubble_measure_dirty_applier(applier: &mut dyn Applier, mut node_id: NodeId) {
1145 if let Ok(node) = applier.get_mut(node_id) {
1147 node.mark_needs_measure();
1148 }
1149
1150 loop {
1152 let parent_id = match applier.get_mut(node_id) {
1154 Ok(node) => node.parent(),
1155 Err(_) => None,
1156 };
1157
1158 match parent_id {
1159 Some(pid) => {
1160 if let Ok(parent) = applier.get_mut(pid) {
1162 if !parent.needs_measure() {
1163 parent.mark_needs_measure();
1164 node_id = pid; } else {
1166 break; }
1168 } else {
1169 break;
1170 }
1171 }
1172 None => {
1173 break; }
1175 }
1176 }
1177}
1178
1179fn bubble_semantics_dirty_applier(applier: &mut dyn Applier, mut node_id: NodeId) {
1181 if let Ok(node) = applier.get_mut(node_id) {
1182 node.mark_needs_semantics();
1183 }
1184
1185 loop {
1186 let parent_id = match applier.get_mut(node_id) {
1187 Ok(node) => node.parent(),
1188 Err(_) => None,
1189 };
1190
1191 match parent_id {
1192 Some(pid) => {
1193 if let Ok(parent) = applier.get_mut(pid) {
1194 if !parent.needs_semantics() {
1195 parent.mark_needs_semantics();
1196 node_id = pid;
1197 } else {
1198 break;
1199 }
1200 } else {
1201 break;
1202 }
1203 }
1204 None => break,
1205 }
1206 }
1207}
1208
1209fn bubble_layout_dirty_composer<N: Node + 'static>(mut node_id: NodeId) {
1213 let _ = with_node_mut(node_id, |node: &mut N| {
1215 node.mark_needs_layout();
1216 });
1217
1218 while let Ok(Some(pid)) = with_node_mut(node_id, |node: &mut N| node.parent()) {
1220 let parent_id = pid;
1221
1222 let should_continue = with_node_mut(parent_id, |node: &mut N| {
1224 if !node.needs_layout() {
1225 node.mark_needs_layout();
1226 true } else {
1228 false }
1230 })
1231 .unwrap_or(false);
1232
1233 if should_continue {
1234 node_id = parent_id;
1235 } else {
1236 break;
1237 }
1238 }
1239}
1240
1241fn bubble_semantics_dirty_composer<N: Node + 'static>(mut node_id: NodeId) {
1243 let _ = with_node_mut(node_id, |node: &mut N| {
1245 node.mark_needs_semantics();
1246 });
1247
1248 while let Ok(Some(pid)) = with_node_mut(node_id, |node: &mut N| node.parent()) {
1249 let parent_id = pid;
1250
1251 let should_continue = with_node_mut(parent_id, |node: &mut N| {
1252 if !node.needs_semantics() {
1253 node.mark_needs_semantics();
1254 true
1255 } else {
1256 false
1257 }
1258 })
1259 .unwrap_or(false);
1260
1261 if should_continue {
1262 node_id = parent_id;
1263 } else {
1264 break;
1265 }
1266 }
1267}
1268
1269impl dyn Node {
1270 pub fn as_any_mut(&mut self) -> &mut dyn Any {
1271 self
1272 }
1273}
1274
1275pub trait Applier: Any {
1276 fn create(&mut self, node: Box<dyn Node>) -> NodeId;
1277 fn get_mut(&mut self, id: NodeId) -> Result<&mut dyn Node, NodeError>;
1278 fn remove(&mut self, id: NodeId) -> Result<(), NodeError>;
1279
1280 fn insert_with_id(&mut self, id: NodeId, node: Box<dyn Node>) -> Result<(), NodeError>;
1288
1289 fn as_any(&self) -> &dyn Any
1290 where
1291 Self: Sized,
1292 {
1293 self
1294 }
1295
1296 fn as_any_mut(&mut self) -> &mut dyn Any
1297 where
1298 Self: Sized,
1299 {
1300 self
1301 }
1302}
1303
1304pub(crate) type Command = Box<dyn FnMut(&mut dyn Applier) -> Result<(), NodeError> + 'static>;
1305
1306#[derive(Default)]
1307pub struct MemoryApplier {
1308 nodes: Vec<Option<Box<dyn Node>>>, high_id_nodes: std::collections::HashMap<NodeId, Box<dyn Node>>,
1312 layout_runtime: Option<RuntimeHandle>,
1313 slots: SlotBackend,
1314}
1315
1316impl MemoryApplier {
1317 pub fn new() -> Self {
1318 Self {
1319 nodes: Vec::new(),
1320 high_id_nodes: std::collections::HashMap::new(),
1321 layout_runtime: None,
1322 slots: SlotBackend::default(),
1323 }
1324 }
1325
1326 pub fn slots(&mut self) -> &mut SlotBackend {
1327 &mut self.slots
1328 }
1329
1330 pub fn with_node<N: Node + 'static, R>(
1331 &mut self,
1332 id: NodeId,
1333 f: impl FnOnce(&mut N) -> R,
1334 ) -> Result<R, NodeError> {
1335 let slot = self
1336 .nodes
1337 .get_mut(id)
1338 .ok_or(NodeError::Missing { id })?
1339 .as_deref_mut()
1340 .ok_or(NodeError::Missing { id })?;
1341 let typed = slot
1342 .as_any_mut()
1343 .downcast_mut::<N>()
1344 .ok_or(NodeError::TypeMismatch {
1345 id,
1346 expected: std::any::type_name::<N>(),
1347 })?;
1348 Ok(f(typed))
1349 }
1350
1351 pub fn len(&self) -> usize {
1352 self.nodes.iter().filter(|n| n.is_some()).count()
1353 }
1354
1355 pub fn is_empty(&self) -> bool {
1356 self.len() == 0
1357 }
1358
1359 pub fn set_runtime_handle(&mut self, handle: RuntimeHandle) {
1360 self.layout_runtime = Some(handle);
1361 }
1362
1363 pub fn clear_runtime_handle(&mut self) {
1364 self.layout_runtime = None;
1365 }
1366
1367 pub fn runtime_handle(&self) -> Option<RuntimeHandle> {
1368 self.layout_runtime.clone()
1369 }
1370
1371 pub fn dump_tree(&self, root: Option<NodeId>) -> String {
1372 let mut output = String::new();
1373 if let Some(root_id) = root {
1374 self.dump_node(&mut output, root_id, 0);
1375 } else {
1376 output.push_str("(no root)\n");
1377 }
1378 output
1379 }
1380
1381 fn dump_node(&self, output: &mut String, id: NodeId, depth: usize) {
1382 let indent = " ".repeat(depth);
1383 if let Some(Some(node)) = self.nodes.get(id) {
1384 let type_name = std::any::type_name_of_val(&**node);
1385 output.push_str(&format!("{}[{}] {}\n", indent, id, type_name));
1386
1387 let children = node.children();
1388 for child_id in children {
1389 self.dump_node(output, child_id, depth + 1);
1390 }
1391 } else {
1392 output.push_str(&format!("{}[{}] (missing)\n", indent, id));
1393 }
1394 }
1395}
1396
1397impl Applier for MemoryApplier {
1398 fn create(&mut self, node: Box<dyn Node>) -> NodeId {
1399 let id = self.nodes.len();
1400 self.nodes.push(Some(node));
1401 id
1402 }
1403
1404 fn get_mut(&mut self, id: NodeId) -> Result<&mut dyn Node, NodeError> {
1405 if let Some(node) = self.high_id_nodes.get_mut(&id) {
1407 return Ok(node.as_mut());
1408 }
1409 let slot = self
1411 .nodes
1412 .get_mut(id)
1413 .ok_or(NodeError::Missing { id })?
1414 .as_deref_mut()
1415 .ok_or(NodeError::Missing { id })?;
1416 Ok(slot)
1417 }
1418
1419 fn remove(&mut self, id: NodeId) -> Result<(), NodeError> {
1420 if self.high_id_nodes.contains_key(&id) {
1422 let children = self
1424 .high_id_nodes
1425 .get(&id)
1426 .map(|n| n.children())
1427 .unwrap_or_default();
1428
1429 for child_id in children {
1431 let is_owned = self
1432 .get_mut(child_id)
1433 .map(|child| child.parent() == Some(id))
1434 .unwrap_or(false);
1435 if is_owned {
1436 let _ = self.remove(child_id);
1437 }
1438 }
1439
1440 self.high_id_nodes.remove(&id);
1441 return Ok(());
1442 }
1443
1444 let children = {
1446 let slot = self.nodes.get(id).ok_or(NodeError::Missing { id })?;
1447 if let Some(node) = slot {
1448 node.children()
1449 } else {
1450 return Err(NodeError::Missing { id });
1451 }
1452 };
1453
1454 for child_id in children {
1456 let is_owned = self
1457 .get_mut(child_id)
1458 .map(|child| child.parent() == Some(id))
1459 .unwrap_or(false);
1460
1461 if is_owned {
1462 let _ = self.remove(child_id);
1463 }
1464 }
1465
1466 let slot = self.nodes.get_mut(id).ok_or(NodeError::Missing { id })?;
1467 slot.take();
1468 Ok(())
1469 }
1470
1471 fn insert_with_id(&mut self, id: NodeId, node: Box<dyn Node>) -> Result<(), NodeError> {
1472 const HIGH_ID_THRESHOLD: NodeId = 1_000_000_000; if id >= HIGH_ID_THRESHOLD {
1477 if self.high_id_nodes.contains_key(&id) {
1478 return Err(NodeError::AlreadyExists { id });
1479 }
1480 self.high_id_nodes.insert(id, node);
1481 Ok(())
1482 } else {
1483 if id >= self.nodes.len() {
1485 self.nodes.resize_with(id + 1, || None);
1486 }
1487
1488 if self.nodes[id].is_some() {
1489 return Err(NodeError::AlreadyExists { id });
1490 }
1491
1492 self.nodes[id] = Some(node);
1493 Ok(())
1494 }
1495 }
1496}
1497
1498pub trait ApplierHost {
1499 fn borrow_dyn(&self) -> RefMut<'_, dyn Applier>;
1500}
1501
1502pub struct ConcreteApplierHost<A: Applier + 'static> {
1503 inner: RefCell<A>,
1504}
1505
1506impl<A: Applier + 'static> ConcreteApplierHost<A> {
1507 pub fn new(applier: A) -> Self {
1508 Self {
1509 inner: RefCell::new(applier),
1510 }
1511 }
1512
1513 pub fn borrow_typed(&self) -> RefMut<'_, A> {
1514 self.inner.borrow_mut()
1515 }
1516
1517 pub fn try_borrow_typed(&self) -> Result<RefMut<'_, A>, std::cell::BorrowMutError> {
1518 self.inner.try_borrow_mut()
1519 }
1520
1521 pub fn into_inner(self) -> A {
1522 self.inner.into_inner()
1523 }
1524}
1525
1526impl<A: Applier + 'static> ApplierHost for ConcreteApplierHost<A> {
1527 fn borrow_dyn(&self) -> RefMut<'_, dyn Applier> {
1528 RefMut::map(self.inner.borrow_mut(), |applier| {
1529 applier as &mut dyn Applier
1530 })
1531 }
1532}
1533
1534pub struct ApplierGuard<'a, A: Applier + 'static> {
1535 inner: RefMut<'a, A>,
1536}
1537
1538impl<'a, A: Applier + 'static> ApplierGuard<'a, A> {
1539 fn new(inner: RefMut<'a, A>) -> Self {
1540 Self { inner }
1541 }
1542}
1543
1544impl<'a, A: Applier + 'static> Deref for ApplierGuard<'a, A> {
1545 type Target = A;
1546
1547 fn deref(&self) -> &Self::Target {
1548 &self.inner
1549 }
1550}
1551
1552impl<'a, A: Applier + 'static> DerefMut for ApplierGuard<'a, A> {
1553 fn deref_mut(&mut self) -> &mut Self::Target {
1554 &mut self.inner
1555 }
1556}
1557
1558pub struct SlotsHost {
1559 inner: RefCell<SlotBackend>,
1560}
1561
1562impl SlotsHost {
1563 pub fn new(storage: SlotBackend) -> Self {
1564 Self {
1565 inner: RefCell::new(storage),
1566 }
1567 }
1568
1569 pub fn borrow(&self) -> Ref<'_, SlotBackend> {
1570 self.inner.borrow()
1571 }
1572
1573 pub fn borrow_mut(&self) -> RefMut<'_, SlotBackend> {
1574 self.inner.borrow_mut()
1575 }
1576
1577 pub fn take(&self) -> SlotBackend {
1578 std::mem::take(&mut *self.inner.borrow_mut())
1579 }
1580}
1581
1582pub(crate) struct ComposerCore {
1583 slots: Rc<SlotsHost>,
1584 slots_override: RefCell<Vec<Rc<SlotsHost>>>,
1585 applier: Rc<dyn ApplierHost>,
1586 runtime: RuntimeHandle,
1587 observer: SnapshotStateObserver,
1588 parent_stack: RefCell<Vec<ParentFrame>>,
1589 subcompose_stack: RefCell<Vec<SubcomposeFrame>>,
1590 root: Cell<Option<NodeId>>,
1591 commands: RefCell<Vec<Command>>,
1592 scope_stack: RefCell<Vec<RecomposeScope>>,
1593 local_stack: RefCell<Vec<LocalContext>>,
1594 side_effects: RefCell<Vec<Box<dyn FnOnce()>>>,
1595 pending_scope_options: RefCell<Option<RecomposeOptions>>,
1596 phase: Cell<Phase>,
1597 last_node_reused: Cell<Option<bool>>,
1598 recranpose_parent_hint: Cell<Option<NodeId>>,
1599 _not_send: PhantomData<*const ()>,
1600}
1601
1602impl ComposerCore {
1603 pub fn new(
1604 slots: Rc<SlotsHost>,
1605 applier: Rc<dyn ApplierHost>,
1606 runtime: RuntimeHandle,
1607 observer: SnapshotStateObserver,
1608 root: Option<NodeId>,
1609 ) -> Self {
1610 let parent_stack = if let Some(root_id) = root {
1616 vec![ParentFrame {
1617 id: root_id,
1618 remembered: Owned::new(ParentChildren::default()),
1619 previous: Vec::new(),
1620 new_children: Vec::new(),
1621 }]
1622 } else {
1623 Vec::new()
1624 };
1625
1626 Self {
1627 slots,
1628 slots_override: RefCell::new(Vec::new()),
1629 applier,
1630 runtime,
1631 observer,
1632 parent_stack: RefCell::new(parent_stack),
1633 subcompose_stack: RefCell::new(Vec::new()),
1634 root: Cell::new(root),
1635 commands: RefCell::new(Vec::new()),
1636 scope_stack: RefCell::new(Vec::new()),
1637 local_stack: RefCell::new(Vec::new()),
1638 side_effects: RefCell::new(Vec::new()),
1639 pending_scope_options: RefCell::new(None),
1640 phase: Cell::new(Phase::Compose),
1641 last_node_reused: Cell::new(None),
1642 recranpose_parent_hint: Cell::new(None),
1643 _not_send: PhantomData,
1644 }
1645 }
1646}
1647
1648#[derive(Clone)]
1649pub struct Composer {
1650 core: Rc<ComposerCore>,
1651}
1652
1653impl Composer {
1654 pub fn new(
1655 slots: Rc<SlotsHost>,
1656 applier: Rc<dyn ApplierHost>,
1657 runtime: RuntimeHandle,
1658 observer: SnapshotStateObserver,
1659 root: Option<NodeId>,
1660 ) -> Self {
1661 let core = Rc::new(ComposerCore::new(slots, applier, runtime, observer, root));
1662 Self { core }
1663 }
1664
1665 pub(crate) fn from_core(core: Rc<ComposerCore>) -> Self {
1666 Self { core }
1667 }
1668
1669 pub(crate) fn clone_core(&self) -> Rc<ComposerCore> {
1670 Rc::clone(&self.core)
1671 }
1672
1673 fn observer(&self) -> SnapshotStateObserver {
1674 self.core.observer.clone()
1675 }
1676
1677 fn observe_scope<R>(&self, scope: &RecomposeScope, block: impl FnOnce() -> R) -> R {
1678 let observer = self.observer();
1679 let scope_clone = scope.clone();
1680 observer.observe_reads(scope_clone, move |scope_ref| scope_ref.invalidate(), block)
1681 }
1682
1683 fn active_slots_host(&self) -> Rc<SlotsHost> {
1684 self.core
1685 .slots_override
1686 .borrow()
1687 .last()
1688 .cloned()
1689 .unwrap_or_else(|| Rc::clone(&self.core.slots))
1690 }
1691
1692 fn with_slots<R>(&self, f: impl FnOnce(&SlotBackend) -> R) -> R {
1693 let host = self.active_slots_host();
1694 let slots = host.borrow();
1695 f(&slots)
1696 }
1697
1698 fn with_slots_mut<R>(&self, f: impl FnOnce(&mut SlotBackend) -> R) -> R {
1699 let host = self.active_slots_host();
1700 let mut slots = host.borrow_mut();
1701 f(&mut slots)
1702 }
1703
1704 fn with_slot_override<R>(&self, slots: Rc<SlotsHost>, f: impl FnOnce(&Composer) -> R) -> R {
1705 self.core.slots_override.borrow_mut().push(slots);
1706 struct Guard {
1707 core: Rc<ComposerCore>,
1708 }
1709 impl Drop for Guard {
1710 fn drop(&mut self) {
1711 self.core.slots_override.borrow_mut().pop();
1712 }
1713 }
1714 let guard = Guard {
1715 core: self.clone_core(),
1716 };
1717 let result = f(self);
1718 drop(guard);
1719 result
1720 }
1721
1722 fn parent_stack(&self) -> RefMut<'_, Vec<ParentFrame>> {
1723 self.core.parent_stack.borrow_mut()
1724 }
1725
1726 fn subcompose_stack(&self) -> RefMut<'_, Vec<SubcomposeFrame>> {
1727 self.core.subcompose_stack.borrow_mut()
1728 }
1729
1730 fn commands_mut(&self) -> RefMut<'_, Vec<Command>> {
1731 self.core.commands.borrow_mut()
1732 }
1733
1734 pub(crate) fn enqueue_semantics_invalidation(&self, id: NodeId) {
1735 self.commands_mut()
1736 .push(Box::new(move |applier: &mut dyn Applier| {
1737 bubble_semantics_dirty(applier, id);
1738 Ok(())
1739 }));
1740 }
1741
1742 fn scope_stack(&self) -> RefMut<'_, Vec<RecomposeScope>> {
1743 self.core.scope_stack.borrow_mut()
1744 }
1745
1746 fn local_stack(&self) -> RefMut<'_, Vec<LocalContext>> {
1747 self.core.local_stack.borrow_mut()
1748 }
1749
1750 fn side_effects_mut(&self) -> RefMut<'_, Vec<Box<dyn FnOnce()>>> {
1751 self.core.side_effects.borrow_mut()
1752 }
1753
1754 fn pending_scope_options(&self) -> RefMut<'_, Option<RecomposeOptions>> {
1755 self.core.pending_scope_options.borrow_mut()
1756 }
1757
1758 fn borrow_applier(&self) -> RefMut<'_, dyn Applier> {
1759 self.core.applier.borrow_dyn()
1760 }
1761
1762 pub fn register_virtual_node(
1769 &self,
1770 node_id: NodeId,
1771 node: Box<dyn Node>,
1772 ) -> Result<(), NodeError> {
1773 let mut applier = self.borrow_applier();
1774 applier.insert_with_id(node_id, node)
1775 }
1776
1777 pub fn node_has_no_parent(&self, node_id: NodeId) -> bool {
1780 let mut applier = self.borrow_applier();
1781 match applier.get_mut(node_id) {
1782 Ok(node) => node.parent().is_none(),
1783 Err(_) => true, }
1785 }
1786
1787 pub fn get_node_children(&self, node_id: NodeId) -> Vec<NodeId> {
1792 let mut applier = self.borrow_applier();
1793 match applier.get_mut(node_id) {
1794 Ok(node) => node.children(),
1795 Err(_) => Vec::new(),
1796 }
1797 }
1798
1799 pub fn clear_node_children(&self, node_id: NodeId) {
1805 let mut applier = self.borrow_applier();
1806 if let Ok(node) = applier.get_mut(node_id) {
1807 node.update_children(&[]);
1809 }
1810 }
1811
1812 pub fn install<R>(&self, f: impl FnOnce(&Composer) -> R) -> R {
1813 let _composer_guard = composer_context::enter(self);
1814 runtime::push_active_runtime(&self.core.runtime);
1815 struct Guard;
1816 impl Drop for Guard {
1817 fn drop(&mut self) {
1818 runtime::pop_active_runtime();
1819 }
1820 }
1821 let guard = Guard;
1822 let result = f(self);
1823 drop(guard);
1824 result
1825 }
1826
1827 pub fn with_group<R>(&self, key: Key, f: impl FnOnce(&Composer) -> R) -> R {
1828 let (group, scope_ref, restored_from_gap) = self.with_slots_mut(|slots| {
1829 let StartGroup {
1830 group,
1831 restored_from_gap,
1832 } = slots.begin_group(key);
1833 let scope_ref = slots
1834 .remember(|| RecomposeScope::new(self.runtime_handle()))
1835 .with(|scope| scope.clone());
1836 (group, scope_ref, restored_from_gap)
1837 });
1838
1839 if restored_from_gap {
1840 scope_ref.force_recompose();
1841 }
1842
1843 if let Some(options) = self.pending_scope_options().take() {
1844 if options.force_recompose {
1845 scope_ref.force_recompose();
1846 } else if options.force_reuse {
1847 scope_ref.force_reuse();
1848 }
1849 }
1850
1851 self.with_slots_mut(|slots| {
1852 SlotStorage::set_group_scope(slots, group, scope_ref.id());
1853 });
1854
1855 {
1856 let mut stack = self.scope_stack();
1857 stack.push(scope_ref.clone());
1858 }
1859
1860 {
1861 let mut stack = self.subcompose_stack();
1862 if let Some(frame) = stack.last_mut() {
1863 frame.scopes.push(scope_ref.clone());
1864 }
1865 }
1866
1867 {
1868 let locals = self.core.local_stack.borrow();
1869 scope_ref.snapshot_locals(&locals);
1870 }
1871 {
1872 let parent_hint = self.parent_stack().last().map(|frame| frame.id);
1873 scope_ref.set_parent_hint(parent_hint);
1874 }
1875
1876 let result = self.observe_scope(&scope_ref, || f(self));
1877
1878 let trimmed = self.with_slots_mut(|slots| slots.finalize_current_group());
1879 if trimmed {
1880 scope_ref.force_recompose();
1881 }
1882
1883 {
1884 let mut stack = self.scope_stack();
1885 stack.pop();
1886 }
1887 scope_ref.mark_recomposed();
1888 self.with_slots_mut(|slots| slots.end_group());
1889 result
1890 }
1891
1892 pub fn cranpose_with_reuse<R>(
1893 &self,
1894 key: Key,
1895 options: RecomposeOptions,
1896 f: impl FnOnce(&Composer) -> R,
1897 ) -> R {
1898 self.pending_scope_options().replace(options);
1899 self.with_group(key, f)
1900 }
1901
1902 pub fn with_key<K: Hash, R>(&self, key: &K, f: impl FnOnce(&Composer) -> R) -> R {
1903 let hashed = hash_key(key);
1904 self.with_group(hashed, f)
1905 }
1906
1907 pub fn remember<T: 'static>(&self, init: impl FnOnce() -> T) -> Owned<T> {
1908 self.with_slots_mut(|slots| slots.remember(init))
1909 }
1910
1911 pub fn use_value_slot<T: 'static>(&self, init: impl FnOnce() -> T) -> usize {
1912 self.with_slots_mut(|slots| slots.alloc_value_slot(init).index())
1913 }
1914
1915 pub fn with_slot_value<T: 'static, R>(&self, idx: usize, f: impl FnOnce(&T) -> R) -> R {
1916 self.with_slots(|slots| {
1917 let value = SlotStorage::read_value(slots, ValueSlotId::new(idx));
1918 f(value)
1919 })
1920 }
1921
1922 pub fn with_slot_value_mut<T: 'static, R>(&self, idx: usize, f: impl FnOnce(&mut T) -> R) -> R {
1923 self.with_slots_mut(|slots| {
1924 let value = SlotStorage::read_value_mut(slots, ValueSlotId::new(idx));
1925 f(value)
1926 })
1927 }
1928
1929 pub fn write_slot_value<T: 'static>(&self, idx: usize, value: T) {
1930 self.with_slots_mut(|slots| slots.write_value(ValueSlotId::new(idx), value));
1931 }
1932
1933 pub fn mutable_state_of<T: Clone + 'static>(&self, initial: T) -> MutableState<T> {
1934 MutableState::with_runtime(initial, self.runtime_handle())
1935 }
1936
1937 pub fn mutable_state_list_of<T, I>(&self, values: I) -> SnapshotStateList<T>
1938 where
1939 T: Clone + 'static,
1940 I: IntoIterator<Item = T>,
1941 {
1942 SnapshotStateList::with_runtime(values, self.runtime_handle())
1943 }
1944
1945 pub fn mutable_state_map_of<K, V, I>(&self, pairs: I) -> SnapshotStateMap<K, V>
1946 where
1947 K: Clone + Eq + Hash + 'static,
1948 V: Clone + 'static,
1949 I: IntoIterator<Item = (K, V)>,
1950 {
1951 SnapshotStateMap::with_runtime(pairs, self.runtime_handle())
1952 }
1953
1954 pub fn read_composition_local<T: Clone + 'static>(&self, local: &CompositionLocal<T>) -> T {
1955 let stack = self.core.local_stack.borrow();
1956 for context in stack.iter().rev() {
1957 if let Some(entry) = context.values.get(&local.key) {
1958 let typed = entry
1959 .clone()
1960 .downcast::<LocalStateEntry<T>>()
1961 .expect("composition local type mismatch");
1962 return typed.value();
1963 }
1964 }
1965 local.default_value()
1966 }
1967
1968 pub fn read_static_composition_local<T: Clone + 'static>(
1969 &self,
1970 local: &StaticCompositionLocal<T>,
1971 ) -> T {
1972 let stack = self.core.local_stack.borrow();
1973 for context in stack.iter().rev() {
1974 if let Some(entry) = context.values.get(&local.key) {
1975 let typed = entry
1976 .clone()
1977 .downcast::<StaticLocalEntry<T>>()
1978 .expect("static composition local type mismatch");
1979 return typed.value();
1980 }
1981 }
1982 local.default_value()
1983 }
1984
1985 pub fn current_recranpose_scope(&self) -> Option<RecomposeScope> {
1986 self.core.scope_stack.borrow().last().cloned()
1987 }
1988
1989 pub fn phase(&self) -> Phase {
1990 self.core.phase.get()
1991 }
1992
1993 pub(crate) fn set_phase(&self, phase: Phase) {
1994 self.core.phase.set(phase);
1995 }
1996
1997 pub fn enter_phase(&self, phase: Phase) {
1998 self.set_phase(phase);
1999 }
2000
2001 pub(crate) fn subcompose<R>(
2002 &self,
2003 state: &mut SubcomposeState,
2004 slot_id: SlotId,
2005 content: impl FnOnce(&Composer) -> R,
2006 ) -> (R, Vec<NodeId>) {
2007 match self.phase() {
2008 Phase::Measure | Phase::Layout => {}
2009 current => panic!(
2010 "subcompose() may only be called during measure or layout; current phase: {:?}",
2011 current
2012 ),
2013 }
2014
2015 self.subcompose_stack().push(SubcomposeFrame::default());
2016 struct StackGuard {
2017 core: Rc<ComposerCore>,
2018 leaked: bool,
2019 }
2020 impl Drop for StackGuard {
2021 fn drop(&mut self) {
2022 if !self.leaked {
2023 self.core.subcompose_stack.borrow_mut().pop();
2024 }
2025 }
2026 }
2027 let mut guard = StackGuard {
2028 core: self.clone_core(),
2029 leaked: false,
2030 };
2031
2032 let slot_host = state.get_or_create_slots(slot_id);
2033 {
2034 let mut slots = slot_host.borrow_mut();
2035 slots.reset();
2036 }
2037 let result = self.with_slot_override(slot_host.clone(), |composer| {
2038 composer.with_group(slot_id.raw(), |composer| content(composer))
2040 });
2041 {
2042 let mut slots = slot_host.borrow_mut();
2043 slots.finalize_current_group();
2044 slots.flush();
2045 }
2046
2047 let frame = {
2048 let mut stack = guard.core.subcompose_stack.borrow_mut();
2049 let frame = stack.pop().expect("subcompose stack underflow");
2050 guard.leaked = true;
2051 frame
2052 };
2053 let nodes = frame.nodes;
2054 let scopes = frame.scopes;
2055 state.register_active(slot_id, &nodes, &scopes);
2056 (result, nodes)
2057 }
2058
2059 pub fn subcompose_measurement<R>(
2060 &self,
2061 state: &mut SubcomposeState,
2062 slot_id: SlotId,
2063 content: impl FnOnce(&Composer) -> R,
2064 ) -> (R, Vec<NodeId>) {
2065 let (result, nodes) = self.subcompose(state, slot_id, content);
2066
2067 let roots = nodes
2071 .into_iter()
2072 .filter(|&id| self.node_has_no_parent(id))
2073 .collect();
2074
2075 (result, roots)
2076 }
2077
2078 pub fn subcompose_in<R>(
2079 &self,
2080 slots: &Rc<SlotsHost>,
2081 root: Option<NodeId>,
2082 f: impl FnOnce(&Composer) -> R,
2083 ) -> Result<R, NodeError> {
2084 let runtime_handle = self.runtime_handle();
2085 slots.borrow_mut().reset();
2086 let phase = self.phase();
2087 let locals = self.core.local_stack.borrow().clone();
2088 let core = Rc::new(ComposerCore::new(
2089 Rc::clone(slots),
2090 Rc::clone(&self.core.applier),
2091 runtime_handle.clone(),
2092 self.observer(),
2093 root,
2094 ));
2095 core.phase.set(phase);
2096 *core.local_stack.borrow_mut() = locals;
2097 let composer = Composer::from_core(core);
2098 let (result, mut commands, side_effects) = composer.install(|composer| {
2099 let output = f(composer);
2100 let commands = composer.take_commands();
2101 let side_effects = composer.take_side_effects();
2102 (output, commands, side_effects)
2103 });
2104
2105 {
2106 let mut applier = self.borrow_applier();
2107 for mut command in commands.drain(..) {
2108 command(&mut *applier)?;
2109 }
2110 for mut update in runtime_handle.take_updates() {
2111 update(&mut *applier)?;
2112 }
2113 }
2114 runtime_handle.drain_ui();
2115 for effect in side_effects {
2116 effect();
2117 }
2118 runtime_handle.drain_ui();
2119 {
2120 let mut slots_mut = slots.borrow_mut();
2121 slots_mut.finalize_current_group();
2122 slots_mut.flush();
2123 }
2124 Ok(result)
2125 }
2126
2127 pub fn subcompose_slot<R>(
2132 &self,
2133 slots: &Rc<SlotsHost>,
2134 root: Option<NodeId>,
2135 f: impl FnOnce(&Composer) -> R,
2136 ) -> Result<R, NodeError> {
2137 let runtime_handle = self.runtime_handle();
2138 slots.borrow_mut().reset();
2141 let phase = self.phase();
2142 let locals = self.core.local_stack.borrow().clone();
2143 let core = Rc::new(ComposerCore::new(
2144 Rc::clone(slots),
2145 Rc::clone(&self.core.applier),
2146 runtime_handle.clone(),
2147 self.observer(),
2148 root, ));
2150 core.phase.set(phase);
2151 *core.local_stack.borrow_mut() = locals;
2152 let composer = Composer::from_core(core);
2153 let (result, mut commands, side_effects) = composer.install(|composer| {
2154 let output = f(composer);
2155 if root.is_some() {
2159 composer.pop_parent();
2160 }
2161 let commands = composer.take_commands();
2162 let side_effects = composer.take_side_effects();
2163 (output, commands, side_effects)
2164 });
2165
2166 {
2167 let mut applier = self.borrow_applier();
2168 for mut command in commands.drain(..) {
2169 command(&mut *applier)?;
2170 }
2171 for mut update in runtime_handle.take_updates() {
2172 update(&mut *applier)?;
2173 }
2174 }
2175 runtime_handle.drain_ui();
2176 for effect in side_effects {
2177 effect();
2178 }
2179 runtime_handle.drain_ui();
2180 Ok(result)
2185 }
2186
2187 pub fn skip_current_group(&self) {
2188 let nodes = self.with_slots(|slots| slots.nodes_in_current_group());
2189 self.with_slots_mut(|slots| slots.skip_current_group());
2190 let current_parent = {
2192 let stack = self.parent_stack();
2193 stack.last().map(|frame| frame.id)
2194 };
2195
2196 let mut applier = self.borrow_applier();
2200 for id in nodes {
2201 if let Ok(node) = applier.get_mut(id) {
2202 let node_parent = node.parent();
2203 if node_parent.is_none() || node_parent == current_parent {
2204 drop(applier);
2205 self.attach_to_parent(id);
2206 applier = self.borrow_applier();
2207 }
2208 }
2209 }
2210 }
2211
2212 pub fn runtime_handle(&self) -> RuntimeHandle {
2213 self.core.runtime.clone()
2214 }
2215
2216 pub fn set_recranpose_callback<F>(&self, callback: F)
2217 where
2218 F: FnMut(&Composer) + 'static,
2219 {
2220 if let Some(scope) = self.current_recranpose_scope() {
2221 let observer = self.observer();
2222 let scope_weak = scope.downgrade();
2223 let mut callback = callback;
2224 scope.set_recompose(Box::new(move |composer: &Composer| {
2225 if let Some(inner) = scope_weak.upgrade() {
2226 let scope_instance = RecomposeScope { inner };
2227 observer.observe_reads(
2228 scope_instance.clone(),
2229 move |scope_ref| scope_ref.invalidate(),
2230 || {
2231 callback(composer);
2232 },
2233 );
2234 }
2235 }));
2236 }
2237 }
2238
2239 pub fn with_composition_locals<R>(
2240 &self,
2241 provided: Vec<ProvidedValue>,
2242 f: impl FnOnce(&Composer) -> R,
2243 ) -> R {
2244 if provided.is_empty() {
2245 return f(self);
2246 }
2247 let mut context = LocalContext::default();
2248 for value in provided {
2249 let (key, entry) = value.into_entry(self);
2250 context.values.insert(key, entry);
2251 }
2252 {
2253 let mut stack = self.local_stack();
2254 stack.push(context);
2255 }
2256 let result = f(self);
2257 {
2258 let mut stack = self.local_stack();
2259 stack.pop();
2260 }
2261 result
2262 }
2263
2264 fn recranpose_group(&self, scope: &RecomposeScope) {
2265 if !scope.is_invalid() {
2271 scope.mark_recomposed();
2272 return;
2273 }
2274 let started = self.with_slots_mut(|slots| slots.begin_recranpose_at_scope(scope.id()));
2275 if started.is_some() {
2276 let previous_hint = self
2277 .core
2278 .recranpose_parent_hint
2279 .replace(scope.parent_hint());
2280 struct HintGuard {
2281 core: Rc<ComposerCore>,
2282 previous: Option<NodeId>,
2283 }
2284 impl Drop for HintGuard {
2285 fn drop(&mut self) {
2286 self.core.recranpose_parent_hint.set(self.previous);
2287 }
2288 }
2289 let _hint_guard = HintGuard {
2290 core: self.clone_core(),
2291 previous: previous_hint,
2292 };
2293 {
2294 let mut stack = self.scope_stack();
2295 stack.push(scope.clone());
2296 }
2297 let saved_locals = {
2298 let mut locals = self.local_stack();
2299 std::mem::take(&mut *locals)
2300 };
2301 {
2302 let mut locals = self.local_stack();
2303 *locals = scope.local_stack();
2304 }
2305 self.observe_scope(scope, || {
2306 scope.run_recompose(self);
2307 });
2308 {
2309 let mut locals = self.local_stack();
2310 *locals = saved_locals;
2311 }
2312 {
2313 let mut stack = self.scope_stack();
2314 stack.pop();
2315 }
2316 self.with_slots_mut(SlotStorage::end_recompose);
2317 scope.mark_recomposed();
2318 } else {
2319 scope.mark_recomposed();
2320 }
2321 }
2322
2323 pub fn use_state<T: Clone + 'static>(&self, init: impl FnOnce() -> T) -> MutableState<T> {
2324 let runtime = self.runtime_handle();
2325 let state = self.with_slots_mut(|slots| {
2326 slots.remember(|| MutableState::with_runtime(init(), runtime.clone()))
2327 });
2328 state.with(|state| *state)
2329 }
2330
2331 pub fn emit_node<N: Node + 'static>(&self, init: impl FnOnce() -> N) -> NodeId {
2332 let (existing_id, type_matches) = {
2334 if let Some(id) = self.with_slots_mut(|slots| slots.peek_node()) {
2335 let mut applier = self.borrow_applier();
2337 let matches = match applier.get_mut(id) {
2338 Ok(node) => node.as_any_mut().downcast_ref::<N>().is_some(),
2339 Err(_) => false,
2340 };
2341 (Some(id), matches)
2342 } else {
2343 (None, false)
2344 }
2345 };
2346
2347 if let Some(id) = existing_id {
2349 if type_matches {
2350 let reuse_allowed = true;
2354
2355 #[cfg(not(target_arch = "wasm32"))]
2356 if compose_debug_enabled() {
2357 eprintln!("emit_node: candidate #{id} reuse_allowed={reuse_allowed}");
2358 }
2359
2360 if reuse_allowed {
2361 self.core.last_node_reused.set(Some(true));
2362 #[cfg(not(target_arch = "wasm32"))]
2363 if compose_debug_enabled() {
2364 eprintln!(
2365 "emit_node: reusing node #{id} as {}",
2366 std::any::type_name::<N>()
2367 );
2368 }
2369 self.with_slots_mut(|slots| slots.advance_after_node_read());
2370
2371 self.commands_mut()
2372 .push(Box::new(move |applier: &mut dyn Applier| {
2373 let node = match applier.get_mut(id) {
2374 Ok(node) => node,
2375 Err(NodeError::Missing { .. }) => return Ok(()),
2376 Err(err) => return Err(err),
2377 };
2378 let typed = node.as_any_mut().downcast_mut::<N>().ok_or(
2379 NodeError::TypeMismatch {
2380 id,
2381 expected: std::any::type_name::<N>(),
2382 },
2383 )?;
2384 typed.update();
2385 Ok(())
2386 }));
2387 self.attach_to_parent(id);
2388 return id;
2389 }
2390 }
2391 }
2392
2393 if let Some(old_id) = existing_id {
2395 if !type_matches {
2396 #[cfg(not(target_arch = "wasm32"))]
2397 if compose_debug_enabled() {
2398 eprintln!(
2399 "emit_node: replacing node #{old_id} with new {}",
2400 std::any::type_name::<N>()
2401 );
2402 }
2403 self.commands_mut()
2404 .push(Box::new(move |applier: &mut dyn Applier| {
2405 if let Ok(node) = applier.get_mut(old_id) {
2406 node.unmount();
2407 }
2408 match applier.remove(old_id) {
2409 Ok(()) | Err(NodeError::Missing { .. }) => Ok(()),
2410 Err(err) => Err(err),
2411 }
2412 }));
2413 }
2414 }
2415
2416 let id = {
2419 let mut applier = self.borrow_applier();
2420 applier.create(Box::new(init()))
2421 };
2422 self.core.last_node_reused.set(Some(false));
2423 #[cfg(not(target_arch = "wasm32"))]
2424 if compose_debug_enabled() {
2425 eprintln!(
2426 "emit_node: creating node #{} as {}",
2427 id,
2428 std::any::type_name::<N>()
2429 );
2430 }
2431 {
2432 self.with_slots_mut(|slots| slots.record_node(id));
2433 }
2434 self.commands_mut()
2435 .push(Box::new(move |applier: &mut dyn Applier| {
2436 let node = match applier.get_mut(id) {
2437 Ok(node) => node,
2438 Err(NodeError::Missing { .. }) => return Ok(()),
2439 Err(err) => return Err(err),
2440 };
2441 node.set_node_id(id);
2442 node.mount();
2443 Ok(())
2444 }));
2445 self.attach_to_parent(id);
2446 id
2447 }
2448
2449 fn attach_to_parent(&self, id: NodeId) {
2450 let mut parent_stack = self.parent_stack();
2456 if let Some(frame) = parent_stack.last_mut() {
2457 let parent_id = frame.id;
2458 if parent_id == id {
2459 return;
2460 }
2461 frame.new_children.push(id);
2462 drop(parent_stack);
2463
2464 {
2475 let mut applier = self.borrow_applier();
2476 if let Ok(child_node) = applier.get_mut(id) {
2477 let existing_parent = child_node.parent();
2478 let should_set = match existing_parent {
2483 None => true,
2484 Some(existing) => {
2485 let root_id = self.core.root.get();
2487 parent_id != root_id.unwrap_or(0) || existing == root_id.unwrap_or(0)
2488 }
2489 };
2490 if should_set {
2491 child_node.set_parent_for_bubbling(parent_id);
2492 }
2493 }
2494 }
2495 return;
2496 }
2497 drop(parent_stack);
2498
2499 let in_subcompose = !self.subcompose_stack().is_empty();
2501 if in_subcompose {
2502 let has_parent = {
2506 let mut applier = self.borrow_applier();
2507 applier
2508 .get_mut(id)
2509 .map(|node| node.parent().is_some())
2510 .unwrap_or(false)
2511 };
2512
2513 if !has_parent {
2514 let mut subcompose_stack = self.subcompose_stack();
2515 if let Some(frame) = subcompose_stack.last_mut() {
2516 frame.nodes.push(id);
2517 }
2518 }
2519 return;
2520 }
2521
2522 if let Some(parent_hint) = self.core.recranpose_parent_hint.get() {
2524 let parent_status = {
2525 let mut applier = self.borrow_applier();
2526 applier
2527 .get_mut(id)
2528 .map(|node| node.parent())
2529 .unwrap_or(None)
2530 };
2531 match parent_status {
2532 Some(existing) if existing == parent_hint => {}
2533 None => {
2534 self.commands_mut()
2535 .push(Box::new(move |applier: &mut dyn Applier| {
2536 if let Ok(parent_node) = applier.get_mut(parent_hint) {
2537 parent_node.insert_child(id);
2538 }
2539 if let Ok(child_node) = applier.get_mut(id) {
2540 child_node.on_attached_to_parent(parent_hint);
2541 }
2542 bubble_layout_dirty(applier, parent_hint);
2543 bubble_measure_dirty(applier, parent_hint);
2544 Ok(())
2545 }));
2546 }
2547 Some(_) => {}
2548 }
2549 return;
2550 }
2551
2552 let has_parent = {
2557 let mut applier = self.borrow_applier();
2558 applier
2559 .get_mut(id)
2560 .map(|node| node.parent().is_some())
2561 .unwrap_or(false)
2562 };
2563 if has_parent {
2564 return;
2566 }
2567
2568 self.set_root(Some(id));
2570 }
2571
2572 pub fn with_node_mut<N: Node + 'static, R>(
2573 &self,
2574 id: NodeId,
2575 f: impl FnOnce(&mut N) -> R,
2576 ) -> Result<R, NodeError> {
2577 let mut applier = self.borrow_applier();
2578 let node = applier.get_mut(id)?;
2579 let typed = node
2580 .as_any_mut()
2581 .downcast_mut::<N>()
2582 .ok_or(NodeError::TypeMismatch {
2583 id,
2584 expected: std::any::type_name::<N>(),
2585 })?;
2586 Ok(f(typed))
2587 }
2588
2589 pub fn push_parent(&self, id: NodeId) {
2590 let remembered = self.remember(ParentChildren::default);
2591 let reused = self.core.last_node_reused.take().unwrap_or(true);
2592 let in_subcompose = !self.core.subcompose_stack.borrow().is_empty();
2593
2594 let previous = if reused || in_subcompose {
2597 remembered.with(|entry| entry.children.clone())
2598 } else {
2599 Vec::new()
2600 };
2601
2602 self.parent_stack().push(ParentFrame {
2603 id,
2604 remembered,
2605 previous,
2606 new_children: Vec::new(),
2607 });
2608 }
2609
2610 pub fn pop_parent(&self) {
2611 let frame_opt = {
2612 let mut stack = self.parent_stack();
2613 stack.pop()
2614 };
2615 if let Some(frame) = frame_opt {
2616 let ParentFrame {
2617 id,
2618 remembered,
2619 previous,
2620 new_children,
2621 } = frame;
2622
2623 #[cfg(not(target_arch = "wasm32"))]
2624 if compose_debug_enabled() {
2625 eprintln!("pop_parent: node #{}", id);
2626 eprintln!(" previous children: {:?}", previous);
2627 eprintln!(" new children: {:?}", new_children);
2628 }
2629 let children_changed = previous != new_children;
2630
2631 if children_changed {
2632 let mut current = previous.clone();
2633 let target = new_children.clone();
2634 let desired: HashSet<NodeId> = target.iter().copied().collect();
2635
2636 for index in (0..current.len()).rev() {
2637 let child = current[index];
2638 if !desired.contains(&child) {
2639 current.remove(index);
2640 self.commands_mut()
2641 .push(Box::new(move |applier: &mut dyn Applier| {
2642 if let Ok(parent_node) = applier.get_mut(id) {
2644 parent_node.remove_child(child);
2645 }
2646 bubble_layout_dirty(applier, id);
2648 bubble_measure_dirty(applier, id);
2649 let should_remove = if let Ok(node) = applier.get_mut(child) {
2653 match node.parent() {
2654 Some(parent_id) if parent_id == id => {
2655 node.on_removed_from_parent();
2656 node.unmount();
2657 true
2658 }
2659 None => {
2660 node.unmount();
2662 true
2663 }
2664 Some(_) => false,
2665 }
2666 } else {
2667 true
2668 };
2669
2670 if should_remove {
2671 let _ = applier.remove(child);
2672 }
2673 Ok(())
2674 }));
2675 }
2676 }
2677
2678 for (target_index, &child) in target.iter().enumerate() {
2679 if let Some(current_index) = current.iter().position(|&c| c == child) {
2680 if current_index != target_index {
2681 let from_index = current_index;
2682 current.remove(from_index);
2683 let to_index = target_index.min(current.len());
2684 current.insert(to_index, child);
2685 self.commands_mut()
2686 .push(Box::new(move |applier: &mut dyn Applier| {
2687 if let Ok(parent_node) = applier.get_mut(id) {
2688 parent_node.move_child(from_index, to_index);
2689 }
2690 Ok(())
2691 }));
2692 self.commands_mut()
2693 .push(Box::new(move |applier: &mut dyn Applier| {
2694 bubble_layout_dirty(applier, id);
2697 bubble_measure_dirty(applier, id);
2698 Ok(())
2699 }));
2700 }
2701 } else {
2702 let insert_index = target_index.min(current.len());
2703 let appended_index = current.len();
2704 current.insert(insert_index, child);
2705 self.commands_mut()
2706 .push(Box::new(move |applier: &mut dyn Applier| {
2707 let old_parent =
2710 applier.get_mut(child).ok().and_then(|node| node.parent());
2711 if let Some(old_parent_id) = old_parent {
2712 if old_parent_id != id {
2713 if let Ok(old_parent_node) = applier.get_mut(old_parent_id)
2714 {
2715 old_parent_node.remove_child(child);
2716 }
2717 if let Ok(child_node) = applier.get_mut(child) {
2718 child_node.on_removed_from_parent();
2719 }
2720 bubble_layout_dirty(applier, old_parent_id);
2721 bubble_measure_dirty(applier, old_parent_id);
2722 }
2723 }
2724 if let Ok(parent_node) = applier.get_mut(id) {
2726 parent_node.insert_child(child);
2727 }
2728 if let Ok(child_node) = applier.get_mut(child) {
2730 child_node.on_attached_to_parent(id);
2731 }
2732 bubble_layout_dirty(applier, id);
2734 bubble_measure_dirty(applier, id);
2735 Ok(())
2736 }));
2737 if insert_index != appended_index {
2738 self.commands_mut()
2739 .push(Box::new(move |applier: &mut dyn Applier| {
2740 if let Ok(parent_node) = applier.get_mut(id) {
2741 parent_node.move_child(appended_index, insert_index);
2742 }
2743 Ok(())
2744 }));
2745 }
2746 }
2747 }
2748 }
2749
2750 let expected_children = new_children.clone();
2751 let needs_dirty_check = !children_changed;
2752 self.commands_mut()
2753 .push(Box::new(move |applier: &mut dyn Applier| {
2754 let mut repaired = false;
2755 for &child in &expected_children {
2756 let needs_attach = if let Ok(node) = applier.get_mut(child) {
2757 node.parent() != Some(id)
2758 } else {
2759 false
2760 };
2761 if needs_attach {
2762 let old_parent =
2763 applier.get_mut(child).ok().and_then(|node| node.parent());
2764 if let Some(old_parent_id) = old_parent {
2765 if old_parent_id != id {
2766 if let Ok(old_parent_node) = applier.get_mut(old_parent_id) {
2767 old_parent_node.remove_child(child);
2768 }
2769 if let Ok(child_node) = applier.get_mut(child) {
2770 child_node.on_removed_from_parent();
2771 }
2772 bubble_layout_dirty(applier, old_parent_id);
2773 bubble_measure_dirty(applier, old_parent_id);
2774 }
2775 }
2776 if let Ok(parent_node) = applier.get_mut(id) {
2777 parent_node.insert_child(child);
2778 }
2779 if let Ok(child_node) = applier.get_mut(child) {
2780 child_node.on_attached_to_parent(id);
2781 }
2782 repaired = true;
2783 }
2784 }
2785 let is_dirty = if needs_dirty_check {
2786 if let Ok(node) = applier.get_mut(id) {
2787 node.needs_layout()
2788 } else {
2789 false
2790 }
2791 } else {
2792 false
2793 };
2794 if repaired {
2795 bubble_layout_dirty(applier, id);
2796 bubble_measure_dirty(applier, id);
2797 } else if is_dirty {
2798 bubble_layout_dirty(applier, id);
2799 }
2800 Ok(())
2801 }));
2802
2803 remembered.update(|entry| entry.children = new_children);
2804 }
2805 }
2806
2807 pub fn take_commands(&self) -> Vec<Command> {
2808 std::mem::take(&mut *self.commands_mut())
2809 }
2810
2811 pub fn apply_pending_commands(&self) -> Result<(), NodeError> {
2816 let mut commands = self.take_commands();
2817 let runtime_handle = self.runtime_handle();
2818 {
2819 let mut applier = self.borrow_applier();
2820 for mut command in commands.drain(..) {
2821 command(&mut *applier)?;
2822 }
2823 for mut update in runtime_handle.take_updates() {
2824 update(&mut *applier)?;
2825 }
2826 }
2827 runtime_handle.drain_ui();
2828 Ok(())
2829 }
2830
2831 pub fn register_side_effect(&self, effect: impl FnOnce() + 'static) {
2832 self.side_effects_mut().push(Box::new(effect));
2833 }
2834
2835 pub fn take_side_effects(&self) -> Vec<Box<dyn FnOnce()>> {
2836 std::mem::take(&mut *self.side_effects_mut())
2837 }
2838
2839 pub(crate) fn root(&self) -> Option<NodeId> {
2840 self.core.root.get()
2841 }
2842
2843 pub(crate) fn set_root(&self, node: Option<NodeId>) {
2844 self.core.root.set(node);
2845 }
2846}
2847
2848#[derive(Default, Clone)]
2849struct ParentChildren {
2850 children: Vec<NodeId>,
2851}
2852
2853struct ParentFrame {
2854 id: NodeId,
2855 remembered: Owned<ParentChildren>,
2856 previous: Vec<NodeId>,
2857 new_children: Vec<NodeId>,
2858}
2859
2860#[derive(Default)]
2861struct SubcomposeFrame {
2862 nodes: Vec<NodeId>,
2863 scopes: Vec<RecomposeScope>,
2864}
2865
2866#[derive(Default, Clone)]
2867struct LocalContext {
2868 values: HashMap<LocalKey, Rc<dyn Any>>,
2869}
2870
2871pub(crate) struct MutableStateInner<T: Clone + 'static> {
2872 state: Arc<SnapshotMutableState<T>>,
2873 watchers: RefCell<Vec<Weak<RecomposeScopeInner>>>, runtime: RuntimeHandle,
2875}
2876
2877impl<T: Clone + 'static> MutableStateInner<T> {
2878 fn new(value: T, runtime: RuntimeHandle) -> Self {
2879 Self {
2880 state: SnapshotMutableState::new_in_arc(value, Arc::new(NeverEqual)),
2881 watchers: RefCell::new(Vec::new()),
2882 runtime,
2883 }
2884 }
2885
2886 fn install_snapshot_observer(&self, state_id: StateId) {
2887 let runtime_handle = self.runtime.clone();
2888 self.state.add_apply_observer(Box::new(move || {
2889 let runtime = runtime_handle.clone();
2890 runtime_handle.enqueue_ui_task(Box::new(move || {
2891 runtime.with_state_arena(|arena| {
2892 if let Some(inner) = arena.get_typed_opt::<T>(state_id) {
2893 inner.invalidate_watchers();
2894 }
2895 });
2896 }));
2897 }));
2898 }
2899
2900 fn with_value<R>(&self, f: impl FnOnce(&T) -> R) -> R {
2901 let value = self.state.get();
2902 f(&value)
2903 }
2904
2905 fn invalidate_watchers(&self) {
2906 let watchers: Vec<RecomposeScope> = {
2907 let mut watchers = self.watchers.borrow_mut();
2908 watchers.retain(|w| w.strong_count() > 0);
2909 watchers
2910 .iter()
2911 .filter_map(|w| w.upgrade())
2912 .map(|inner| RecomposeScope { inner })
2913 .collect()
2914 };
2915
2916 for watcher in watchers {
2917 watcher.invalidate();
2918 }
2919 }
2920}
2921
2922#[derive(Clone)]
2923pub struct State<T: Clone + 'static> {
2924 id: StateId,
2925 runtime_id: RuntimeId,
2926 _marker: PhantomData<fn() -> T>,
2927}
2928
2929impl<T: Clone + 'static> Copy for State<T> {}
2930
2931#[derive(Clone)]
2932pub struct MutableState<T: Clone + 'static> {
2933 id: StateId,
2934 runtime_id: RuntimeId,
2935 _marker: PhantomData<fn() -> T>,
2936}
2937
2938impl<T: Clone + 'static> Copy for MutableState<T> {}
2939
2940impl<T: Clone + 'static> PartialEq for State<T> {
2941 fn eq(&self, other: &Self) -> bool {
2942 self.id == other.id && self.runtime_id == other.runtime_id
2943 }
2944}
2945
2946impl<T: Clone + 'static> Eq for State<T> {}
2947
2948impl<T: Clone + 'static> PartialEq for MutableState<T> {
2949 fn eq(&self, other: &Self) -> bool {
2950 self.id == other.id && self.runtime_id == other.runtime_id
2951 }
2952}
2953
2954impl<T: Clone + 'static> Eq for MutableState<T> {}
2955
2956impl<T: Clone + 'static> State<T> {
2957 fn runtime_handle(&self) -> RuntimeHandle {
2958 runtime_handle_for(self.runtime_id).expect("runtime handle missing")
2959 }
2960
2961 fn with_inner<R>(&self, f: impl FnOnce(&MutableStateInner<T>) -> R) -> R {
2962 self.runtime_handle().with_state_arena(|arena| {
2963 let inner = arena.get_typed::<T>(self.id);
2964 f(&inner)
2965 })
2966 }
2967
2968 fn subscribe_current_scope(&self) {
2969 if let Some(Some(scope)) =
2970 with_current_composer_opt(|composer| composer.current_recranpose_scope())
2971 {
2972 self.with_inner(|inner| {
2973 let mut watchers = inner.watchers.borrow_mut();
2974 watchers.retain(|w| w.strong_count() > 0);
2975 let id = scope.id();
2976 let already_registered = watchers
2977 .iter()
2978 .any(|w| w.upgrade().map(|inner| inner.id == id).unwrap_or(false));
2979 if !already_registered {
2980 watchers.push(scope.downgrade());
2981 }
2982 });
2983 }
2984 }
2985
2986 pub fn with<R>(&self, f: impl FnOnce(&T) -> R) -> R {
2987 self.subscribe_current_scope();
2988 self.with_inner(|inner| inner.with_value(f))
2989 }
2990
2991 pub fn value(&self) -> T {
2992 self.subscribe_current_scope();
2993 self.with(|value| value.clone())
2994 }
2995
2996 pub fn get(&self) -> T {
2997 self.value()
2998 }
2999}
3000
3001impl<T: Clone + 'static> MutableState<T> {
3002 pub fn with_runtime(value: T, runtime: RuntimeHandle) -> Self {
3003 let id = runtime.alloc_state(value);
3004 Self {
3005 id,
3006 runtime_id: runtime.id(),
3007 _marker: PhantomData,
3008 }
3009 }
3010
3011 fn runtime_handle(&self) -> RuntimeHandle {
3012 runtime_handle_for(self.runtime_id).expect("runtime handle missing")
3013 }
3014
3015 fn with_inner<R>(&self, f: impl FnOnce(&MutableStateInner<T>) -> R) -> R {
3016 self.runtime_handle().with_state_arena(|arena| {
3017 let inner = arena.get_typed::<T>(self.id);
3018 f(&inner)
3019 })
3020 }
3021
3022 pub fn as_state(&self) -> State<T> {
3023 State {
3024 id: self.id,
3025 runtime_id: self.runtime_id,
3026 _marker: PhantomData,
3027 }
3028 }
3029
3030 pub fn with<R>(&self, f: impl FnOnce(&T) -> R) -> R {
3031 self.as_state().with(f)
3032 }
3033
3034 pub fn update<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
3035 let runtime = self.runtime_handle();
3036 runtime.assert_ui_thread();
3037 runtime.with_state_arena(|arena| {
3038 let inner = arena.get_typed::<T>(self.id);
3039 let mut value = inner.state.get();
3040 let tracker = UpdateScope::new(inner.state.id());
3041 let result = f(&mut value);
3042 let wrote_elsewhere = tracker.finish();
3043 if !wrote_elsewhere {
3044 inner.state.set(value);
3045 }
3046 inner.invalidate_watchers();
3047 result
3048 })
3049 }
3050
3051 pub fn replace(&self, value: T) {
3052 let runtime = self.runtime_handle();
3053 runtime.assert_ui_thread();
3054 runtime.with_state_arena(|arena| {
3055 let inner = arena.get_typed::<T>(self.id);
3056 inner.state.set(value);
3057 inner.invalidate_watchers();
3058 });
3059 }
3060
3061 pub fn set_value(&self, value: T) {
3062 self.replace(value);
3063 }
3064
3065 pub fn set(&self, value: T) {
3066 self.replace(value);
3067 }
3068
3069 pub fn value(&self) -> T {
3070 self.as_state().value()
3071 }
3072
3073 pub fn get(&self) -> T {
3074 self.value()
3075 }
3076
3077 pub fn get_non_reactive(&self) -> T {
3090 self.with_inner(|inner| inner.state.get())
3092 }
3093
3094 #[cfg(test)]
3095 pub(crate) fn watcher_count(&self) -> usize {
3096 self.with_inner(|inner| inner.watchers.borrow().len())
3097 }
3098}
3099
3100impl<T: fmt::Debug + Clone + 'static> fmt::Debug for MutableState<T> {
3101 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3102 self.with_inner(|inner| {
3103 inner.with_value(|value| {
3104 f.debug_struct("MutableState")
3105 .field("value", value)
3106 .finish()
3107 })
3108 })
3109 }
3110}
3111
3112#[derive(Clone)]
3113pub struct SnapshotStateList<T: Clone + 'static> {
3114 state: MutableState<Vec<T>>,
3115}
3116
3117impl<T: Clone + 'static> SnapshotStateList<T> {
3118 pub fn with_runtime<I>(values: I, runtime: RuntimeHandle) -> Self
3119 where
3120 I: IntoIterator<Item = T>,
3121 {
3122 let initial: Vec<T> = values.into_iter().collect();
3123 Self {
3124 state: MutableState::with_runtime(initial, runtime),
3125 }
3126 }
3127
3128 pub fn as_state(&self) -> State<Vec<T>> {
3129 self.state.as_state()
3130 }
3131
3132 pub fn as_mutable_state(&self) -> MutableState<Vec<T>> {
3133 self.state
3134 }
3135
3136 pub fn len(&self) -> usize {
3137 self.state.with(|values| values.len())
3138 }
3139
3140 pub fn is_empty(&self) -> bool {
3141 self.len() == 0
3142 }
3143
3144 pub fn to_vec(&self) -> Vec<T> {
3145 self.state.with(|values| values.clone())
3146 }
3147
3148 pub fn iter(&self) -> Vec<T> {
3149 self.to_vec()
3150 }
3151
3152 pub fn get(&self, index: usize) -> T {
3153 self.state.with(|values| values[index].clone())
3154 }
3155
3156 pub fn get_opt(&self, index: usize) -> Option<T> {
3157 self.state.with(|values| values.get(index).cloned())
3158 }
3159
3160 pub fn first(&self) -> Option<T> {
3161 self.get_opt(0)
3162 }
3163
3164 pub fn last(&self) -> Option<T> {
3165 self.state.with(|values| values.last().cloned())
3166 }
3167
3168 pub fn push(&self, value: T) {
3169 self.state.update(|values| values.push(value));
3170 }
3171
3172 pub fn extend<I>(&self, iter: I)
3173 where
3174 I: IntoIterator<Item = T>,
3175 {
3176 self.state.update(|values| values.extend(iter));
3177 }
3178
3179 pub fn insert(&self, index: usize, value: T) {
3180 self.state.update(|values| values.insert(index, value));
3181 }
3182
3183 pub fn set(&self, index: usize, value: T) -> T {
3184 self.state
3185 .update(|values| std::mem::replace(&mut values[index], value))
3186 }
3187
3188 pub fn remove(&self, index: usize) -> T {
3189 self.state.update(|values| values.remove(index))
3190 }
3191
3192 pub fn pop(&self) -> Option<T> {
3193 self.state.update(|values| values.pop())
3194 }
3195
3196 pub fn clear(&self) {
3197 self.state.replace(Vec::new());
3198 }
3199
3200 pub fn retain<F>(&self, mut predicate: F)
3201 where
3202 F: FnMut(&T) -> bool,
3203 {
3204 self.state
3205 .update(|values| values.retain(|value| predicate(value)));
3206 }
3207
3208 pub fn replace_with<I>(&self, iter: I)
3209 where
3210 I: IntoIterator<Item = T>,
3211 {
3212 self.state.replace(iter.into_iter().collect());
3213 }
3214}
3215
3216impl<T: fmt::Debug + Clone + 'static> fmt::Debug for SnapshotStateList<T> {
3217 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3218 let contents = self.to_vec();
3219 f.debug_struct("SnapshotStateList")
3220 .field("values", &contents)
3221 .finish()
3222 }
3223}
3224
3225#[derive(Clone)]
3226pub struct SnapshotStateMap<K, V>
3227where
3228 K: Clone + Eq + Hash + 'static,
3229 V: Clone + 'static,
3230{
3231 state: MutableState<HashMap<K, V>>,
3232}
3233
3234impl<K, V> SnapshotStateMap<K, V>
3235where
3236 K: Clone + Eq + Hash + 'static,
3237 V: Clone + 'static,
3238{
3239 pub fn with_runtime<I>(pairs: I, runtime: RuntimeHandle) -> Self
3240 where
3241 I: IntoIterator<Item = (K, V)>,
3242 {
3243 let map: HashMap<K, V> = pairs.into_iter().collect();
3244 Self {
3245 state: MutableState::with_runtime(map, runtime),
3246 }
3247 }
3248
3249 pub fn as_state(&self) -> State<HashMap<K, V>> {
3250 self.state.as_state()
3251 }
3252
3253 pub fn as_mutable_state(&self) -> MutableState<HashMap<K, V>> {
3254 self.state
3255 }
3256
3257 pub fn len(&self) -> usize {
3258 self.state.with(|map| map.len())
3259 }
3260
3261 pub fn is_empty(&self) -> bool {
3262 self.state.with(|map| map.is_empty())
3263 }
3264
3265 pub fn contains_key(&self, key: &K) -> bool {
3266 self.state.with(|map| map.contains_key(key))
3267 }
3268
3269 pub fn get(&self, key: &K) -> Option<V> {
3270 self.state.with(|map| map.get(key).cloned())
3271 }
3272
3273 pub fn to_hash_map(&self) -> HashMap<K, V> {
3274 self.state.with(|map| map.clone())
3275 }
3276
3277 pub fn insert(&self, key: K, value: V) -> Option<V> {
3278 self.state.update(|map| map.insert(key, value))
3279 }
3280
3281 pub fn extend<I>(&self, iter: I)
3282 where
3283 I: IntoIterator<Item = (K, V)>,
3284 {
3285 self.state.update(|map| map.extend(iter));
3286 }
3288
3289 pub fn remove(&self, key: &K) -> Option<V> {
3290 self.state.update(|map| map.remove(key))
3291 }
3292
3293 pub fn clear(&self) {
3294 self.state.replace(HashMap::default());
3295 }
3296
3297 pub fn retain<F>(&self, mut predicate: F)
3298 where
3299 F: FnMut(&K, &mut V) -> bool,
3300 {
3301 self.state.update(|map| map.retain(|k, v| predicate(k, v)));
3302 }
3303}
3304
3305impl<K, V> fmt::Debug for SnapshotStateMap<K, V>
3306where
3307 K: Clone + Eq + Hash + fmt::Debug + 'static,
3308 V: Clone + fmt::Debug + 'static,
3309{
3310 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3311 let contents = self.to_hash_map();
3312 f.debug_struct("SnapshotStateMap")
3313 .field("entries", &contents)
3314 .finish()
3315 }
3316}
3317
3318struct DerivedState<T: Clone + 'static> {
3319 compute: Rc<dyn Fn() -> T>, state: MutableState<T>,
3321}
3322
3323impl<T: Clone + 'static> DerivedState<T> {
3324 fn new(runtime: RuntimeHandle, compute: Rc<dyn Fn() -> T>) -> Self {
3325 let initial = compute();
3327 Self {
3328 compute,
3329 state: MutableState::with_runtime(initial, runtime),
3330 }
3331 }
3332
3333 fn set_compute(&mut self, compute: Rc<dyn Fn() -> T>) {
3334 self.compute = compute;
3336 }
3337
3338 fn recompute(&self) {
3339 let value = (self.compute)();
3340 self.state.set_value(value);
3341 }
3342}
3343
3344impl<T: fmt::Debug + Clone + 'static> fmt::Debug for State<T> {
3345 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3346 self.with_inner(|inner| {
3347 inner.with_value(|value| f.debug_struct("State").field("value", value).finish())
3348 })
3349 }
3350}
3351
3352pub struct ParamState<T> {
3353 value: Option<T>,
3354}
3355
3356impl<T> ParamState<T> {
3357 pub fn update(&mut self, new_value: &T) -> bool
3358 where
3359 T: PartialEq + Clone,
3360 {
3361 match &self.value {
3362 Some(old) if old == new_value => false,
3363 _ => {
3364 self.value = Some(new_value.clone());
3365 true
3366 }
3367 }
3368 }
3369
3370 pub fn value(&self) -> Option<T>
3371 where
3372 T: Clone,
3373 {
3374 self.value.clone()
3375 }
3376}
3377
3378pub struct ParamSlot<T> {
3381 val: RefCell<Option<T>>,
3382}
3383
3384impl<T> Default for ParamSlot<T> {
3385 fn default() -> Self {
3386 Self {
3387 val: RefCell::new(None),
3388 }
3389 }
3390}
3391
3392impl<T> ParamSlot<T> {
3393 pub fn set(&self, v: T) {
3394 *self.val.borrow_mut() = Some(v);
3395 }
3396
3397 pub fn take(&self) -> T {
3399 self.val
3400 .borrow_mut()
3401 .take()
3402 .expect("ParamSlot take() called before set")
3403 }
3404}
3405
3406#[derive(Clone)]
3410pub struct CallbackHolder {
3411 rc: Rc<RefCell<Box<dyn FnMut()>>>,
3412}
3413
3414impl CallbackHolder {
3415 pub fn new() -> Self {
3417 Self::default()
3418 }
3419
3420 pub fn update<F>(&self, f: F)
3422 where
3423 F: FnMut() + 'static,
3424 {
3425 *self.rc.borrow_mut() = Box::new(f);
3426 }
3427
3428 pub fn clone_rc(&self) -> impl FnMut() + 'static {
3430 let rc = self.rc.clone();
3431 move || {
3432 (rc.borrow_mut())();
3433 }
3434 }
3435}
3436
3437impl Default for CallbackHolder {
3438 fn default() -> Self {
3439 Self {
3440 rc: Rc::new(RefCell::new(Box::new(|| {}) as Box<dyn FnMut()>)),
3441 }
3442 }
3443}
3444
3445pub struct ReturnSlot<T> {
3446 value: Option<T>,
3447}
3448
3449impl<T: Clone> ReturnSlot<T> {
3450 pub fn store(&mut self, value: T) {
3451 self.value = Some(value);
3452 }
3453
3454 pub fn get(&self) -> Option<T> {
3455 self.value.clone()
3456 }
3457}
3458
3459impl<T> Default for ParamState<T> {
3460 fn default() -> Self {
3461 Self { value: None }
3462 }
3463}
3464
3465impl<T> Default for ReturnSlot<T> {
3466 fn default() -> Self {
3467 Self { value: None }
3468 }
3469}
3470
3471pub struct Composition<A: Applier + 'static> {
3472 slots: Rc<SlotsHost>,
3473 applier: Rc<ConcreteApplierHost<A>>,
3474 runtime: Runtime,
3475 observer: SnapshotStateObserver,
3476 root: Option<NodeId>,
3477}
3478
3479impl<A: Applier + 'static> Composition<A> {
3480 pub fn new(applier: A) -> Self {
3481 Self::with_runtime(applier, Runtime::new(Arc::new(DefaultScheduler)))
3482 }
3483
3484 pub fn with_runtime(applier: A, runtime: Runtime) -> Self {
3485 Self::with_backend(applier, runtime, SlotBackendKind::default())
3486 }
3487
3488 pub fn with_backend(applier: A, runtime: Runtime, backend_kind: SlotBackendKind) -> Self {
3489 let storage = make_backend(backend_kind);
3490 let slots = Rc::new(SlotsHost::new(storage));
3491 let applier = Rc::new(ConcreteApplierHost::new(applier));
3492 let observer_handle = runtime.handle();
3493 let observer = SnapshotStateObserver::new(move |callback| {
3494 observer_handle.enqueue_ui_task(callback);
3495 });
3496 observer.start();
3497 Self {
3498 slots,
3499 applier,
3500 runtime,
3501 observer,
3502 root: None,
3503 }
3504 }
3505
3506 fn slots_host(&self) -> Rc<SlotsHost> {
3507 Rc::clone(&self.slots)
3508 }
3509
3510 fn applier_host(&self) -> Rc<dyn ApplierHost> {
3511 self.applier.clone()
3512 }
3513
3514 pub fn render(&mut self, key: Key, mut content: impl FnMut()) -> Result<(), NodeError> {
3515 self.slots.borrow_mut().reset();
3516 let runtime_handle = self.runtime_handle();
3517 runtime_handle.drain_ui();
3518 let composer = Composer::new(
3519 Rc::clone(&self.slots),
3520 self.applier.clone(),
3521 runtime_handle.clone(),
3522 self.observer.clone(),
3523 self.root,
3524 );
3525 self.observer.begin_frame();
3526 let (root, mut commands, side_effects) = composer.install(|composer| {
3527 composer.with_group(key, |_| content());
3528 let root = composer.root();
3529 let commands = composer.take_commands();
3530 let side_effects = composer.take_side_effects();
3531 (root, commands, side_effects)
3532 });
3533
3534 {
3535 let mut applier = self.applier.borrow_dyn();
3536 for mut command in commands.drain(..) {
3537 command(&mut *applier)?;
3538 }
3539 for mut update in runtime_handle.take_updates() {
3540 update(&mut *applier)?;
3541 }
3542 }
3543
3544 runtime_handle.drain_ui();
3545 for effect in side_effects {
3546 effect();
3547 }
3548 runtime_handle.drain_ui();
3549 self.root = root;
3550 {
3551 let mut slots = self.slots.borrow_mut();
3552 let _ = slots.finalize_current_group();
3553 slots.flush();
3554 }
3555 let _ = self.process_invalid_scopes()?;
3556 if !self.runtime.has_updates()
3557 && !runtime_handle.has_invalid_scopes()
3558 && !runtime_handle.has_frame_callbacks()
3559 && !runtime_handle.has_pending_ui()
3560 {
3561 self.runtime.set_needs_frame(false);
3562 }
3563 Ok(())
3564 }
3565
3566 pub fn should_render(&self) -> bool {
3575 self.runtime.needs_frame() || self.runtime.has_updates()
3576 }
3577
3578 pub fn runtime_handle(&self) -> RuntimeHandle {
3579 self.runtime.handle()
3580 }
3581
3582 pub fn applier_mut(&mut self) -> ApplierGuard<'_, A> {
3583 ApplierGuard::new(self.applier.borrow_typed())
3584 }
3585
3586 pub fn root(&self) -> Option<NodeId> {
3587 self.root
3588 }
3589
3590 pub fn debug_dump_slot_table_groups(&self) -> Vec<(usize, Key, Option<ScopeId>, usize)> {
3591 self.slots.borrow().debug_dump_groups()
3592 }
3593
3594 pub fn debug_dump_all_slots(&self) -> Vec<(usize, String)> {
3595 self.slots.borrow().debug_dump_all_slots()
3596 }
3597
3598 pub fn process_invalid_scopes(&mut self) -> Result<bool, NodeError> {
3599 let runtime_handle = self.runtime_handle();
3600 let mut did_recompose = false;
3601 let mut loop_count = 0;
3602 loop {
3603 loop_count += 1;
3604 if loop_count > 100 {
3605 log::error!("process_invalid_scopes looped too many times! Breaking loop to prevent freeze.");
3606 break;
3607 }
3608 runtime_handle.drain_ui();
3609 let pending = runtime_handle.take_invalidated_scopes();
3610 if pending.is_empty() {
3611 break;
3612 }
3613 let mut scopes = Vec::new();
3614 for (id, weak) in pending {
3615 if let Some(inner) = weak.upgrade() {
3616 scopes.push(RecomposeScope { inner });
3617 } else {
3618 runtime_handle.mark_scope_recomposed(id);
3619 }
3620 }
3621 if scopes.is_empty() {
3622 continue;
3623 }
3624 did_recompose = true;
3625 let runtime_clone = runtime_handle.clone();
3626 let (mut commands, side_effects) = {
3627 let composer = Composer::new(
3628 self.slots_host(),
3629 self.applier_host(),
3630 runtime_clone,
3631 self.observer.clone(),
3632 self.root,
3633 );
3634 self.observer.begin_frame();
3635 composer.install(|composer| {
3636 for scope in scopes.iter() {
3637 composer.recranpose_group(scope);
3638 }
3639 let commands = composer.take_commands();
3640 let side_effects = composer.take_side_effects();
3641 (commands, side_effects)
3642 })
3643 };
3644 {
3645 let mut applier = self.applier.borrow_dyn();
3646 for mut command in commands.drain(..) {
3647 command(&mut *applier)?;
3648 }
3649 for mut update in runtime_handle.take_updates() {
3650 update(&mut *applier)?;
3651 }
3652 }
3653 for effect in side_effects {
3654 effect();
3655 }
3656 runtime_handle.drain_ui();
3657 }
3658 if !self.runtime.has_updates()
3659 && !runtime_handle.has_invalid_scopes()
3660 && !runtime_handle.has_frame_callbacks()
3661 && !runtime_handle.has_pending_ui()
3662 {
3663 self.runtime.set_needs_frame(false);
3664 }
3665 Ok(did_recompose)
3666 }
3667
3668 pub fn flush_pending_node_updates(&mut self) -> Result<(), NodeError> {
3669 let updates = self.runtime_handle().take_updates();
3670 let mut applier = self.applier.borrow_dyn();
3671 for mut update in updates {
3672 update(&mut *applier)?;
3673 }
3674 Ok(())
3675 }
3676}
3677
3678impl<A: Applier + 'static> Drop for Composition<A> {
3679 fn drop(&mut self) {
3680 self.observer.stop();
3681 }
3682}
3683pub fn location_key(file: &str, line: u32, column: u32) -> Key {
3684 let base = file.as_ptr() as u64;
3685 base
3686 .wrapping_mul(0x9E37_79B9_7F4A_7C15) ^ ((line as u64) << 32)
3688 ^ (column as u64)
3689}
3690
3691fn hash_key<K: Hash>(key: &K) -> Key {
3692 let mut hasher = hash::default::new();
3693 key.hash(&mut hasher);
3694 hasher.finish()
3695}
3696
3697#[cfg(test)]
3698#[path = "tests/lib_tests.rs"]
3699mod tests;
3700
3701#[cfg(test)]
3702#[path = "tests/recursive_decrease_increase_test.rs"]
3703mod recursive_decrease_increase_test;
3704
3705#[cfg(test)]
3706#[path = "tests/slot_backend_tests.rs"]
3707mod slot_backend_tests;
3708
3709pub mod collections;
3710pub mod hash;