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