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.core.recranpose_parent_hint.replace(scope.parent_hint());
2192 struct HintGuard {
2193 core: Rc<ComposerCore>,
2194 previous: Option<NodeId>,
2195 }
2196 impl Drop for HintGuard {
2197 fn drop(&mut self) {
2198 self.core.recranpose_parent_hint.set(self.previous);
2199 }
2200 }
2201 let _hint_guard = HintGuard {
2202 core: self.clone_core(),
2203 previous: previous_hint,
2204 };
2205 {
2206 let mut stack = self.scope_stack();
2207 stack.push(scope.clone());
2208 }
2209 let saved_locals = {
2210 let mut locals = self.local_stack();
2211 std::mem::take(&mut *locals)
2212 };
2213 {
2214 let mut locals = self.local_stack();
2215 *locals = scope.local_stack();
2216 }
2217 self.observe_scope(scope, || {
2218 scope.run_recompose(self);
2219 });
2220 {
2221 let mut locals = self.local_stack();
2222 *locals = saved_locals;
2223 }
2224 {
2225 let mut stack = self.scope_stack();
2226 stack.pop();
2227 }
2228 self.with_slots_mut(SlotStorage::end_recompose);
2229 scope.mark_recomposed();
2230 } else {
2231 scope.mark_recomposed();
2232 }
2233 }
2234
2235 pub fn use_state<T: Clone + 'static>(&self, init: impl FnOnce() -> T) -> MutableState<T> {
2236 let runtime = self.runtime_handle();
2237 let state = self.with_slots_mut(|slots| {
2238 slots.remember(|| MutableState::with_runtime(init(), runtime.clone()))
2239 });
2240 state.with(|state| *state)
2241 }
2242
2243 pub fn emit_node<N: Node + 'static>(&self, init: impl FnOnce() -> N) -> NodeId {
2244 let (existing_id, type_matches) = {
2246 if let Some(id) = self.with_slots_mut(|slots| slots.peek_node()) {
2247 let mut applier = self.borrow_applier();
2249 let matches = match applier.get_mut(id) {
2250 Ok(node) => node.as_any_mut().downcast_ref::<N>().is_some(),
2251 Err(_) => false,
2252 };
2253 (Some(id), matches)
2254 } else {
2255 (None, false)
2256 }
2257 };
2258
2259 if let Some(id) = existing_id {
2261 if type_matches {
2262 let reuse_allowed = true;
2266
2267 #[cfg(not(target_arch = "wasm32"))]
2268 if std::env::var("COMPOSE_DEBUG").is_ok() {
2269 eprintln!("emit_node: candidate #{id} reuse_allowed={reuse_allowed}");
2270 }
2271
2272 if reuse_allowed {
2273 self.core.last_node_reused.set(Some(true));
2274 #[cfg(not(target_arch = "wasm32"))]
2275 if std::env::var("COMPOSE_DEBUG").is_ok() {
2276 eprintln!(
2277 "emit_node: reusing node #{id} as {}",
2278 std::any::type_name::<N>()
2279 );
2280 }
2281 self.with_slots_mut(|slots| slots.advance_after_node_read());
2282
2283 self.commands_mut()
2284 .push(Box::new(move |applier: &mut dyn Applier| {
2285 let node = match applier.get_mut(id) {
2286 Ok(node) => node,
2287 Err(NodeError::Missing { .. }) => return Ok(()),
2288 Err(err) => return Err(err),
2289 };
2290 let typed = node.as_any_mut().downcast_mut::<N>().ok_or(
2291 NodeError::TypeMismatch {
2292 id,
2293 expected: std::any::type_name::<N>(),
2294 },
2295 )?;
2296 typed.update();
2297 Ok(())
2298 }));
2299 self.attach_to_parent(id);
2300 return id;
2301 }
2302 }
2303 }
2304
2305 if let Some(old_id) = existing_id {
2307 if !type_matches {
2308 #[cfg(not(target_arch = "wasm32"))]
2309 if std::env::var("COMPOSE_DEBUG").is_ok() {
2310 eprintln!(
2311 "emit_node: replacing node #{old_id} with new {}",
2312 std::any::type_name::<N>()
2313 );
2314 }
2315 self.commands_mut()
2316 .push(Box::new(move |applier: &mut dyn Applier| {
2317 if let Ok(node) = applier.get_mut(old_id) {
2318 node.unmount();
2319 }
2320 match applier.remove(old_id) {
2321 Ok(()) | Err(NodeError::Missing { .. }) => Ok(()),
2322 Err(err) => Err(err),
2323 }
2324 }));
2325 }
2326 }
2327
2328 let id = {
2331 let mut applier = self.borrow_applier();
2332 applier.create(Box::new(init()))
2333 };
2334 self.core.last_node_reused.set(Some(false));
2335 #[cfg(not(target_arch = "wasm32"))]
2336 if std::env::var("COMPOSE_DEBUG").is_ok() {
2337 eprintln!(
2338 "emit_node: creating node #{} as {}",
2339 id,
2340 std::any::type_name::<N>()
2341 );
2342 }
2343 {
2344 self.with_slots_mut(|slots| slots.record_node(id));
2345 }
2346 self.commands_mut()
2347 .push(Box::new(move |applier: &mut dyn Applier| {
2348 let node = match applier.get_mut(id) {
2349 Ok(node) => node,
2350 Err(NodeError::Missing { .. }) => return Ok(()),
2351 Err(err) => return Err(err),
2352 };
2353 node.set_node_id(id);
2354 node.mount();
2355 Ok(())
2356 }));
2357 self.attach_to_parent(id);
2358 id
2359 }
2360
2361 fn attach_to_parent(&self, id: NodeId) {
2362 let mut parent_stack = self.parent_stack();
2368 if let Some(frame) = parent_stack.last_mut() {
2369 let parent_id = frame.id;
2370 if parent_id == id {
2371 return;
2372 }
2373 frame.new_children.push(id);
2374 drop(parent_stack);
2375
2376 {
2387 let mut applier = self.borrow_applier();
2388 if let Ok(child_node) = applier.get_mut(id) {
2389 let existing_parent = child_node.parent();
2390 let should_set = match existing_parent {
2395 None => true,
2396 Some(existing) => {
2397 let root_id = self.core.root.get();
2399 parent_id != root_id.unwrap_or(0) || existing == root_id.unwrap_or(0)
2400 }
2401 };
2402 if should_set {
2403 child_node.set_parent_for_bubbling(parent_id);
2404 }
2405 }
2406 }
2407 return;
2408 }
2409 drop(parent_stack);
2410
2411 let in_subcompose = !self.subcompose_stack().is_empty();
2413 if in_subcompose {
2414 let has_parent = {
2418 let mut applier = self.borrow_applier();
2419 applier
2420 .get_mut(id)
2421 .map(|node| node.parent().is_some())
2422 .unwrap_or(false)
2423 };
2424
2425 if !has_parent {
2426 let mut subcompose_stack = self.subcompose_stack();
2427 if let Some(frame) = subcompose_stack.last_mut() {
2428 frame.nodes.push(id);
2429 }
2430 }
2431 return;
2432 }
2433
2434 if let Some(parent_hint) = self.core.recranpose_parent_hint.get() {
2436 let parent_status = {
2437 let mut applier = self.borrow_applier();
2438 applier
2439 .get_mut(id)
2440 .map(|node| node.parent())
2441 .unwrap_or(None)
2442 };
2443 match parent_status {
2444 Some(existing) if existing == parent_hint => {}
2445 None => {
2446 self.commands_mut()
2447 .push(Box::new(move |applier: &mut dyn Applier| {
2448 if let Ok(parent_node) = applier.get_mut(parent_hint) {
2449 parent_node.insert_child(id);
2450 }
2451 if let Ok(child_node) = applier.get_mut(id) {
2452 child_node.on_attached_to_parent(parent_hint);
2453 }
2454 bubble_layout_dirty(applier, parent_hint);
2455 bubble_measure_dirty(applier, parent_hint);
2456 Ok(())
2457 }));
2458 }
2459 Some(_) => {}
2460 }
2461 return;
2462 }
2463
2464 let has_parent = {
2469 let mut applier = self.borrow_applier();
2470 applier
2471 .get_mut(id)
2472 .map(|node| node.parent().is_some())
2473 .unwrap_or(false)
2474 };
2475 if has_parent {
2476 return;
2478 }
2479
2480 self.set_root(Some(id));
2482 }
2483
2484 pub fn with_node_mut<N: Node + 'static, R>(
2485 &self,
2486 id: NodeId,
2487 f: impl FnOnce(&mut N) -> R,
2488 ) -> Result<R, NodeError> {
2489 let mut applier = self.borrow_applier();
2490 let node = applier.get_mut(id)?;
2491 let typed = node
2492 .as_any_mut()
2493 .downcast_mut::<N>()
2494 .ok_or(NodeError::TypeMismatch {
2495 id,
2496 expected: std::any::type_name::<N>(),
2497 })?;
2498 Ok(f(typed))
2499 }
2500
2501 pub fn push_parent(&self, id: NodeId) {
2502 let remembered = self.remember(ParentChildren::default);
2503 let reused = self.core.last_node_reused.take().unwrap_or(true);
2504 let in_subcompose = !self.core.subcompose_stack.borrow().is_empty();
2505
2506 let previous = if reused || in_subcompose {
2509 remembered.with(|entry| entry.children.clone())
2510 } else {
2511 Vec::new()
2512 };
2513
2514 self.parent_stack().push(ParentFrame {
2515 id,
2516 remembered,
2517 previous,
2518 new_children: Vec::new(),
2519 });
2520 }
2521
2522 pub fn pop_parent(&self) {
2523 let frame_opt = {
2524 let mut stack = self.parent_stack();
2525 stack.pop()
2526 };
2527 if let Some(frame) = frame_opt {
2528 let ParentFrame {
2529 id,
2530 remembered,
2531 previous,
2532 new_children,
2533 } = frame;
2534
2535 #[cfg(not(target_arch = "wasm32"))]
2536 if std::env::var("COMPOSE_DEBUG").is_ok() {
2537 eprintln!("pop_parent: node #{}", id);
2538 eprintln!(" previous children: {:?}", previous);
2539 eprintln!(" new children: {:?}", new_children);
2540 }
2541 let children_changed = previous != new_children;
2542
2543 if children_changed {
2544 let mut current = previous.clone();
2545 let target = new_children.clone();
2546 let desired: HashSet<NodeId> = target.iter().copied().collect();
2547
2548 for index in (0..current.len()).rev() {
2549 let child = current[index];
2550 if !desired.contains(&child) {
2551 current.remove(index);
2552 self.commands_mut()
2553 .push(Box::new(move |applier: &mut dyn Applier| {
2554 if let Ok(parent_node) = applier.get_mut(id) {
2556 parent_node.remove_child(child);
2557 }
2558 bubble_layout_dirty(applier, id);
2560 bubble_measure_dirty(applier, id);
2561 let should_remove = if let Ok(node) = applier.get_mut(child) {
2565 match node.parent() {
2566 Some(parent_id) if parent_id == id => {
2567 node.on_removed_from_parent();
2568 node.unmount();
2569 true
2570 }
2571 None => {
2572 node.unmount();
2574 true
2575 }
2576 Some(_) => false,
2577 }
2578 } else {
2579 true
2580 };
2581
2582 if should_remove {
2583 let _ = applier.remove(child);
2584 }
2585 Ok(())
2586 }));
2587 }
2588 }
2589
2590 for (target_index, &child) in target.iter().enumerate() {
2591 if let Some(current_index) = current.iter().position(|&c| c == child) {
2592 if current_index != target_index {
2593 let from_index = current_index;
2594 current.remove(from_index);
2595 let to_index = target_index.min(current.len());
2596 current.insert(to_index, child);
2597 self.commands_mut()
2598 .push(Box::new(move |applier: &mut dyn Applier| {
2599 if let Ok(parent_node) = applier.get_mut(id) {
2600 parent_node.move_child(from_index, to_index);
2601 }
2602 Ok(())
2603 }));
2604 self.commands_mut()
2605 .push(Box::new(move |applier: &mut dyn Applier| {
2606 bubble_layout_dirty(applier, id);
2609 bubble_measure_dirty(applier, id);
2610 Ok(())
2611 }));
2612 }
2613 } else {
2614 let insert_index = target_index.min(current.len());
2615 let appended_index = current.len();
2616 current.insert(insert_index, child);
2617 self.commands_mut()
2618 .push(Box::new(move |applier: &mut dyn Applier| {
2619 let old_parent =
2622 applier.get_mut(child).ok().and_then(|node| node.parent());
2623 if let Some(old_parent_id) = old_parent {
2624 if old_parent_id != id {
2625 if let Ok(old_parent_node) = applier.get_mut(old_parent_id)
2626 {
2627 old_parent_node.remove_child(child);
2628 }
2629 if let Ok(child_node) = applier.get_mut(child) {
2630 child_node.on_removed_from_parent();
2631 }
2632 bubble_layout_dirty(applier, old_parent_id);
2633 bubble_measure_dirty(applier, old_parent_id);
2634 }
2635 }
2636 if let Ok(parent_node) = applier.get_mut(id) {
2638 parent_node.insert_child(child);
2639 }
2640 if let Ok(child_node) = applier.get_mut(child) {
2642 child_node.on_attached_to_parent(id);
2643 }
2644 bubble_layout_dirty(applier, id);
2646 bubble_measure_dirty(applier, id);
2647 Ok(())
2648 }));
2649 if insert_index != appended_index {
2650 self.commands_mut()
2651 .push(Box::new(move |applier: &mut dyn Applier| {
2652 if let Ok(parent_node) = applier.get_mut(id) {
2653 parent_node.move_child(appended_index, insert_index);
2654 }
2655 Ok(())
2656 }));
2657 }
2658 }
2659 }
2660 }
2661
2662 let expected_children = new_children.clone();
2663 let needs_dirty_check = !children_changed;
2664 self.commands_mut()
2665 .push(Box::new(move |applier: &mut dyn Applier| {
2666 let mut repaired = false;
2667 for &child in &expected_children {
2668 let needs_attach = if let Ok(node) = applier.get_mut(child) {
2669 node.parent() != Some(id)
2670 } else {
2671 false
2672 };
2673 if needs_attach {
2674 let old_parent =
2675 applier.get_mut(child).ok().and_then(|node| node.parent());
2676 if let Some(old_parent_id) = old_parent {
2677 if old_parent_id != id {
2678 if let Ok(old_parent_node) = applier.get_mut(old_parent_id) {
2679 old_parent_node.remove_child(child);
2680 }
2681 if let Ok(child_node) = applier.get_mut(child) {
2682 child_node.on_removed_from_parent();
2683 }
2684 bubble_layout_dirty(applier, old_parent_id);
2685 bubble_measure_dirty(applier, old_parent_id);
2686 }
2687 }
2688 if let Ok(parent_node) = applier.get_mut(id) {
2689 parent_node.insert_child(child);
2690 }
2691 if let Ok(child_node) = applier.get_mut(child) {
2692 child_node.on_attached_to_parent(id);
2693 }
2694 repaired = true;
2695 }
2696 }
2697 let is_dirty = if needs_dirty_check {
2698 if let Ok(node) = applier.get_mut(id) {
2699 node.needs_layout()
2700 } else {
2701 false
2702 }
2703 } else {
2704 false
2705 };
2706 if repaired {
2707 bubble_layout_dirty(applier, id);
2708 bubble_measure_dirty(applier, id);
2709 } else if is_dirty {
2710 bubble_layout_dirty(applier, id);
2711 }
2712 Ok(())
2713 }));
2714
2715 remembered.update(|entry| entry.children = new_children);
2716 }
2717 }
2718
2719 pub fn take_commands(&self) -> Vec<Command> {
2720 std::mem::take(&mut *self.commands_mut())
2721 }
2722
2723 pub fn apply_pending_commands(&self) -> Result<(), NodeError> {
2728 let mut commands = self.take_commands();
2729 let runtime_handle = self.runtime_handle();
2730 {
2731 let mut applier = self.borrow_applier();
2732 for mut command in commands.drain(..) {
2733 command(&mut *applier)?;
2734 }
2735 for mut update in runtime_handle.take_updates() {
2736 update(&mut *applier)?;
2737 }
2738 }
2739 runtime_handle.drain_ui();
2740 Ok(())
2741 }
2742
2743 pub fn register_side_effect(&self, effect: impl FnOnce() + 'static) {
2744 self.side_effects_mut().push(Box::new(effect));
2745 }
2746
2747 pub fn take_side_effects(&self) -> Vec<Box<dyn FnOnce()>> {
2748 std::mem::take(&mut *self.side_effects_mut())
2749 }
2750
2751 pub(crate) fn root(&self) -> Option<NodeId> {
2752 self.core.root.get()
2753 }
2754
2755 pub(crate) fn set_root(&self, node: Option<NodeId>) {
2756 self.core.root.set(node);
2757 }
2758}
2759
2760#[derive(Default, Clone)]
2761struct ParentChildren {
2762 children: Vec<NodeId>,
2763}
2764
2765struct ParentFrame {
2766 id: NodeId,
2767 remembered: Owned<ParentChildren>,
2768 previous: Vec<NodeId>,
2769 new_children: Vec<NodeId>,
2770}
2771
2772#[derive(Default)]
2773struct SubcomposeFrame {
2774 nodes: Vec<NodeId>,
2775 scopes: Vec<RecomposeScope>,
2776}
2777
2778#[derive(Default, Clone)]
2779struct LocalContext {
2780 values: HashMap<LocalKey, Rc<dyn Any>>,
2781}
2782
2783pub(crate) struct MutableStateInner<T: Clone + 'static> {
2784 state: Arc<SnapshotMutableState<T>>,
2785 watchers: RefCell<Vec<Weak<RecomposeScopeInner>>>, runtime: RuntimeHandle,
2787}
2788
2789impl<T: Clone + 'static> MutableStateInner<T> {
2790 fn new(value: T, runtime: RuntimeHandle) -> Self {
2791 Self {
2792 state: SnapshotMutableState::new_in_arc(value, Arc::new(NeverEqual)),
2793 watchers: RefCell::new(Vec::new()),
2794 runtime,
2795 }
2796 }
2797
2798 fn install_snapshot_observer(&self, state_id: StateId) {
2799 let runtime_handle = self.runtime.clone();
2800 self.state.add_apply_observer(Box::new(move || {
2801 let runtime = runtime_handle.clone();
2802 runtime_handle.enqueue_ui_task(Box::new(move || {
2803 runtime.with_state_arena(|arena| {
2804 if let Some(inner) = arena.get_typed_opt::<T>(state_id) {
2805 inner.invalidate_watchers();
2806 }
2807 });
2808 }));
2809 }));
2810 }
2811
2812 fn with_value<R>(&self, f: impl FnOnce(&T) -> R) -> R {
2813 let value = self.state.get();
2814 f(&value)
2815 }
2816
2817 fn invalidate_watchers(&self) {
2818 let watchers: Vec<RecomposeScope> = {
2819 let mut watchers = self.watchers.borrow_mut();
2820 watchers.retain(|w| w.strong_count() > 0);
2821 watchers
2822 .iter()
2823 .filter_map(|w| w.upgrade())
2824 .map(|inner| RecomposeScope { inner })
2825 .collect()
2826 };
2827
2828 for watcher in watchers {
2829 watcher.invalidate();
2830 }
2831 }
2832}
2833
2834#[derive(Clone)]
2835pub struct State<T: Clone + 'static> {
2836 id: StateId,
2837 runtime_id: RuntimeId,
2838 _marker: PhantomData<fn() -> T>,
2839}
2840
2841impl<T: Clone + 'static> Copy for State<T> {}
2842
2843#[derive(Clone)]
2844pub struct MutableState<T: Clone + 'static> {
2845 id: StateId,
2846 runtime_id: RuntimeId,
2847 _marker: PhantomData<fn() -> T>,
2848}
2849
2850impl<T: Clone + 'static> Copy for MutableState<T> {}
2851
2852impl<T: Clone + 'static> PartialEq for State<T> {
2853 fn eq(&self, other: &Self) -> bool {
2854 self.id == other.id && self.runtime_id == other.runtime_id
2855 }
2856}
2857
2858impl<T: Clone + 'static> Eq for State<T> {}
2859
2860impl<T: Clone + 'static> PartialEq for MutableState<T> {
2861 fn eq(&self, other: &Self) -> bool {
2862 self.id == other.id && self.runtime_id == other.runtime_id
2863 }
2864}
2865
2866impl<T: Clone + 'static> Eq for MutableState<T> {}
2867
2868impl<T: Clone + 'static> State<T> {
2869 fn runtime_handle(&self) -> RuntimeHandle {
2870 runtime_handle_for(self.runtime_id).expect("runtime handle missing")
2871 }
2872
2873 fn with_inner<R>(&self, f: impl FnOnce(&MutableStateInner<T>) -> R) -> R {
2874 self.runtime_handle().with_state_arena(|arena| {
2875 let inner = arena.get_typed::<T>(self.id);
2876 f(&inner)
2877 })
2878 }
2879
2880 fn subscribe_current_scope(&self) {
2881 if let Some(Some(scope)) =
2882 with_current_composer_opt(|composer| composer.current_recranpose_scope())
2883 {
2884 self.with_inner(|inner| {
2885 let mut watchers = inner.watchers.borrow_mut();
2886 watchers.retain(|w| w.strong_count() > 0);
2887 let id = scope.id();
2888 let already_registered = watchers
2889 .iter()
2890 .any(|w| w.upgrade().map(|inner| inner.id == id).unwrap_or(false));
2891 if !already_registered {
2892 watchers.push(scope.downgrade());
2893 }
2894 });
2895 }
2896 }
2897
2898 pub fn with<R>(&self, f: impl FnOnce(&T) -> R) -> R {
2899 self.subscribe_current_scope();
2900 self.with_inner(|inner| inner.with_value(f))
2901 }
2902
2903 pub fn value(&self) -> T {
2904 self.subscribe_current_scope();
2905 self.with(|value| value.clone())
2906 }
2907
2908 pub fn get(&self) -> T {
2909 self.value()
2910 }
2911}
2912
2913impl<T: Clone + 'static> MutableState<T> {
2914 pub fn with_runtime(value: T, runtime: RuntimeHandle) -> Self {
2915 let id = runtime.alloc_state(value);
2916 Self {
2917 id,
2918 runtime_id: runtime.id(),
2919 _marker: PhantomData,
2920 }
2921 }
2922
2923 fn runtime_handle(&self) -> RuntimeHandle {
2924 runtime_handle_for(self.runtime_id).expect("runtime handle missing")
2925 }
2926
2927 fn with_inner<R>(&self, f: impl FnOnce(&MutableStateInner<T>) -> R) -> R {
2928 self.runtime_handle().with_state_arena(|arena| {
2929 let inner = arena.get_typed::<T>(self.id);
2930 f(&inner)
2931 })
2932 }
2933
2934 pub fn as_state(&self) -> State<T> {
2935 State {
2936 id: self.id,
2937 runtime_id: self.runtime_id,
2938 _marker: PhantomData,
2939 }
2940 }
2941
2942 pub fn with<R>(&self, f: impl FnOnce(&T) -> R) -> R {
2943 self.as_state().with(f)
2944 }
2945
2946 pub fn update<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
2947 let runtime = self.runtime_handle();
2948 runtime.assert_ui_thread();
2949 runtime.with_state_arena(|arena| {
2950 let inner = arena.get_typed::<T>(self.id);
2951 let mut value = inner.state.get();
2952 let tracker = UpdateScope::new(inner.state.id());
2953 let result = f(&mut value);
2954 let wrote_elsewhere = tracker.finish();
2955 if !wrote_elsewhere {
2956 inner.state.set(value);
2957 }
2958 inner.invalidate_watchers();
2959 result
2960 })
2961 }
2962
2963 pub fn replace(&self, value: T) {
2964 let runtime = self.runtime_handle();
2965 runtime.assert_ui_thread();
2966 runtime.with_state_arena(|arena| {
2967 let inner = arena.get_typed::<T>(self.id);
2968 inner.state.set(value);
2969 inner.invalidate_watchers();
2970 });
2971 }
2972
2973 pub fn set_value(&self, value: T) {
2974 self.replace(value);
2975 }
2976
2977 pub fn set(&self, value: T) {
2978 self.replace(value);
2979 }
2980
2981 pub fn value(&self) -> T {
2982 self.as_state().value()
2983 }
2984
2985 pub fn get(&self) -> T {
2986 self.value()
2987 }
2988
2989 pub fn get_non_reactive(&self) -> T {
3002 self.with_inner(|inner| inner.state.get())
3004 }
3005
3006 #[cfg(test)]
3007 pub(crate) fn watcher_count(&self) -> usize {
3008 self.with_inner(|inner| inner.watchers.borrow().len())
3009 }
3010}
3011
3012impl<T: fmt::Debug + Clone + 'static> fmt::Debug for MutableState<T> {
3013 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3014 self.with_inner(|inner| {
3015 inner.with_value(|value| {
3016 f.debug_struct("MutableState")
3017 .field("value", value)
3018 .finish()
3019 })
3020 })
3021 }
3022}
3023
3024#[derive(Clone)]
3025pub struct SnapshotStateList<T: Clone + 'static> {
3026 state: MutableState<Vec<T>>,
3027}
3028
3029impl<T: Clone + 'static> SnapshotStateList<T> {
3030 pub fn with_runtime<I>(values: I, runtime: RuntimeHandle) -> Self
3031 where
3032 I: IntoIterator<Item = T>,
3033 {
3034 let initial: Vec<T> = values.into_iter().collect();
3035 Self {
3036 state: MutableState::with_runtime(initial, runtime),
3037 }
3038 }
3039
3040 pub fn as_state(&self) -> State<Vec<T>> {
3041 self.state.as_state()
3042 }
3043
3044 pub fn as_mutable_state(&self) -> MutableState<Vec<T>> {
3045 self.state
3046 }
3047
3048 pub fn len(&self) -> usize {
3049 self.state.with(|values| values.len())
3050 }
3051
3052 pub fn is_empty(&self) -> bool {
3053 self.len() == 0
3054 }
3055
3056 pub fn to_vec(&self) -> Vec<T> {
3057 self.state.with(|values| values.clone())
3058 }
3059
3060 pub fn iter(&self) -> Vec<T> {
3061 self.to_vec()
3062 }
3063
3064 pub fn get(&self, index: usize) -> T {
3065 self.state.with(|values| values[index].clone())
3066 }
3067
3068 pub fn get_opt(&self, index: usize) -> Option<T> {
3069 self.state.with(|values| values.get(index).cloned())
3070 }
3071
3072 pub fn first(&self) -> Option<T> {
3073 self.get_opt(0)
3074 }
3075
3076 pub fn last(&self) -> Option<T> {
3077 self.state.with(|values| values.last().cloned())
3078 }
3079
3080 pub fn push(&self, value: T) {
3081 self.state.update(|values| values.push(value));
3082 }
3083
3084 pub fn extend<I>(&self, iter: I)
3085 where
3086 I: IntoIterator<Item = T>,
3087 {
3088 self.state.update(|values| values.extend(iter));
3089 }
3090
3091 pub fn insert(&self, index: usize, value: T) {
3092 self.state.update(|values| values.insert(index, value));
3093 }
3094
3095 pub fn set(&self, index: usize, value: T) -> T {
3096 self.state
3097 .update(|values| std::mem::replace(&mut values[index], value))
3098 }
3099
3100 pub fn remove(&self, index: usize) -> T {
3101 self.state.update(|values| values.remove(index))
3102 }
3103
3104 pub fn pop(&self) -> Option<T> {
3105 self.state.update(|values| values.pop())
3106 }
3107
3108 pub fn clear(&self) {
3109 self.state.replace(Vec::new());
3110 }
3111
3112 pub fn retain<F>(&self, mut predicate: F)
3113 where
3114 F: FnMut(&T) -> bool,
3115 {
3116 self.state
3117 .update(|values| values.retain(|value| predicate(value)));
3118 }
3119
3120 pub fn replace_with<I>(&self, iter: I)
3121 where
3122 I: IntoIterator<Item = T>,
3123 {
3124 self.state.replace(iter.into_iter().collect());
3125 }
3126}
3127
3128impl<T: fmt::Debug + Clone + 'static> fmt::Debug for SnapshotStateList<T> {
3129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3130 let contents = self.to_vec();
3131 f.debug_struct("SnapshotStateList")
3132 .field("values", &contents)
3133 .finish()
3134 }
3135}
3136
3137#[derive(Clone)]
3138pub struct SnapshotStateMap<K, V>
3139where
3140 K: Clone + Eq + Hash + 'static,
3141 V: Clone + 'static,
3142{
3143 state: MutableState<HashMap<K, V>>,
3144}
3145
3146impl<K, V> SnapshotStateMap<K, V>
3147where
3148 K: Clone + Eq + Hash + 'static,
3149 V: Clone + 'static,
3150{
3151 pub fn with_runtime<I>(pairs: I, runtime: RuntimeHandle) -> Self
3152 where
3153 I: IntoIterator<Item = (K, V)>,
3154 {
3155 let map: HashMap<K, V> = pairs.into_iter().collect();
3156 Self {
3157 state: MutableState::with_runtime(map, runtime),
3158 }
3159 }
3160
3161 pub fn as_state(&self) -> State<HashMap<K, V>> {
3162 self.state.as_state()
3163 }
3164
3165 pub fn as_mutable_state(&self) -> MutableState<HashMap<K, V>> {
3166 self.state
3167 }
3168
3169 pub fn len(&self) -> usize {
3170 self.state.with(|map| map.len())
3171 }
3172
3173 pub fn is_empty(&self) -> bool {
3174 self.state.with(|map| map.is_empty())
3175 }
3176
3177 pub fn contains_key(&self, key: &K) -> bool {
3178 self.state.with(|map| map.contains_key(key))
3179 }
3180
3181 pub fn get(&self, key: &K) -> Option<V> {
3182 self.state.with(|map| map.get(key).cloned())
3183 }
3184
3185 pub fn to_hash_map(&self) -> HashMap<K, V> {
3186 self.state.with(|map| map.clone())
3187 }
3188
3189 pub fn insert(&self, key: K, value: V) -> Option<V> {
3190 self.state.update(|map| map.insert(key, value))
3191 }
3192
3193 pub fn extend<I>(&self, iter: I)
3194 where
3195 I: IntoIterator<Item = (K, V)>,
3196 {
3197 self.state.update(|map| map.extend(iter));
3198 }
3200
3201 pub fn remove(&self, key: &K) -> Option<V> {
3202 self.state.update(|map| map.remove(key))
3203 }
3204
3205 pub fn clear(&self) {
3206 self.state.replace(HashMap::default());
3207 }
3208
3209 pub fn retain<F>(&self, mut predicate: F)
3210 where
3211 F: FnMut(&K, &mut V) -> bool,
3212 {
3213 self.state.update(|map| map.retain(|k, v| predicate(k, v)));
3214 }
3215}
3216
3217impl<K, V> fmt::Debug for SnapshotStateMap<K, V>
3218where
3219 K: Clone + Eq + Hash + fmt::Debug + 'static,
3220 V: Clone + fmt::Debug + 'static,
3221{
3222 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3223 let contents = self.to_hash_map();
3224 f.debug_struct("SnapshotStateMap")
3225 .field("entries", &contents)
3226 .finish()
3227 }
3228}
3229
3230struct DerivedState<T: Clone + 'static> {
3231 compute: Rc<dyn Fn() -> T>, state: MutableState<T>,
3233}
3234
3235impl<T: Clone + 'static> DerivedState<T> {
3236 fn new(runtime: RuntimeHandle, compute: Rc<dyn Fn() -> T>) -> Self {
3237 let initial = compute();
3239 Self {
3240 compute,
3241 state: MutableState::with_runtime(initial, runtime),
3242 }
3243 }
3244
3245 fn set_compute(&mut self, compute: Rc<dyn Fn() -> T>) {
3246 self.compute = compute;
3248 }
3249
3250 fn recompute(&self) {
3251 let value = (self.compute)();
3252 self.state.set_value(value);
3253 }
3254}
3255
3256impl<T: fmt::Debug + Clone + 'static> fmt::Debug for State<T> {
3257 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3258 self.with_inner(|inner| {
3259 inner.with_value(|value| f.debug_struct("State").field("value", value).finish())
3260 })
3261 }
3262}
3263
3264pub struct ParamState<T> {
3265 value: Option<T>,
3266}
3267
3268impl<T> ParamState<T> {
3269 pub fn update(&mut self, new_value: &T) -> bool
3270 where
3271 T: PartialEq + Clone,
3272 {
3273 match &self.value {
3274 Some(old) if old == new_value => false,
3275 _ => {
3276 self.value = Some(new_value.clone());
3277 true
3278 }
3279 }
3280 }
3281
3282 pub fn value(&self) -> Option<T>
3283 where
3284 T: Clone,
3285 {
3286 self.value.clone()
3287 }
3288}
3289
3290pub struct ParamSlot<T> {
3293 val: RefCell<Option<T>>,
3294}
3295
3296impl<T> Default for ParamSlot<T> {
3297 fn default() -> Self {
3298 Self {
3299 val: RefCell::new(None),
3300 }
3301 }
3302}
3303
3304impl<T> ParamSlot<T> {
3305 pub fn set(&self, v: T) {
3306 *self.val.borrow_mut() = Some(v);
3307 }
3308
3309 pub fn take(&self) -> T {
3311 self.val
3312 .borrow_mut()
3313 .take()
3314 .expect("ParamSlot take() called before set")
3315 }
3316}
3317
3318#[derive(Clone)]
3322pub struct CallbackHolder {
3323 rc: Rc<RefCell<Box<dyn FnMut()>>>,
3324}
3325
3326impl CallbackHolder {
3327 pub fn new() -> Self {
3329 Self::default()
3330 }
3331
3332 pub fn update<F>(&self, f: F)
3334 where
3335 F: FnMut() + 'static,
3336 {
3337 *self.rc.borrow_mut() = Box::new(f);
3338 }
3339
3340 pub fn clone_rc(&self) -> impl FnMut() + 'static {
3342 let rc = self.rc.clone();
3343 move || {
3344 (rc.borrow_mut())();
3345 }
3346 }
3347}
3348
3349impl Default for CallbackHolder {
3350 fn default() -> Self {
3351 Self {
3352 rc: Rc::new(RefCell::new(Box::new(|| {}) as Box<dyn FnMut()>)),
3353 }
3354 }
3355}
3356
3357pub struct ReturnSlot<T> {
3358 value: Option<T>,
3359}
3360
3361impl<T: Clone> ReturnSlot<T> {
3362 pub fn store(&mut self, value: T) {
3363 self.value = Some(value);
3364 }
3365
3366 pub fn get(&self) -> Option<T> {
3367 self.value.clone()
3368 }
3369}
3370
3371impl<T> Default for ParamState<T> {
3372 fn default() -> Self {
3373 Self { value: None }
3374 }
3375}
3376
3377impl<T> Default for ReturnSlot<T> {
3378 fn default() -> Self {
3379 Self { value: None }
3380 }
3381}
3382
3383pub struct Composition<A: Applier + 'static> {
3384 slots: Rc<SlotsHost>,
3385 applier: Rc<ConcreteApplierHost<A>>,
3386 runtime: Runtime,
3387 observer: SnapshotStateObserver,
3388 root: Option<NodeId>,
3389}
3390
3391impl<A: Applier + 'static> Composition<A> {
3392 pub fn new(applier: A) -> Self {
3393 Self::with_runtime(applier, Runtime::new(Arc::new(DefaultScheduler)))
3394 }
3395
3396 pub fn with_runtime(applier: A, runtime: Runtime) -> Self {
3397 Self::with_backend(applier, runtime, SlotBackendKind::default())
3398 }
3399
3400 pub fn with_backend(applier: A, runtime: Runtime, backend_kind: SlotBackendKind) -> Self {
3401 let storage = make_backend(backend_kind);
3402 let slots = Rc::new(SlotsHost::new(storage));
3403 let applier = Rc::new(ConcreteApplierHost::new(applier));
3404 let observer_handle = runtime.handle();
3405 let observer = SnapshotStateObserver::new(move |callback| {
3406 observer_handle.enqueue_ui_task(callback);
3407 });
3408 observer.start();
3409 Self {
3410 slots,
3411 applier,
3412 runtime,
3413 observer,
3414 root: None,
3415 }
3416 }
3417
3418 fn slots_host(&self) -> Rc<SlotsHost> {
3419 Rc::clone(&self.slots)
3420 }
3421
3422 fn applier_host(&self) -> Rc<dyn ApplierHost> {
3423 self.applier.clone()
3424 }
3425
3426 pub fn render(&mut self, key: Key, mut content: impl FnMut()) -> Result<(), NodeError> {
3427 self.slots.borrow_mut().reset();
3428 let runtime_handle = self.runtime_handle();
3429 runtime_handle.drain_ui();
3430 let composer = Composer::new(
3431 Rc::clone(&self.slots),
3432 self.applier.clone(),
3433 runtime_handle.clone(),
3434 self.observer.clone(),
3435 self.root,
3436 );
3437 self.observer.begin_frame();
3438 let (root, mut commands, side_effects) = composer.install(|composer| {
3439 composer.with_group(key, |_| content());
3440 let root = composer.root();
3441 let commands = composer.take_commands();
3442 let side_effects = composer.take_side_effects();
3443 (root, commands, side_effects)
3444 });
3445
3446 {
3447 let mut applier = self.applier.borrow_dyn();
3448 for mut command in commands.drain(..) {
3449 command(&mut *applier)?;
3450 }
3451 for mut update in runtime_handle.take_updates() {
3452 update(&mut *applier)?;
3453 }
3454 }
3455
3456 runtime_handle.drain_ui();
3457 for effect in side_effects {
3458 effect();
3459 }
3460 runtime_handle.drain_ui();
3461 self.root = root;
3462 {
3463 let mut slots = self.slots.borrow_mut();
3464 let _ = slots.finalize_current_group();
3465 slots.flush();
3466 }
3467 let _ = self.process_invalid_scopes()?;
3468 if !self.runtime.has_updates()
3469 && !runtime_handle.has_invalid_scopes()
3470 && !runtime_handle.has_frame_callbacks()
3471 && !runtime_handle.has_pending_ui()
3472 {
3473 self.runtime.set_needs_frame(false);
3474 }
3475 Ok(())
3476 }
3477
3478 pub fn should_render(&self) -> bool {
3487 self.runtime.needs_frame() || self.runtime.has_updates()
3488 }
3489
3490 pub fn runtime_handle(&self) -> RuntimeHandle {
3491 self.runtime.handle()
3492 }
3493
3494 pub fn applier_mut(&mut self) -> ApplierGuard<'_, A> {
3495 ApplierGuard::new(self.applier.borrow_typed())
3496 }
3497
3498 pub fn root(&self) -> Option<NodeId> {
3499 self.root
3500 }
3501
3502 pub fn debug_dump_slot_table_groups(&self) -> Vec<(usize, Key, Option<ScopeId>, usize)> {
3503 self.slots.borrow().debug_dump_groups()
3504 }
3505
3506 pub fn debug_dump_all_slots(&self) -> Vec<(usize, String)> {
3507 self.slots.borrow().debug_dump_all_slots()
3508 }
3509
3510 pub fn process_invalid_scopes(&mut self) -> Result<bool, NodeError> {
3511 let runtime_handle = self.runtime_handle();
3512 let mut did_recompose = false;
3513 let mut loop_count = 0;
3514 loop {
3515 loop_count += 1;
3516 if loop_count > 100 {
3517 log::error!("process_invalid_scopes looped too many times! Breaking loop to prevent freeze.");
3518 break;
3519 }
3520 runtime_handle.drain_ui();
3521 let pending = runtime_handle.take_invalidated_scopes();
3522 if pending.is_empty() {
3523 break;
3524 }
3525 let mut scopes = Vec::new();
3526 for (id, weak) in pending {
3527 if let Some(inner) = weak.upgrade() {
3528 scopes.push(RecomposeScope { inner });
3529 } else {
3530 runtime_handle.mark_scope_recomposed(id);
3531 }
3532 }
3533 if scopes.is_empty() {
3534 continue;
3535 }
3536 did_recompose = true;
3537 let runtime_clone = runtime_handle.clone();
3538 let (mut commands, side_effects) = {
3539 let composer = Composer::new(
3540 self.slots_host(),
3541 self.applier_host(),
3542 runtime_clone,
3543 self.observer.clone(),
3544 self.root,
3545 );
3546 self.observer.begin_frame();
3547 composer.install(|composer| {
3548 for scope in scopes.iter() {
3549 composer.recranpose_group(scope);
3550 }
3551 let commands = composer.take_commands();
3552 let side_effects = composer.take_side_effects();
3553 (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 for effect in side_effects {
3566 effect();
3567 }
3568 runtime_handle.drain_ui();
3569 }
3570 if !self.runtime.has_updates()
3571 && !runtime_handle.has_invalid_scopes()
3572 && !runtime_handle.has_frame_callbacks()
3573 && !runtime_handle.has_pending_ui()
3574 {
3575 self.runtime.set_needs_frame(false);
3576 }
3577 Ok(did_recompose)
3578 }
3579
3580 pub fn flush_pending_node_updates(&mut self) -> Result<(), NodeError> {
3581 let updates = self.runtime_handle().take_updates();
3582 let mut applier = self.applier.borrow_dyn();
3583 for mut update in updates {
3584 update(&mut *applier)?;
3585 }
3586 Ok(())
3587 }
3588}
3589
3590impl<A: Applier + 'static> Drop for Composition<A> {
3591 fn drop(&mut self) {
3592 self.observer.stop();
3593 }
3594}
3595pub fn location_key(file: &str, line: u32, column: u32) -> Key {
3596 let base = file.as_ptr() as u64;
3597 base
3598 .wrapping_mul(0x9E37_79B9_7F4A_7C15) ^ ((line as u64) << 32)
3600 ^ (column as u64)
3601}
3602
3603fn hash_key<K: Hash>(key: &K) -> Key {
3604 let mut hasher = hash::default::new();
3605 key.hash(&mut hasher);
3606 hasher.finish()
3607}
3608
3609#[cfg(test)]
3610#[path = "tests/lib_tests.rs"]
3611mod tests;
3612
3613#[cfg(test)]
3614#[path = "tests/recursive_decrease_increase_test.rs"]
3615mod recursive_decrease_increase_test;
3616
3617#[cfg(test)]
3618#[path = "tests/slot_backend_tests.rs"]
3619mod slot_backend_tests;
3620
3621pub mod collections;
3622pub mod hash;