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