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