1#![doc = r"Core runtime pieces for the Cranpose experiment."]
2
3pub extern crate self as cranpose_core;
4
5pub mod composer_context;
6mod frame_clock;
7mod launched_effect;
8pub mod owned;
9pub mod platform;
10pub mod runtime;
11pub mod snapshot_double_index_heap;
12pub mod snapshot_id_set;
13pub mod snapshot_pinning;
14pub mod snapshot_state_observer;
15pub mod snapshot_v2;
16mod snapshot_weak_set;
17mod state;
18pub mod subcompose;
19
20#[cfg(feature = "internal")]
21#[doc(hidden)]
22pub mod internal {
23 pub use crate::frame_clock::{FrameCallbackRegistration, FrameClock};
24}
25pub use launched_effect::{
26 __launched_effect_async_impl, __launched_effect_impl, CancelToken, LaunchedEffectScope,
27};
28pub use owned::Owned;
29pub use platform::{Clock, RuntimeScheduler};
30pub use runtime::{
31 current_runtime_handle, schedule_frame, schedule_node_update, DefaultScheduler, Runtime,
32 RuntimeHandle, StateId, TaskHandle,
33};
34pub use snapshot_state_observer::SnapshotStateObserver;
35
36pub fn run_in_mutable_snapshot<T>(block: impl FnOnce() -> T) -> Result<T, &'static str> {
61 let snapshot = snapshot_v2::take_mutable_snapshot(None, None);
62
63 IN_APPLIED_SNAPSHOT.with(|c| c.set(true));
65 let value = snapshot.enter(block);
66 IN_APPLIED_SNAPSHOT.with(|c| c.set(false));
67
68 match snapshot.apply() {
69 snapshot_v2::SnapshotApplyResult::Success => Ok(value),
70 snapshot_v2::SnapshotApplyResult::Failure => Err("Snapshot apply failed"),
71 }
72}
73
74pub fn dispatch_ui_event<T>(block: impl FnOnce() -> T) -> Option<T> {
89 run_in_mutable_snapshot(block).ok()
90}
91
92thread_local! {
99 pub(crate) static IN_EVENT_HANDLER: Cell<bool> = const { Cell::new(false) };
101 pub(crate) static IN_APPLIED_SNAPSHOT: Cell<bool> = const { Cell::new(false) };
103}
104
105pub fn enter_event_handler() {
109 IN_EVENT_HANDLER.with(|c| c.set(true));
110}
111
112pub fn exit_event_handler() {
114 IN_EVENT_HANDLER.with(|c| c.set(false));
115}
116
117pub fn in_event_handler() -> bool {
119 IN_EVENT_HANDLER.with(|c| c.get())
120}
121
122pub fn in_applied_snapshot() -> bool {
124 IN_APPLIED_SNAPSHOT.with(|c| c.get())
125}
126
127#[cfg(not(target_arch = "wasm32"))]
133fn compose_debug_enabled() -> bool {
134 use std::sync::OnceLock;
135 static COMPOSE_DEBUG: OnceLock<bool> = OnceLock::new();
136 *COMPOSE_DEBUG.get_or_init(|| std::env::var_os("COMPOSE_DEBUG").is_some())
137}
138
139#[cfg(not(target_arch = "wasm32"))]
140fn input_debug_enabled() -> bool {
141 use std::sync::OnceLock;
142 static INPUT_DEBUG: OnceLock<bool> = OnceLock::new();
143 *INPUT_DEBUG.get_or_init(|| std::env::var_os("CRANPOSE_INPUT_DEBUG").is_some())
144}
145
146#[cfg(target_arch = "wasm32")]
147fn input_debug_enabled() -> bool {
148 false
149}
150
151#[cfg(test)]
152pub use runtime::{TestRuntime, TestScheduler};
153
154use crate::collections::map::HashMap;
155use crate::state::{NeverEqual, SnapshotMutableState, UpdateScope};
156use std::any::Any;
157use std::cell::{Cell, Ref, RefCell, RefMut};
158use std::fmt;
159use std::hash::{Hash, Hasher};
160use std::marker::PhantomData;
161use std::ops::{Deref, DerefMut};
162use std::rc::{Rc, Weak}; use std::sync::atomic::{AtomicUsize, Ordering};
164use std::sync::Arc;
165
166pub type Key = u64;
167pub type NodeId = usize;
168
169#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Default)]
175pub struct AnchorId(usize);
176
177impl AnchorId {
178 pub(crate) const INVALID: AnchorId = AnchorId(0);
180
181 pub(crate) fn new(id: usize) -> Self {
183 Self(id)
184 }
185
186 pub fn is_valid(&self) -> bool {
188 self.0 != 0
189 }
190}
191
192pub(crate) type ScopeId = usize;
193type LocalKey = usize;
194pub(crate) type FrameCallbackId = u64;
195type LocalStackSnapshot = Rc<Vec<LocalContext>>;
196
197static NEXT_SCOPE_ID: AtomicUsize = AtomicUsize::new(1);
198static NEXT_LOCAL_KEY: AtomicUsize = AtomicUsize::new(1);
199
200fn next_scope_id() -> ScopeId {
201 NEXT_SCOPE_ID.fetch_add(1, Ordering::Relaxed)
202}
203
204fn next_local_key() -> LocalKey {
205 NEXT_LOCAL_KEY.fetch_add(1, Ordering::Relaxed)
206}
207
208pub(crate) struct RecomposeScopeInner {
209 id: ScopeId,
210 runtime: RuntimeHandle,
211 invalid: Cell<bool>,
212 enqueued: Cell<bool>,
213 active: Cell<bool>,
214 pending_recompose: Cell<bool>,
215 force_reuse: Cell<bool>,
216 force_recompose: Cell<bool>,
217 parent_hint: Cell<Option<NodeId>>,
218 recompose: RefCell<Option<RecomposeCallback>>,
219 local_stack: RefCell<LocalStackSnapshot>,
220 slots_host: RefCell<Option<Weak<SlotsHost>>>,
221}
222
223impl RecomposeScopeInner {
224 fn new(runtime: RuntimeHandle) -> Self {
225 Self {
226 id: next_scope_id(),
227 runtime,
228 invalid: Cell::new(false),
229 enqueued: Cell::new(false),
230 active: Cell::new(true),
231 pending_recompose: Cell::new(false),
232 force_reuse: Cell::new(false),
233 force_recompose: Cell::new(false),
234 parent_hint: Cell::new(None),
235 recompose: RefCell::new(None),
236 local_stack: RefCell::new(Rc::new(Vec::new())),
237 slots_host: RefCell::new(None),
238 }
239 }
240}
241
242type RecomposeCallback = Box<dyn FnMut(&Composer) + 'static>;
243
244#[derive(Clone)]
245pub struct RecomposeScope {
246 inner: Rc<RecomposeScopeInner>, }
248
249impl PartialEq for RecomposeScope {
250 fn eq(&self, other: &Self) -> bool {
251 Rc::ptr_eq(&self.inner, &other.inner)
252 }
253}
254
255impl Eq for RecomposeScope {}
256
257impl RecomposeScope {
258 fn new(runtime: RuntimeHandle) -> Self {
259 Self {
260 inner: Rc::new(RecomposeScopeInner::new(runtime)),
261 }
262 }
263
264 pub fn id(&self) -> ScopeId {
265 self.inner.id
266 }
267
268 pub fn is_invalid(&self) -> bool {
269 self.inner.invalid.get()
270 }
271
272 pub fn is_active(&self) -> bool {
273 self.inner.active.get()
274 }
275
276 fn invalidate(&self) {
277 if input_debug_enabled() {
278 eprintln!(
279 "[CRANPOSE_INPUT_DEBUG] scope invalidate id={} active={} enqueued={}",
280 self.inner.id,
281 self.inner.active.get(),
282 self.inner.enqueued.get()
283 );
284 }
285 self.inner.invalid.set(true);
286 if !self.inner.active.get() {
287 return;
288 }
289 if !self.inner.enqueued.replace(true) {
290 self.inner
291 .runtime
292 .register_invalid_scope(self.inner.id, Rc::downgrade(&self.inner));
293 }
294 }
295
296 fn mark_recomposed(&self) {
297 self.inner.invalid.set(false);
298 self.inner.force_reuse.set(false);
299 self.inner.force_recompose.set(false);
300 if self.inner.enqueued.replace(false) {
301 self.inner.runtime.mark_scope_recomposed(self.inner.id);
302 }
303 let pending = self.inner.pending_recompose.replace(false);
304 if pending {
305 if self.inner.active.get() {
306 self.invalidate();
307 } else {
308 self.inner.invalid.set(true);
309 }
310 }
311 }
312
313 fn downgrade(&self) -> Weak<RecomposeScopeInner> {
314 Rc::downgrade(&self.inner)
315 }
316
317 fn set_recompose(&self, callback: RecomposeCallback) {
318 *self.inner.recompose.borrow_mut() = Some(callback);
319 }
320
321 fn run_recompose(&self, composer: &Composer) {
322 let mut callback_cell = self.inner.recompose.borrow_mut();
323 if let Some(mut callback) = callback_cell.take() {
324 drop(callback_cell);
325 callback(composer);
326 }
327 }
328
329 fn snapshot_locals(&self, stack: LocalStackSnapshot) {
330 *self.inner.local_stack.borrow_mut() = stack;
331 }
332
333 fn local_stack(&self) -> LocalStackSnapshot {
334 self.inner.local_stack.borrow().clone()
335 }
336
337 fn set_parent_hint(&self, parent: Option<NodeId>) {
338 self.inner.parent_hint.set(parent);
339 }
340
341 fn parent_hint(&self) -> Option<NodeId> {
342 self.inner.parent_hint.get()
343 }
344
345 fn set_slots_host(&self, host: Weak<SlotsHost>) {
346 *self.inner.slots_host.borrow_mut() = Some(host);
347 }
348
349 fn slots_host(&self) -> Option<Rc<SlotsHost>> {
350 self.inner
351 .slots_host
352 .borrow()
353 .as_ref()
354 .and_then(|weak| weak.upgrade())
355 }
356
357 pub fn deactivate(&self) {
358 if !self.inner.active.replace(false) {
359 return;
360 }
361 if self.inner.enqueued.replace(false) {
362 self.inner.runtime.mark_scope_recomposed(self.inner.id);
363 }
364 }
365
366 pub fn reactivate(&self) {
367 if self.inner.active.replace(true) {
368 return;
369 }
370 if self.inner.invalid.get() && !self.inner.enqueued.replace(true) {
371 self.inner
372 .runtime
373 .register_invalid_scope(self.inner.id, Rc::downgrade(&self.inner));
374 }
375 }
376
377 pub fn force_reuse(&self) {
378 self.inner.force_reuse.set(true);
379 self.inner.force_recompose.set(false);
380 self.inner.pending_recompose.set(true);
381 }
382
383 pub fn force_recompose(&self) {
384 self.inner.force_recompose.set(true);
385 self.inner.force_reuse.set(false);
386 self.inner.pending_recompose.set(false);
387 }
388
389 pub fn should_recompose(&self) -> bool {
390 if self.inner.force_recompose.replace(false) {
391 self.inner.force_reuse.set(false);
392 return true;
393 }
394 if self.inner.force_reuse.replace(false) {
395 return false;
396 }
397 self.is_invalid()
398 }
399}
400
401#[cfg(test)]
402impl RecomposeScope {
403 pub(crate) fn new_for_test(runtime: RuntimeHandle) -> Self {
404 Self::new(runtime)
405 }
406}
407
408#[derive(Debug, Clone, Copy, Default)]
409pub struct RecomposeOptions {
410 pub force_reuse: bool,
411 pub force_recompose: bool,
412}
413
414#[derive(Debug, Clone, PartialEq, Eq)]
415pub enum NodeError {
416 Missing { id: NodeId },
417 TypeMismatch { id: NodeId, expected: &'static str },
418 MissingContext { id: NodeId, reason: &'static str },
419 AlreadyExists { id: NodeId },
420}
421
422impl std::fmt::Display for NodeError {
423 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
424 match self {
425 NodeError::Missing { id } => write!(f, "node {id} missing"),
426 NodeError::TypeMismatch { id, expected } => {
427 write!(f, "node {id} type mismatch; expected {expected}")
428 }
429 NodeError::MissingContext { id, reason } => {
430 write!(f, "missing context for node {id}: {reason}")
431 }
432 NodeError::AlreadyExists { id } => {
433 write!(f, "node {id} already exists")
434 }
435 }
436 }
437}
438
439impl std::error::Error for NodeError {}
440
441pub use subcompose::{
442 ContentTypeReusePolicy, DefaultSlotReusePolicy, SlotId, SlotReusePolicy, SubcomposeState,
443};
444
445#[derive(Copy, Clone, Debug, PartialEq, Eq)]
446pub enum Phase {
447 Compose,
448 Measure,
449 Layout,
450}
451
452pub use composer_context::with_composer as with_current_composer;
453
454#[allow(non_snake_case)]
455pub fn withCurrentComposer<R>(f: impl FnOnce(&Composer) -> R) -> R {
456 composer_context::with_composer(f)
457}
458
459fn with_current_composer_opt<R>(f: impl FnOnce(&Composer) -> R) -> Option<R> {
460 composer_context::try_with_composer(f)
461}
462
463pub fn with_key<K: Hash>(key: &K, content: impl FnOnce()) {
464 with_current_composer(|composer| composer.with_key(key, |_| content()));
465}
466
467#[allow(non_snake_case)]
468pub fn withKey<K: Hash>(key: &K, content: impl FnOnce()) {
469 with_key(key, content)
470}
471
472pub fn remember<T: 'static>(init: impl FnOnce() -> T) -> Owned<T> {
473 with_current_composer(|composer| composer.remember(init))
474}
475
476#[allow(non_snake_case)]
504pub fn rememberUpdatedState<T: Clone + 'static>(value: T) -> MutableState<T> {
505 with_current_composer(|composer| {
506 let runtime = composer.runtime_handle();
507 let state = composer.remember(|| OwnedMutableState::with_runtime(value.clone(), runtime));
508 state.with(|s| {
509 s.set(value);
510 s.handle()
511 })
512 })
513}
514
515#[cfg(feature = "internal")]
516#[allow(non_snake_case)]
517pub fn withFrameNanos(callback: impl FnOnce(u64) + 'static) -> internal::FrameCallbackRegistration {
518 with_current_composer(|composer| {
519 composer
520 .runtime_handle()
521 .frame_clock()
522 .with_frame_nanos(callback)
523 })
524}
525
526#[cfg(feature = "internal")]
527#[allow(non_snake_case)]
528pub fn withFrameMillis(
529 callback: impl FnOnce(u64) + 'static,
530) -> internal::FrameCallbackRegistration {
531 with_current_composer(|composer| {
532 composer
533 .runtime_handle()
534 .frame_clock()
535 .with_frame_millis(callback)
536 })
537}
538
539#[allow(non_snake_case)]
575pub fn mutableStateOf<T: Clone + 'static>(initial: T) -> MutableState<T> {
576 let runtime = with_current_composer_opt(|composer| composer.runtime_handle())
581 .or_else(runtime::current_runtime_handle)
582 .expect("mutableStateOf requires an active runtime. Create state inside a composition or after a Runtime is created.");
583 runtime.alloc_persistent_state(initial)
584}
585
586#[allow(non_snake_case)]
587pub fn ownedMutableStateOf<T: Clone + 'static>(initial: T) -> OwnedMutableState<T> {
588 let runtime = with_current_composer_opt(|composer| composer.runtime_handle())
589 .or_else(runtime::current_runtime_handle)
590 .expect("ownedMutableStateOf requires an active runtime. Create state inside a composition or after a Runtime is created.");
591 OwnedMutableState::with_runtime(initial, runtime)
592}
593
594#[allow(non_snake_case)]
599pub fn try_mutableStateOf<T: Clone + 'static>(initial: T) -> Option<MutableState<T>> {
600 let runtime = with_current_composer_opt(|composer| composer.runtime_handle())
601 .or_else(runtime::current_runtime_handle)?;
602 Some(runtime.alloc_persistent_state(initial))
603}
604
605#[allow(non_snake_case)]
606pub fn mutableStateListOf<T, I>(values: I) -> SnapshotStateList<T>
607where
608 T: Clone + 'static,
609 I: IntoIterator<Item = T>,
610{
611 with_current_composer(move |composer| composer.mutable_state_list_of(values))
612}
613
614#[allow(non_snake_case)]
615pub fn mutableStateList<T: Clone + 'static>() -> SnapshotStateList<T> {
616 mutableStateListOf(std::iter::empty::<T>())
617}
618
619#[allow(non_snake_case)]
620pub fn mutableStateMapOf<K, V, I>(pairs: I) -> SnapshotStateMap<K, V>
621where
622 K: Clone + Eq + Hash + 'static,
623 V: Clone + 'static,
624 I: IntoIterator<Item = (K, V)>,
625{
626 with_current_composer(move |composer| composer.mutable_state_map_of(pairs))
627}
628
629#[allow(non_snake_case)]
630pub fn mutableStateMap<K, V>() -> SnapshotStateMap<K, V>
631where
632 K: Clone + Eq + Hash + 'static,
633 V: Clone + 'static,
634{
635 mutableStateMapOf(std::iter::empty::<(K, V)>())
636}
637
638#[allow(non_snake_case)]
664pub fn useState<T: Clone + 'static>(init: impl FnOnce() -> T) -> MutableState<T> {
665 with_current_composer(|composer| {
666 let runtime = composer.runtime_handle();
667 composer
668 .remember(|| OwnedMutableState::with_runtime(init(), runtime))
669 .with(|state| state.handle())
670 })
671}
672
673#[allow(deprecated)]
674#[deprecated(
675 since = "0.1.0",
676 note = "use useState(|| value) instead of use_state(|| value)"
677)]
678pub fn use_state<T: Clone + 'static>(init: impl FnOnce() -> T) -> MutableState<T> {
679 useState(init)
680}
681
682#[allow(non_snake_case)]
683pub fn derivedStateOf<T: 'static + Clone>(compute: impl Fn() -> T + 'static) -> State<T> {
684 with_current_composer(|composer| {
685 let key = location_key(file!(), line!(), column!());
686 composer.with_group(key, |composer| {
687 let should_recompute = composer
688 .current_recranpose_scope()
689 .map(|scope| scope.should_recompose())
690 .unwrap_or(true);
691 let runtime = composer.runtime_handle();
692 let compute_rc: Rc<dyn Fn() -> T> = Rc::new(compute); let derived =
694 composer.remember(|| DerivedState::new(runtime.clone(), compute_rc.clone()));
695 derived.update(|derived| {
696 derived.set_compute(compute_rc.clone());
697 if should_recompute {
698 derived.recompute();
699 }
700 });
701 derived.with(|derived| derived.state.as_state())
702 })
703 })
704}
705
706pub struct ProvidedValue {
707 key: LocalKey,
708 #[allow(clippy::type_complexity)] apply: Box<dyn Fn(&Composer) -> Rc<dyn Any>>, }
711
712impl ProvidedValue {
713 fn into_entry(self, composer: &Composer) -> (LocalKey, Rc<dyn Any>) {
714 let ProvidedValue { key, apply } = self;
716 let entry = apply(composer);
717 (key, entry)
718 }
719}
720
721#[allow(non_snake_case)]
722pub fn CompositionLocalProvider(
723 values: impl IntoIterator<Item = ProvidedValue>,
724 content: impl FnOnce(),
725) {
726 with_current_composer(|composer| {
727 let provided: Vec<ProvidedValue> = values.into_iter().collect(); composer.with_composition_locals(provided, |_composer| content());
729 })
730}
731
732struct LocalStateEntry<T: Clone + 'static> {
733 state: OwnedMutableState<T>,
734}
735
736impl<T: Clone + 'static> LocalStateEntry<T> {
737 fn new(initial: T, runtime: RuntimeHandle) -> Self {
738 Self {
739 state: OwnedMutableState::with_runtime(initial, runtime),
740 }
741 }
742
743 fn set(&self, value: T) {
744 self.state.replace(value);
745 }
746
747 fn value(&self) -> T {
748 self.state.value()
749 }
750}
751
752struct StaticLocalEntry<T: Clone + 'static> {
753 value: RefCell<T>,
754}
755
756impl<T: Clone + 'static> StaticLocalEntry<T> {
757 fn new(value: T) -> Self {
758 Self {
759 value: RefCell::new(value),
760 }
761 }
762
763 fn set(&self, value: T) {
764 *self.value.borrow_mut() = value;
765 }
766
767 fn value(&self) -> T {
768 self.value.borrow().clone()
769 }
770}
771
772#[derive(Clone)]
773pub struct CompositionLocal<T: Clone + 'static> {
774 key: LocalKey,
775 default: Rc<dyn Fn() -> T>, }
777
778impl<T: Clone + 'static> PartialEq for CompositionLocal<T> {
779 fn eq(&self, other: &Self) -> bool {
780 self.key == other.key
781 }
782}
783
784impl<T: Clone + 'static> Eq for CompositionLocal<T> {}
785
786impl<T: Clone + 'static> CompositionLocal<T> {
787 pub fn provides(&self, value: T) -> ProvidedValue {
788 let key = self.key;
789 ProvidedValue {
790 key,
791 apply: Box::new(move |composer: &Composer| {
792 let runtime = composer.runtime_handle();
793 let entry_ref = composer
794 .remember(|| Rc::new(LocalStateEntry::new(value.clone(), runtime.clone())));
795 entry_ref.update(|entry| entry.set(value.clone()));
796 entry_ref.with(|entry| entry.clone() as Rc<dyn Any>) }),
798 }
799 }
800
801 pub fn current(&self) -> T {
802 with_current_composer(|composer| composer.read_composition_local(self))
803 }
804
805 pub fn default_value(&self) -> T {
806 (self.default)()
807 }
808}
809
810#[allow(non_snake_case)]
811pub fn compositionLocalOf<T: Clone + 'static>(
812 default: impl Fn() -> T + 'static,
813) -> CompositionLocal<T> {
814 CompositionLocal {
815 key: next_local_key(),
816 default: Rc::new(default), }
818}
819
820#[derive(Clone)]
831pub struct StaticCompositionLocal<T: Clone + 'static> {
832 key: LocalKey,
833 default: Rc<dyn Fn() -> T>, }
835
836impl<T: Clone + 'static> PartialEq for StaticCompositionLocal<T> {
837 fn eq(&self, other: &Self) -> bool {
838 self.key == other.key
839 }
840}
841
842impl<T: Clone + 'static> Eq for StaticCompositionLocal<T> {}
843
844impl<T: Clone + 'static> StaticCompositionLocal<T> {
845 pub fn provides(&self, value: T) -> ProvidedValue {
846 let key = self.key;
847 ProvidedValue {
848 key,
849 apply: Box::new(move |composer: &Composer| {
850 let entry_ref = composer.remember(|| Rc::new(StaticLocalEntry::new(value.clone())));
853 entry_ref.update(|entry| entry.set(value.clone()));
854 entry_ref.with(|entry| entry.clone() as Rc<dyn Any>) }),
856 }
857 }
858
859 pub fn current(&self) -> T {
860 with_current_composer(|composer| composer.read_static_composition_local(self))
861 }
862
863 pub fn default_value(&self) -> T {
864 (self.default)()
865 }
866}
867
868#[allow(non_snake_case)]
869pub fn staticCompositionLocalOf<T: Clone + 'static>(
870 default: impl Fn() -> T + 'static,
871) -> StaticCompositionLocal<T> {
872 StaticCompositionLocal {
873 key: next_local_key(),
874 default: Rc::new(default), }
876}
877
878#[derive(Default)]
879struct DisposableEffectState {
880 key: Option<Key>,
881 cleanup: Option<Box<dyn FnOnce()>>,
882}
883
884impl DisposableEffectState {
885 fn should_run(&self, key: Key) -> bool {
886 match self.key {
887 Some(current) => current != key,
888 None => true,
889 }
890 }
891
892 fn set_key(&mut self, key: Key) {
893 self.key = Some(key);
894 }
895
896 fn set_cleanup(&mut self, cleanup: Option<Box<dyn FnOnce()>>) {
897 self.cleanup = cleanup;
898 }
899
900 fn run_cleanup(&mut self) {
901 if let Some(cleanup) = self.cleanup.take() {
902 cleanup();
903 }
904 }
905}
906
907impl Drop for DisposableEffectState {
908 fn drop(&mut self) {
909 self.run_cleanup();
910 }
911}
912
913#[derive(Clone, Copy, Debug, Default)]
914pub struct DisposableEffectScope;
915
916#[derive(Default)]
917pub struct DisposableEffectResult {
918 cleanup: Option<Box<dyn FnOnce()>>,
919}
920
921impl DisposableEffectScope {
922 pub fn on_dispose(&self, cleanup: impl FnOnce() + 'static) -> DisposableEffectResult {
923 DisposableEffectResult::new(cleanup)
924 }
925}
926
927impl DisposableEffectResult {
928 pub fn new(cleanup: impl FnOnce() + 'static) -> Self {
929 Self {
930 cleanup: Some(Box::new(cleanup)),
931 }
932 }
933
934 fn into_cleanup(self) -> Option<Box<dyn FnOnce()>> {
935 self.cleanup
936 }
937}
938
939#[allow(non_snake_case)]
940pub fn SideEffect(effect: impl FnOnce() + 'static) {
941 with_current_composer(|composer| composer.register_side_effect(effect));
942}
943
944pub fn __disposable_effect_impl<K, F>(group_key: Key, keys: K, effect: F)
945where
946 K: Hash,
947 F: FnOnce(DisposableEffectScope) -> DisposableEffectResult + 'static,
948{
949 with_current_composer(|composer| {
952 composer.with_group(group_key, |composer| {
953 let key_hash = hash_key(&keys);
954 let state = composer.remember(DisposableEffectState::default);
955 if state.with(|state| state.should_run(key_hash)) {
956 state.update(|state| {
957 state.run_cleanup();
958 state.set_key(key_hash);
959 });
960 let state_for_effect = state.clone();
961 let mut effect_opt = Some(effect);
962 composer.register_side_effect(move || {
963 if let Some(effect) = effect_opt.take() {
964 let result = effect(DisposableEffectScope);
965 state_for_effect.update(|state| state.set_cleanup(result.into_cleanup()));
966 }
967 });
968 }
969 });
970 });
971}
972
973#[macro_export]
974macro_rules! DisposableEffect {
975 ($keys:expr, $effect:expr) => {
976 $crate::__disposable_effect_impl(
977 $crate::location_key(file!(), line!(), column!()),
978 $keys,
979 $effect,
980 )
981 };
982}
983
984#[macro_export]
985macro_rules! clone_captures {
986 ($($alias:ident $(= $value:expr)?),+ $(,)?; $body:expr) => {{
987 $(let $alias = $crate::clone_captures!(@clone $alias $(= $value)?);)+
988 $body
989 }};
990 (@clone $alias:ident = $value:expr) => {
991 ($value).clone()
992 };
993 (@clone $alias:ident) => {
994 $alias.clone()
995 };
996}
997
998pub fn with_node_mut<N: Node + 'static, R>(
999 id: NodeId,
1000 f: impl FnOnce(&mut N) -> R,
1001) -> Result<R, NodeError> {
1002 with_current_composer(|composer| composer.with_node_mut(id, f))
1003}
1004
1005pub fn push_parent(id: NodeId) {
1006 with_current_composer(|composer| composer.push_parent(id));
1007}
1008
1009pub fn pop_parent() {
1010 with_current_composer(|composer| composer.pop_parent());
1011}
1012
1013mod slot_storage;
1018pub use slot_storage::{GroupId, SlotStorage, StartGroup, ValueSlotId};
1019
1020pub mod chunked_slot_storage;
1021pub mod hierarchical_slot_storage;
1022pub mod slot_backend;
1023pub mod split_slot_storage;
1024pub use slot_backend::{make_backend, SlotBackend, SlotBackendKind};
1025
1026pub mod slot_table;
1031pub use slot_table::SlotTable;
1032
1033pub trait Node: Any {
1034 fn mount(&mut self) {}
1035 fn update(&mut self) {}
1036 fn unmount(&mut self) {}
1037 fn insert_child(&mut self, _child: NodeId) {}
1038 fn remove_child(&mut self, _child: NodeId) {}
1039 fn move_child(&mut self, _from: usize, _to: usize) {}
1040 fn update_children(&mut self, _children: &[NodeId]) {}
1041 fn children(&self) -> Vec<NodeId> {
1042 Vec::new()
1043 }
1044 fn set_node_id(&mut self, _id: NodeId) {}
1047 fn on_attached_to_parent(&mut self, _parent: NodeId) {}
1050 fn on_removed_from_parent(&mut self) {}
1053 fn parent(&self) -> Option<NodeId> {
1056 None
1057 }
1058 fn mark_needs_layout(&self) {}
1061 fn needs_layout(&self) -> bool {
1063 false
1064 }
1065 fn mark_needs_measure(&self) {}
1068 fn needs_measure(&self) -> bool {
1070 false
1071 }
1072 fn mark_needs_semantics(&self) {}
1074 fn needs_semantics(&self) -> bool {
1076 false
1077 }
1078 fn set_parent_for_bubbling(&mut self, parent: NodeId) {
1086 self.on_attached_to_parent(parent);
1087 }
1088}
1089
1090pub fn bubble_layout_dirty(applier: &mut dyn Applier, node_id: NodeId) {
1109 bubble_layout_dirty_applier(applier, node_id);
1110}
1111
1112pub fn bubble_measure_dirty(applier: &mut dyn Applier, node_id: NodeId) {
1123 bubble_measure_dirty_applier(applier, node_id);
1124}
1125
1126pub fn bubble_semantics_dirty(applier: &mut dyn Applier, node_id: NodeId) {
1132 bubble_semantics_dirty_applier(applier, node_id);
1133}
1134
1135pub fn queue_semantics_invalidation(node_id: NodeId) {
1140 let _ = composer_context::try_with_composer(|composer| {
1141 composer.enqueue_semantics_invalidation(node_id);
1142 });
1143}
1144
1145pub fn bubble_layout_dirty_in_composer<N: Node + 'static>(node_id: NodeId) {
1168 bubble_layout_dirty_composer::<N>(node_id);
1169}
1170
1171pub fn bubble_semantics_dirty_in_composer<N: Node + 'static>(node_id: NodeId) {
1178 bubble_semantics_dirty_composer::<N>(node_id);
1179}
1180
1181fn bubble_layout_dirty_applier(applier: &mut dyn Applier, mut node_id: NodeId) {
1183 if let Ok(node) = applier.get_mut(node_id) {
1186 node.mark_needs_layout();
1187 }
1188
1189 loop {
1191 let parent_id = match applier.get_mut(node_id) {
1193 Ok(node) => node.parent(),
1194 Err(_) => None,
1195 };
1196
1197 match parent_id {
1198 Some(pid) => {
1199 if let Ok(parent) = applier.get_mut(pid) {
1201 if !parent.needs_layout() {
1202 parent.mark_needs_layout();
1203 node_id = pid; } else {
1205 break; }
1207 } else {
1208 break;
1209 }
1210 }
1211 None => break, }
1213 }
1214}
1215
1216fn bubble_measure_dirty_applier(applier: &mut dyn Applier, mut node_id: NodeId) {
1218 if let Ok(node) = applier.get_mut(node_id) {
1220 node.mark_needs_measure();
1221 }
1222
1223 loop {
1225 let parent_id = match applier.get_mut(node_id) {
1227 Ok(node) => node.parent(),
1228 Err(_) => None,
1229 };
1230
1231 match parent_id {
1232 Some(pid) => {
1233 if let Ok(parent) = applier.get_mut(pid) {
1235 if !parent.needs_measure() {
1236 parent.mark_needs_measure();
1237 node_id = pid; } else {
1239 break; }
1241 } else {
1242 break;
1243 }
1244 }
1245 None => {
1246 break; }
1248 }
1249 }
1250}
1251
1252fn bubble_semantics_dirty_applier(applier: &mut dyn Applier, mut node_id: NodeId) {
1254 if let Ok(node) = applier.get_mut(node_id) {
1255 node.mark_needs_semantics();
1256 }
1257
1258 loop {
1259 let parent_id = match applier.get_mut(node_id) {
1260 Ok(node) => node.parent(),
1261 Err(_) => None,
1262 };
1263
1264 match parent_id {
1265 Some(pid) => {
1266 if let Ok(parent) = applier.get_mut(pid) {
1267 if !parent.needs_semantics() {
1268 parent.mark_needs_semantics();
1269 node_id = pid;
1270 } else {
1271 break;
1272 }
1273 } else {
1274 break;
1275 }
1276 }
1277 None => break,
1278 }
1279 }
1280}
1281
1282fn bubble_layout_dirty_composer<N: Node + 'static>(mut node_id: NodeId) {
1286 let _ = with_node_mut(node_id, |node: &mut N| {
1288 node.mark_needs_layout();
1289 });
1290
1291 while let Ok(Some(pid)) = with_node_mut(node_id, |node: &mut N| node.parent()) {
1293 let parent_id = pid;
1294
1295 let should_continue = with_node_mut(parent_id, |node: &mut N| {
1297 if !node.needs_layout() {
1298 node.mark_needs_layout();
1299 true } else {
1301 false }
1303 })
1304 .unwrap_or(false);
1305
1306 if should_continue {
1307 node_id = parent_id;
1308 } else {
1309 break;
1310 }
1311 }
1312}
1313
1314fn bubble_semantics_dirty_composer<N: Node + 'static>(mut node_id: NodeId) {
1316 let _ = with_node_mut(node_id, |node: &mut N| {
1318 node.mark_needs_semantics();
1319 });
1320
1321 while let Ok(Some(pid)) = with_node_mut(node_id, |node: &mut N| node.parent()) {
1322 let parent_id = pid;
1323
1324 let should_continue = with_node_mut(parent_id, |node: &mut N| {
1325 if !node.needs_semantics() {
1326 node.mark_needs_semantics();
1327 true
1328 } else {
1329 false
1330 }
1331 })
1332 .unwrap_or(false);
1333
1334 if should_continue {
1335 node_id = parent_id;
1336 } else {
1337 break;
1338 }
1339 }
1340}
1341
1342impl dyn Node {
1343 pub fn as_any_mut(&mut self) -> &mut dyn Any {
1344 self
1345 }
1346}
1347
1348pub trait Applier: Any {
1349 fn create(&mut self, node: Box<dyn Node>) -> NodeId;
1350 fn get_mut(&mut self, id: NodeId) -> Result<&mut dyn Node, NodeError>;
1351 fn remove(&mut self, id: NodeId) -> Result<(), NodeError>;
1352
1353 fn insert_with_id(&mut self, id: NodeId, node: Box<dyn Node>) -> Result<(), NodeError>;
1361
1362 fn as_any(&self) -> &dyn Any
1363 where
1364 Self: Sized,
1365 {
1366 self
1367 }
1368
1369 fn as_any_mut(&mut self) -> &mut dyn Any
1370 where
1371 Self: Sized,
1372 {
1373 self
1374 }
1375}
1376
1377type TypedNodeUpdate = fn(&mut dyn Node, NodeId) -> Result<(), NodeError>;
1378type CommandCallback = Box<dyn FnOnce(&mut dyn Applier) -> Result<(), NodeError> + 'static>;
1379
1380#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1381pub(crate) struct DirtyBubble {
1382 layout: bool,
1383 measure: bool,
1384 semantics: bool,
1385}
1386
1387impl DirtyBubble {
1388 pub(crate) const LAYOUT_AND_MEASURE: Self = Self {
1389 layout: true,
1390 measure: true,
1391 semantics: false,
1392 };
1393
1394 pub(crate) const SEMANTICS: Self = Self {
1395 layout: false,
1396 measure: false,
1397 semantics: true,
1398 };
1399
1400 fn apply(self, applier: &mut dyn Applier, node_id: NodeId) {
1401 if self.layout {
1402 bubble_layout_dirty(applier, node_id);
1403 }
1404 if self.measure {
1405 bubble_measure_dirty(applier, node_id);
1406 }
1407 if self.semantics {
1408 bubble_semantics_dirty(applier, node_id);
1409 }
1410 }
1411}
1412
1413pub(crate) enum Command {
1414 BubbleDirty {
1415 node_id: NodeId,
1416 bubble: DirtyBubble,
1417 },
1418 UpdateTypedNode {
1419 id: NodeId,
1420 updater: TypedNodeUpdate,
1421 },
1422 RemoveNode {
1423 id: NodeId,
1424 },
1425 MountNode {
1426 id: NodeId,
1427 },
1428 AttachChild {
1429 parent_id: NodeId,
1430 child_id: NodeId,
1431 bubble: DirtyBubble,
1432 },
1433 InsertChild {
1434 parent_id: NodeId,
1435 child_id: NodeId,
1436 appended_index: usize,
1437 insert_index: usize,
1438 bubble: DirtyBubble,
1439 },
1440 MoveChild {
1441 parent_id: NodeId,
1442 from_index: usize,
1443 to_index: usize,
1444 bubble: DirtyBubble,
1445 },
1446 RemoveChild {
1447 parent_id: NodeId,
1448 child_id: NodeId,
1449 },
1450 ReconcileChildren {
1451 parent_id: NodeId,
1452 expected_children: Vec<NodeId>,
1453 needs_dirty_check: bool,
1454 },
1455 Callback(CommandCallback),
1456}
1457
1458impl Command {
1459 pub(crate) fn update_node<N: Node + 'static>(id: NodeId) -> Self {
1460 Self::UpdateTypedNode {
1461 id,
1462 updater: update_typed_node::<N>,
1463 }
1464 }
1465
1466 pub(crate) fn callback(
1467 callback: impl FnOnce(&mut dyn Applier) -> Result<(), NodeError> + 'static,
1468 ) -> Self {
1469 Self::Callback(Box::new(callback))
1470 }
1471
1472 pub(crate) fn apply(self, applier: &mut dyn Applier) -> Result<(), NodeError> {
1473 match self {
1474 Self::BubbleDirty { node_id, bubble } => {
1475 bubble.apply(applier, node_id);
1476 Ok(())
1477 }
1478 Self::UpdateTypedNode { id, updater } => {
1479 let node = match applier.get_mut(id) {
1480 Ok(node) => node,
1481 Err(NodeError::Missing { .. }) => return Ok(()),
1482 Err(err) => return Err(err),
1483 };
1484 updater(node, id)
1485 }
1486 Self::RemoveNode { id } => {
1487 if let Ok(node) = applier.get_mut(id) {
1488 node.unmount();
1489 }
1490 match applier.remove(id) {
1491 Ok(()) | Err(NodeError::Missing { .. }) => Ok(()),
1492 Err(err) => Err(err),
1493 }
1494 }
1495 Self::MountNode { id } => {
1496 let node = match applier.get_mut(id) {
1497 Ok(node) => node,
1498 Err(NodeError::Missing { .. }) => return Ok(()),
1499 Err(err) => return Err(err),
1500 };
1501 node.set_node_id(id);
1502 node.mount();
1503 Ok(())
1504 }
1505 Self::AttachChild {
1506 parent_id,
1507 child_id,
1508 bubble,
1509 } => {
1510 insert_child_with_reparenting(applier, parent_id, child_id);
1511 bubble.apply(applier, parent_id);
1512 Ok(())
1513 }
1514 Self::InsertChild {
1515 parent_id,
1516 child_id,
1517 appended_index,
1518 insert_index,
1519 bubble,
1520 } => {
1521 insert_child_with_reparenting(applier, parent_id, child_id);
1522 bubble.apply(applier, parent_id);
1523 if insert_index != appended_index {
1524 if let Ok(parent_node) = applier.get_mut(parent_id) {
1525 parent_node.move_child(appended_index, insert_index);
1526 }
1527 }
1528 Ok(())
1529 }
1530 Self::MoveChild {
1531 parent_id,
1532 from_index,
1533 to_index,
1534 bubble,
1535 } => {
1536 if let Ok(parent_node) = applier.get_mut(parent_id) {
1537 parent_node.move_child(from_index, to_index);
1538 }
1539 bubble.apply(applier, parent_id);
1540 Ok(())
1541 }
1542 Self::RemoveChild {
1543 parent_id,
1544 child_id,
1545 } => apply_remove_child(applier, parent_id, child_id),
1546 Self::ReconcileChildren {
1547 parent_id,
1548 expected_children,
1549 needs_dirty_check,
1550 } => reconcile_children(applier, parent_id, &expected_children, needs_dirty_check),
1551 Self::Callback(callback) => callback(applier),
1552 }
1553 }
1554}
1555
1556fn update_typed_node<N: Node + 'static>(node: &mut dyn Node, id: NodeId) -> Result<(), NodeError> {
1557 let typed = node
1558 .as_any_mut()
1559 .downcast_mut::<N>()
1560 .ok_or(NodeError::TypeMismatch {
1561 id,
1562 expected: std::any::type_name::<N>(),
1563 })?;
1564 typed.update();
1565 Ok(())
1566}
1567
1568fn insert_child_with_reparenting(applier: &mut dyn Applier, parent_id: NodeId, child_id: NodeId) {
1569 let old_parent = applier
1570 .get_mut(child_id)
1571 .ok()
1572 .and_then(|node| node.parent());
1573 if let Some(old_parent_id) = old_parent {
1574 if old_parent_id != parent_id {
1575 if let Ok(old_parent_node) = applier.get_mut(old_parent_id) {
1576 old_parent_node.remove_child(child_id);
1577 }
1578 if let Ok(child_node) = applier.get_mut(child_id) {
1579 child_node.on_removed_from_parent();
1580 }
1581 bubble_layout_dirty(applier, old_parent_id);
1582 bubble_measure_dirty(applier, old_parent_id);
1583 }
1584 }
1585
1586 if let Ok(parent_node) = applier.get_mut(parent_id) {
1587 parent_node.insert_child(child_id);
1588 }
1589 if let Ok(child_node) = applier.get_mut(child_id) {
1590 child_node.on_attached_to_parent(parent_id);
1591 }
1592}
1593
1594fn apply_remove_child(
1595 applier: &mut dyn Applier,
1596 parent_id: NodeId,
1597 child_id: NodeId,
1598) -> Result<(), NodeError> {
1599 if let Ok(parent_node) = applier.get_mut(parent_id) {
1600 parent_node.remove_child(child_id);
1601 }
1602 bubble_layout_dirty(applier, parent_id);
1603 bubble_measure_dirty(applier, parent_id);
1604
1605 let should_remove = if let Ok(node) = applier.get_mut(child_id) {
1606 match node.parent() {
1607 Some(existing_parent_id) if existing_parent_id == parent_id => {
1608 node.on_removed_from_parent();
1609 node.unmount();
1610 true
1611 }
1612 None => {
1613 node.unmount();
1614 true
1615 }
1616 Some(_) => false,
1617 }
1618 } else {
1619 true
1620 };
1621
1622 if should_remove {
1623 let _ = applier.remove(child_id);
1624 }
1625 Ok(())
1626}
1627
1628fn reconcile_children(
1629 applier: &mut dyn Applier,
1630 parent_id: NodeId,
1631 expected_children: &[NodeId],
1632 needs_dirty_check: bool,
1633) -> Result<(), NodeError> {
1634 let mut repaired = false;
1635 for &child_id in expected_children {
1636 let needs_attach = if let Ok(node) = applier.get_mut(child_id) {
1637 node.parent() != Some(parent_id)
1638 } else {
1639 false
1640 };
1641
1642 if needs_attach {
1643 insert_child_with_reparenting(applier, parent_id, child_id);
1644 repaired = true;
1645 }
1646 }
1647
1648 let is_dirty = if needs_dirty_check {
1649 if let Ok(node) = applier.get_mut(parent_id) {
1650 node.needs_layout()
1651 } else {
1652 false
1653 }
1654 } else {
1655 false
1656 };
1657
1658 if repaired {
1659 bubble_layout_dirty(applier, parent_id);
1660 bubble_measure_dirty(applier, parent_id);
1661 } else if is_dirty {
1662 bubble_layout_dirty(applier, parent_id);
1663 }
1664
1665 Ok(())
1666}
1667
1668#[derive(Default)]
1669pub struct MemoryApplier {
1670 nodes: Vec<Option<Box<dyn Node>>>, high_id_nodes: std::collections::HashMap<NodeId, Box<dyn Node>>,
1674 layout_runtime: Option<RuntimeHandle>,
1675 slots: SlotBackend,
1676}
1677
1678impl MemoryApplier {
1679 pub fn new() -> Self {
1680 Self {
1681 nodes: Vec::new(),
1682 high_id_nodes: std::collections::HashMap::new(),
1683 layout_runtime: None,
1684 slots: SlotBackend::default(),
1685 }
1686 }
1687
1688 pub fn slots(&mut self) -> &mut SlotBackend {
1689 &mut self.slots
1690 }
1691
1692 pub fn with_node<N: Node + 'static, R>(
1693 &mut self,
1694 id: NodeId,
1695 f: impl FnOnce(&mut N) -> R,
1696 ) -> Result<R, NodeError> {
1697 let slot = self
1698 .nodes
1699 .get_mut(id)
1700 .ok_or(NodeError::Missing { id })?
1701 .as_deref_mut()
1702 .ok_or(NodeError::Missing { id })?;
1703 let typed = slot
1704 .as_any_mut()
1705 .downcast_mut::<N>()
1706 .ok_or(NodeError::TypeMismatch {
1707 id,
1708 expected: std::any::type_name::<N>(),
1709 })?;
1710 Ok(f(typed))
1711 }
1712
1713 pub fn len(&self) -> usize {
1714 self.nodes.iter().filter(|n| n.is_some()).count()
1715 }
1716
1717 pub fn is_empty(&self) -> bool {
1718 self.len() == 0
1719 }
1720
1721 pub fn set_runtime_handle(&mut self, handle: RuntimeHandle) {
1722 self.layout_runtime = Some(handle);
1723 }
1724
1725 pub fn clear_runtime_handle(&mut self) {
1726 self.layout_runtime = None;
1727 }
1728
1729 pub fn runtime_handle(&self) -> Option<RuntimeHandle> {
1730 self.layout_runtime.clone()
1731 }
1732
1733 pub fn dump_tree(&self, root: Option<NodeId>) -> String {
1734 let mut output = String::new();
1735 if let Some(root_id) = root {
1736 self.dump_node(&mut output, root_id, 0);
1737 } else {
1738 output.push_str("(no root)\n");
1739 }
1740 output
1741 }
1742
1743 fn dump_node(&self, output: &mut String, id: NodeId, depth: usize) {
1744 let indent = " ".repeat(depth);
1745 if let Some(Some(node)) = self.nodes.get(id) {
1746 let type_name = std::any::type_name_of_val(&**node);
1747 output.push_str(&format!("{}[{}] {}\n", indent, id, type_name));
1748
1749 let children = node.children();
1750 for child_id in children {
1751 self.dump_node(output, child_id, depth + 1);
1752 }
1753 } else {
1754 output.push_str(&format!("{}[{}] (missing)\n", indent, id));
1755 }
1756 }
1757}
1758
1759impl Applier for MemoryApplier {
1760 fn create(&mut self, node: Box<dyn Node>) -> NodeId {
1761 let id = self.nodes.len();
1762 self.nodes.push(Some(node));
1763 id
1764 }
1765
1766 fn get_mut(&mut self, id: NodeId) -> Result<&mut dyn Node, NodeError> {
1767 if id < self.nodes.len() {
1769 let slot = self.nodes[id]
1770 .as_deref_mut()
1771 .ok_or(NodeError::Missing { id })?;
1772 return Ok(slot);
1773 }
1774 self.high_id_nodes
1775 .get_mut(&id)
1776 .map(|n| n.as_mut())
1777 .ok_or(NodeError::Missing { id })
1778 }
1779
1780 fn remove(&mut self, id: NodeId) -> Result<(), NodeError> {
1781 let (children, is_high_id) = if id < self.nodes.len() {
1783 let slot = self.nodes.get(id).ok_or(NodeError::Missing { id })?;
1784 let node = slot.as_ref().ok_or(NodeError::Missing { id })?;
1785 (node.children(), false)
1786 } else if let Some(node) = self.high_id_nodes.get(&id) {
1787 (node.children(), true)
1788 } else {
1789 return Err(NodeError::Missing { id });
1790 };
1791
1792 for child_id in children {
1794 let is_owned = self
1795 .get_mut(child_id)
1796 .map(|child| child.parent() == Some(id))
1797 .unwrap_or(false);
1798 if is_owned {
1799 let _ = self.remove(child_id);
1800 }
1801 }
1802
1803 if is_high_id {
1804 self.high_id_nodes.remove(&id);
1805 } else {
1806 self.nodes[id].take();
1807 }
1808 Ok(())
1809 }
1810
1811 fn insert_with_id(&mut self, id: NodeId, node: Box<dyn Node>) -> Result<(), NodeError> {
1812 const HIGH_ID_THRESHOLD: NodeId = 1_000_000_000; if id >= HIGH_ID_THRESHOLD {
1817 if self.high_id_nodes.contains_key(&id) {
1818 return Err(NodeError::AlreadyExists { id });
1819 }
1820 self.high_id_nodes.insert(id, node);
1821 Ok(())
1822 } else {
1823 if id >= self.nodes.len() {
1825 self.nodes.resize_with(id + 1, || None);
1826 }
1827
1828 if self.nodes[id].is_some() {
1829 return Err(NodeError::AlreadyExists { id });
1830 }
1831
1832 self.nodes[id] = Some(node);
1833 Ok(())
1834 }
1835 }
1836}
1837
1838pub trait ApplierHost {
1839 fn borrow_dyn(&self) -> RefMut<'_, dyn Applier>;
1840}
1841
1842pub struct ConcreteApplierHost<A: Applier + 'static> {
1843 inner: RefCell<A>,
1844}
1845
1846impl<A: Applier + 'static> ConcreteApplierHost<A> {
1847 pub fn new(applier: A) -> Self {
1848 Self {
1849 inner: RefCell::new(applier),
1850 }
1851 }
1852
1853 pub fn borrow_typed(&self) -> RefMut<'_, A> {
1854 self.inner.borrow_mut()
1855 }
1856
1857 pub fn try_borrow_typed(&self) -> Result<RefMut<'_, A>, std::cell::BorrowMutError> {
1858 self.inner.try_borrow_mut()
1859 }
1860
1861 pub fn into_inner(self) -> A {
1862 self.inner.into_inner()
1863 }
1864}
1865
1866impl<A: Applier + 'static> ApplierHost for ConcreteApplierHost<A> {
1867 fn borrow_dyn(&self) -> RefMut<'_, dyn Applier> {
1868 RefMut::map(self.inner.borrow_mut(), |applier| {
1869 applier as &mut dyn Applier
1870 })
1871 }
1872}
1873
1874pub struct ApplierGuard<'a, A: Applier + 'static> {
1875 inner: RefMut<'a, A>,
1876}
1877
1878impl<'a, A: Applier + 'static> ApplierGuard<'a, A> {
1879 fn new(inner: RefMut<'a, A>) -> Self {
1880 Self { inner }
1881 }
1882}
1883
1884impl<'a, A: Applier + 'static> Deref for ApplierGuard<'a, A> {
1885 type Target = A;
1886
1887 fn deref(&self) -> &Self::Target {
1888 &self.inner
1889 }
1890}
1891
1892impl<'a, A: Applier + 'static> DerefMut for ApplierGuard<'a, A> {
1893 fn deref_mut(&mut self) -> &mut Self::Target {
1894 &mut self.inner
1895 }
1896}
1897
1898pub struct SlotsHost {
1899 inner: RefCell<SlotBackend>,
1900}
1901
1902impl SlotsHost {
1903 pub fn new(storage: SlotBackend) -> Self {
1904 Self {
1905 inner: RefCell::new(storage),
1906 }
1907 }
1908
1909 pub fn borrow(&self) -> Ref<'_, SlotBackend> {
1910 self.inner.borrow()
1911 }
1912
1913 pub fn borrow_mut(&self) -> RefMut<'_, SlotBackend> {
1914 self.inner.borrow_mut()
1915 }
1916
1917 pub fn take(&self) -> SlotBackend {
1918 std::mem::take(&mut *self.inner.borrow_mut())
1919 }
1920}
1921
1922pub(crate) struct ComposerCore {
1923 slots: Rc<SlotsHost>,
1924 slots_override: RefCell<Vec<Rc<SlotsHost>>>,
1925 applier: Rc<dyn ApplierHost>,
1926 runtime: RuntimeHandle,
1927 observer: SnapshotStateObserver,
1928 parent_stack: RefCell<Vec<ParentFrame>>,
1929 subcompose_stack: RefCell<Vec<SubcomposeFrame>>,
1930 root: Cell<Option<NodeId>>,
1931 commands: RefCell<Vec<Command>>,
1932 scope_stack: RefCell<Vec<RecomposeScope>>,
1933 local_stack: RefCell<LocalStackSnapshot>,
1934 side_effects: RefCell<Vec<Box<dyn FnOnce()>>>,
1935 pending_scope_options: RefCell<Option<RecomposeOptions>>,
1936 phase: Cell<Phase>,
1937 last_node_reused: Cell<Option<bool>>,
1938 recranpose_parent_hint: Cell<Option<NodeId>>,
1939 _not_send: PhantomData<*const ()>,
1940}
1941
1942impl ComposerCore {
1943 pub fn new(
1944 slots: Rc<SlotsHost>,
1945 applier: Rc<dyn ApplierHost>,
1946 runtime: RuntimeHandle,
1947 observer: SnapshotStateObserver,
1948 root: Option<NodeId>,
1949 ) -> Self {
1950 let parent_stack = if let Some(root_id) = root {
1956 vec![ParentFrame {
1957 id: root_id,
1958 remembered: Owned::new(ParentChildren::default()),
1959 previous: Vec::new(),
1960 new_children: Vec::new(),
1961 }]
1962 } else {
1963 Vec::new()
1964 };
1965
1966 Self {
1967 slots,
1968 slots_override: RefCell::new(Vec::new()),
1969 applier,
1970 runtime,
1971 observer,
1972 parent_stack: RefCell::new(parent_stack),
1973 subcompose_stack: RefCell::new(Vec::new()),
1974 root: Cell::new(root),
1975 commands: RefCell::new(Vec::new()),
1976 scope_stack: RefCell::new(Vec::new()),
1977 local_stack: RefCell::new(Rc::new(Vec::new())),
1978 side_effects: RefCell::new(Vec::new()),
1979 pending_scope_options: RefCell::new(None),
1980 phase: Cell::new(Phase::Compose),
1981 last_node_reused: Cell::new(None),
1982 recranpose_parent_hint: Cell::new(None),
1983 _not_send: PhantomData,
1984 }
1985 }
1986}
1987
1988#[derive(Clone)]
1989pub struct Composer {
1990 core: Rc<ComposerCore>,
1991}
1992
1993impl Composer {
1994 pub fn new(
1995 slots: Rc<SlotsHost>,
1996 applier: Rc<dyn ApplierHost>,
1997 runtime: RuntimeHandle,
1998 observer: SnapshotStateObserver,
1999 root: Option<NodeId>,
2000 ) -> Self {
2001 let core = Rc::new(ComposerCore::new(slots, applier, runtime, observer, root));
2002 Self { core }
2003 }
2004
2005 pub(crate) fn from_core(core: Rc<ComposerCore>) -> Self {
2006 Self { core }
2007 }
2008
2009 pub(crate) fn clone_core(&self) -> Rc<ComposerCore> {
2010 Rc::clone(&self.core)
2011 }
2012
2013 fn observer(&self) -> SnapshotStateObserver {
2014 self.core.observer.clone()
2015 }
2016
2017 fn observe_scope<R>(&self, scope: &RecomposeScope, block: impl FnOnce() -> R) -> R {
2018 let observer = self.observer();
2019 let scope_clone = scope.clone();
2020 observer.observe_reads(scope_clone, move |scope_ref| scope_ref.invalidate(), block)
2021 }
2022
2023 fn active_slots_host(&self) -> Rc<SlotsHost> {
2024 self.core
2025 .slots_override
2026 .borrow()
2027 .last()
2028 .cloned()
2029 .unwrap_or_else(|| Rc::clone(&self.core.slots))
2030 }
2031
2032 fn with_slots<R>(&self, f: impl FnOnce(&SlotBackend) -> R) -> R {
2033 let host = self.active_slots_host();
2034 let slots = host.borrow();
2035 f(&slots)
2036 }
2037
2038 fn with_slots_mut<R>(&self, f: impl FnOnce(&mut SlotBackend) -> R) -> R {
2039 let host = self.active_slots_host();
2040 let mut slots = host.borrow_mut();
2041 f(&mut slots)
2042 }
2043
2044 fn with_slot_override<R>(&self, slots: Rc<SlotsHost>, f: impl FnOnce(&Composer) -> R) -> R {
2045 self.core.slots_override.borrow_mut().push(slots);
2046 struct Guard {
2047 core: Rc<ComposerCore>,
2048 }
2049 impl Drop for Guard {
2050 fn drop(&mut self) {
2051 self.core.slots_override.borrow_mut().pop();
2052 }
2053 }
2054 let guard = Guard {
2055 core: self.clone_core(),
2056 };
2057 let result = f(self);
2058 drop(guard);
2059 result
2060 }
2061
2062 fn parent_stack(&self) -> RefMut<'_, Vec<ParentFrame>> {
2063 self.core.parent_stack.borrow_mut()
2064 }
2065
2066 fn subcompose_stack(&self) -> RefMut<'_, Vec<SubcomposeFrame>> {
2067 self.core.subcompose_stack.borrow_mut()
2068 }
2069
2070 fn commands_mut(&self) -> RefMut<'_, Vec<Command>> {
2071 self.core.commands.borrow_mut()
2072 }
2073
2074 pub(crate) fn enqueue_semantics_invalidation(&self, id: NodeId) {
2075 self.commands_mut().push(Command::BubbleDirty {
2076 node_id: id,
2077 bubble: DirtyBubble::SEMANTICS,
2078 });
2079 }
2080
2081 fn scope_stack(&self) -> RefMut<'_, Vec<RecomposeScope>> {
2082 self.core.scope_stack.borrow_mut()
2083 }
2084
2085 fn local_stack(&self) -> RefMut<'_, LocalStackSnapshot> {
2086 self.core.local_stack.borrow_mut()
2087 }
2088
2089 fn current_local_stack(&self) -> LocalStackSnapshot {
2090 self.core.local_stack.borrow().clone()
2091 }
2092
2093 fn side_effects_mut(&self) -> RefMut<'_, Vec<Box<dyn FnOnce()>>> {
2094 self.core.side_effects.borrow_mut()
2095 }
2096
2097 fn pending_scope_options(&self) -> RefMut<'_, Option<RecomposeOptions>> {
2098 self.core.pending_scope_options.borrow_mut()
2099 }
2100
2101 fn borrow_applier(&self) -> RefMut<'_, dyn Applier> {
2102 self.core.applier.borrow_dyn()
2103 }
2104
2105 pub fn register_virtual_node(
2112 &self,
2113 node_id: NodeId,
2114 node: Box<dyn Node>,
2115 ) -> Result<(), NodeError> {
2116 let mut applier = self.borrow_applier();
2117 applier.insert_with_id(node_id, node)
2118 }
2119
2120 pub fn node_has_no_parent(&self, node_id: NodeId) -> bool {
2123 let mut applier = self.borrow_applier();
2124 match applier.get_mut(node_id) {
2125 Ok(node) => node.parent().is_none(),
2126 Err(_) => true, }
2128 }
2129
2130 pub fn get_node_children(&self, node_id: NodeId) -> Vec<NodeId> {
2135 let mut applier = self.borrow_applier();
2136 match applier.get_mut(node_id) {
2137 Ok(node) => node.children(),
2138 Err(_) => Vec::new(),
2139 }
2140 }
2141
2142 pub fn clear_node_children(&self, node_id: NodeId) {
2148 let mut applier = self.borrow_applier();
2149 if let Ok(node) = applier.get_mut(node_id) {
2150 node.update_children(&[]);
2152 }
2153 }
2154
2155 pub fn install<R>(&self, f: impl FnOnce(&Composer) -> R) -> R {
2156 let _composer_guard = composer_context::enter(self);
2157 runtime::push_active_runtime(&self.core.runtime);
2158 struct Guard;
2159 impl Drop for Guard {
2160 fn drop(&mut self) {
2161 runtime::pop_active_runtime();
2162 }
2163 }
2164 let guard = Guard;
2165 let result = f(self);
2166 drop(guard);
2167 result
2168 }
2169
2170 pub fn with_group<R>(&self, key: Key, f: impl FnOnce(&Composer) -> R) -> R {
2171 let (group, scope_ref, restored_from_gap) = self.with_slots_mut(|slots| {
2172 let StartGroup {
2173 group,
2174 restored_from_gap,
2175 } = slots.begin_group(key);
2176 let scope_ref = slots
2177 .remember(|| RecomposeScope::new(self.runtime_handle()))
2178 .with(|scope| scope.clone());
2179 (group, scope_ref, restored_from_gap)
2180 });
2181
2182 if restored_from_gap {
2183 scope_ref.force_recompose();
2184 }
2185
2186 if let Some(options) = self.pending_scope_options().take() {
2187 if options.force_recompose {
2188 scope_ref.force_recompose();
2189 } else if options.force_reuse {
2190 scope_ref.force_reuse();
2191 }
2192 }
2193
2194 self.with_slots_mut(|slots| {
2195 SlotStorage::set_group_scope(slots, group, scope_ref.id());
2196 });
2197
2198 let slots_host = self.active_slots_host();
2199 scope_ref.set_slots_host(Rc::downgrade(&slots_host));
2200
2201 {
2202 let mut stack = self.scope_stack();
2203 stack.push(scope_ref.clone());
2204 }
2205
2206 {
2207 let mut stack = self.subcompose_stack();
2208 if let Some(frame) = stack.last_mut() {
2209 frame.scopes.push(scope_ref.clone());
2210 }
2211 }
2212
2213 scope_ref.snapshot_locals(self.current_local_stack());
2214 {
2215 let parent_hint = self.parent_stack().last().map(|frame| frame.id);
2216 scope_ref.set_parent_hint(parent_hint);
2217 }
2218
2219 let result = self.observe_scope(&scope_ref, || f(self));
2220
2221 let trimmed = self.with_slots_mut(|slots| slots.finalize_current_group());
2222 if trimmed {
2223 scope_ref.force_recompose();
2224 }
2225
2226 {
2227 let mut stack = self.scope_stack();
2228 stack.pop();
2229 }
2230 scope_ref.mark_recomposed();
2231 self.with_slots_mut(|slots| slots.end_group());
2232 result
2233 }
2234
2235 pub fn cranpose_with_reuse<R>(
2236 &self,
2237 key: Key,
2238 options: RecomposeOptions,
2239 f: impl FnOnce(&Composer) -> R,
2240 ) -> R {
2241 self.pending_scope_options().replace(options);
2242 self.with_group(key, f)
2243 }
2244
2245 pub fn with_key<K: Hash, R>(&self, key: &K, f: impl FnOnce(&Composer) -> R) -> R {
2246 let hashed = hash_key(key);
2247 self.with_group(hashed, f)
2248 }
2249
2250 pub fn remember<T: 'static>(&self, init: impl FnOnce() -> T) -> Owned<T> {
2251 self.with_slots_mut(|slots| slots.remember(init))
2252 }
2253
2254 pub fn use_value_slot<T: 'static>(&self, init: impl FnOnce() -> T) -> usize {
2255 self.with_slots_mut(|slots| slots.alloc_value_slot(init).index())
2256 }
2257
2258 pub fn with_slot_value<T: 'static, R>(&self, idx: usize, f: impl FnOnce(&T) -> R) -> R {
2259 self.with_slots(|slots| {
2260 let value = SlotStorage::read_value(slots, ValueSlotId::new(idx));
2261 f(value)
2262 })
2263 }
2264
2265 pub fn with_slot_value_mut<T: 'static, R>(&self, idx: usize, f: impl FnOnce(&mut T) -> R) -> R {
2266 self.with_slots_mut(|slots| {
2267 let value = SlotStorage::read_value_mut(slots, ValueSlotId::new(idx));
2268 f(value)
2269 })
2270 }
2271
2272 pub fn write_slot_value<T: 'static>(&self, idx: usize, value: T) {
2273 self.with_slots_mut(|slots| slots.write_value(ValueSlotId::new(idx), value));
2274 }
2275
2276 pub fn mutable_state_of<T: Clone + 'static>(&self, initial: T) -> MutableState<T> {
2277 MutableState::with_runtime(initial, self.runtime_handle())
2278 }
2279
2280 pub fn mutable_state_list_of<T, I>(&self, values: I) -> SnapshotStateList<T>
2281 where
2282 T: Clone + 'static,
2283 I: IntoIterator<Item = T>,
2284 {
2285 SnapshotStateList::with_runtime(values, self.runtime_handle())
2286 }
2287
2288 pub fn mutable_state_map_of<K, V, I>(&self, pairs: I) -> SnapshotStateMap<K, V>
2289 where
2290 K: Clone + Eq + Hash + 'static,
2291 V: Clone + 'static,
2292 I: IntoIterator<Item = (K, V)>,
2293 {
2294 SnapshotStateMap::with_runtime(pairs, self.runtime_handle())
2295 }
2296
2297 pub fn read_composition_local<T: Clone + 'static>(&self, local: &CompositionLocal<T>) -> T {
2298 let stack = self.core.local_stack.borrow();
2299 for context in stack.iter().rev() {
2300 if let Some(entry) = context.values.get(&local.key) {
2301 let typed = entry
2302 .clone()
2303 .downcast::<LocalStateEntry<T>>()
2304 .expect("composition local type mismatch");
2305 return typed.value();
2306 }
2307 }
2308 local.default_value()
2309 }
2310
2311 pub fn read_static_composition_local<T: Clone + 'static>(
2312 &self,
2313 local: &StaticCompositionLocal<T>,
2314 ) -> T {
2315 let stack = self.core.local_stack.borrow();
2316 for context in stack.iter().rev() {
2317 if let Some(entry) = context.values.get(&local.key) {
2318 let typed = entry
2319 .clone()
2320 .downcast::<StaticLocalEntry<T>>()
2321 .expect("static composition local type mismatch");
2322 return typed.value();
2323 }
2324 }
2325 local.default_value()
2326 }
2327
2328 pub fn current_recranpose_scope(&self) -> Option<RecomposeScope> {
2329 self.core.scope_stack.borrow().last().cloned()
2330 }
2331
2332 pub fn phase(&self) -> Phase {
2333 self.core.phase.get()
2334 }
2335
2336 pub(crate) fn set_phase(&self, phase: Phase) {
2337 self.core.phase.set(phase);
2338 }
2339
2340 pub fn enter_phase(&self, phase: Phase) {
2341 self.set_phase(phase);
2342 }
2343
2344 pub(crate) fn subcompose<R>(
2345 &self,
2346 state: &mut SubcomposeState,
2347 slot_id: SlotId,
2348 content: impl FnOnce(&Composer) -> R,
2349 ) -> (R, Vec<NodeId>) {
2350 match self.phase() {
2351 Phase::Measure | Phase::Layout => {}
2352 current => panic!(
2353 "subcompose() may only be called during measure or layout; current phase: {:?}",
2354 current
2355 ),
2356 }
2357
2358 self.subcompose_stack().push(SubcomposeFrame::default());
2359 struct StackGuard {
2360 core: Rc<ComposerCore>,
2361 leaked: bool,
2362 }
2363 impl Drop for StackGuard {
2364 fn drop(&mut self) {
2365 if !self.leaked {
2366 self.core.subcompose_stack.borrow_mut().pop();
2367 }
2368 }
2369 }
2370 let mut guard = StackGuard {
2371 core: self.clone_core(),
2372 leaked: false,
2373 };
2374
2375 let slot_host = state.get_or_create_slots(slot_id);
2376 {
2377 let mut slots = slot_host.borrow_mut();
2378 slots.reset();
2379 }
2380 let result = self.with_slot_override(slot_host.clone(), |composer| {
2381 composer.with_group(slot_id.raw(), |composer| content(composer))
2383 });
2384 {
2385 let mut slots = slot_host.borrow_mut();
2386 slots.finalize_current_group();
2387 slots.flush();
2388 }
2389
2390 let frame = {
2391 let mut stack = guard.core.subcompose_stack.borrow_mut();
2392 let frame = stack.pop().expect("subcompose stack underflow");
2393 guard.leaked = true;
2394 frame
2395 };
2396 let nodes = frame.nodes;
2397 let scopes = frame.scopes;
2398 state.register_active(slot_id, &nodes, &scopes);
2399 (result, nodes)
2400 }
2401
2402 pub fn subcompose_measurement<R>(
2403 &self,
2404 state: &mut SubcomposeState,
2405 slot_id: SlotId,
2406 content: impl FnOnce(&Composer) -> R,
2407 ) -> (R, Vec<NodeId>) {
2408 let (result, nodes) = self.subcompose(state, slot_id, content);
2409
2410 let roots = nodes
2414 .into_iter()
2415 .filter(|&id| self.node_has_no_parent(id))
2416 .collect();
2417
2418 (result, roots)
2419 }
2420
2421 pub fn subcompose_in<R>(
2422 &self,
2423 slots: &Rc<SlotsHost>,
2424 root: Option<NodeId>,
2425 f: impl FnOnce(&Composer) -> R,
2426 ) -> Result<R, NodeError> {
2427 let runtime_handle = self.runtime_handle();
2428 slots.borrow_mut().reset();
2429 let phase = self.phase();
2430 let locals = self.current_local_stack();
2431 let core = Rc::new(ComposerCore::new(
2432 Rc::clone(slots),
2433 Rc::clone(&self.core.applier),
2434 runtime_handle.clone(),
2435 self.observer(),
2436 root,
2437 ));
2438 core.phase.set(phase);
2439 *core.local_stack.borrow_mut() = locals;
2440 let composer = Composer::from_core(core);
2441 let (result, mut commands, side_effects) = composer.install(|composer| {
2442 let output = f(composer);
2443 let commands = composer.take_commands();
2444 let side_effects = composer.take_side_effects();
2445 (output, commands, side_effects)
2446 });
2447
2448 {
2449 let mut applier = self.borrow_applier();
2450 for command in commands.drain(..) {
2451 command.apply(&mut *applier)?;
2452 }
2453 for update in runtime_handle.take_updates() {
2454 update.apply(&mut *applier)?;
2455 }
2456 }
2457 runtime_handle.drain_ui();
2458 for effect in side_effects {
2459 effect();
2460 }
2461 runtime_handle.drain_ui();
2462 {
2463 let mut slots_mut = slots.borrow_mut();
2464 slots_mut.finalize_current_group();
2465 slots_mut.flush();
2466 }
2467 Ok(result)
2468 }
2469
2470 pub fn subcompose_slot<R>(
2475 &self,
2476 slots: &Rc<SlotsHost>,
2477 root: Option<NodeId>,
2478 f: impl FnOnce(&Composer) -> R,
2479 ) -> Result<R, NodeError> {
2480 let runtime_handle = self.runtime_handle();
2481 slots.borrow_mut().reset();
2484 let phase = self.phase();
2485 let locals = self.current_local_stack();
2486 let core = Rc::new(ComposerCore::new(
2487 Rc::clone(slots),
2488 Rc::clone(&self.core.applier),
2489 runtime_handle.clone(),
2490 self.observer(),
2491 root, ));
2493 core.phase.set(phase);
2494 *core.local_stack.borrow_mut() = locals;
2495 let composer = Composer::from_core(core);
2496 let (result, mut commands, side_effects) = composer.install(|composer| {
2497 let output = f(composer);
2498 if root.is_some() {
2502 composer.pop_parent();
2503 }
2504 let commands = composer.take_commands();
2505 let side_effects = composer.take_side_effects();
2506 (output, commands, side_effects)
2507 });
2508
2509 {
2510 let mut applier = self.borrow_applier();
2511 for command in commands.drain(..) {
2512 command.apply(&mut *applier)?;
2513 }
2514 for update in runtime_handle.take_updates() {
2515 update.apply(&mut *applier)?;
2516 }
2517 }
2518 runtime_handle.drain_ui();
2519 for effect in side_effects {
2520 effect();
2521 }
2522 runtime_handle.drain_ui();
2523 Ok(result)
2528 }
2529
2530 pub fn skip_current_group(&self) {
2531 let nodes = self.with_slots(|slots| slots.nodes_in_current_group());
2532 self.with_slots_mut(|slots| slots.skip_current_group());
2533 let current_parent = {
2535 let stack = self.parent_stack();
2536 stack.last().map(|frame| frame.id)
2537 };
2538
2539 let mut applier = self.borrow_applier();
2543 for id in nodes {
2544 if let Ok(node) = applier.get_mut(id) {
2545 let node_parent = node.parent();
2546 if node_parent.is_none() || node_parent == current_parent {
2547 drop(applier);
2548 self.attach_to_parent(id);
2549 applier = self.borrow_applier();
2550 }
2551 }
2552 }
2553 }
2554
2555 pub fn runtime_handle(&self) -> RuntimeHandle {
2556 self.core.runtime.clone()
2557 }
2558
2559 pub fn set_recranpose_callback<F>(&self, callback: F)
2560 where
2561 F: FnMut(&Composer) + 'static,
2562 {
2563 if let Some(scope) = self.current_recranpose_scope() {
2564 let observer = self.observer();
2565 let scope_weak = scope.downgrade();
2566 let mut callback = callback;
2567 scope.set_recompose(Box::new(move |composer: &Composer| {
2568 if let Some(inner) = scope_weak.upgrade() {
2569 let scope_instance = RecomposeScope { inner };
2570 observer.observe_reads(
2571 scope_instance.clone(),
2572 move |scope_ref| scope_ref.invalidate(),
2573 || {
2574 callback(composer);
2575 },
2576 );
2577 }
2578 }));
2579 }
2580 }
2581
2582 pub fn with_composition_locals<R>(
2583 &self,
2584 provided: Vec<ProvidedValue>,
2585 f: impl FnOnce(&Composer) -> R,
2586 ) -> R {
2587 if provided.is_empty() {
2588 return f(self);
2589 }
2590 let mut context = LocalContext::default();
2591 for value in provided {
2592 let (key, entry) = value.into_entry(self);
2593 context.values.insert(key, entry);
2594 }
2595 {
2596 let mut stack = self.local_stack();
2597 Rc::make_mut(&mut *stack).push(context);
2598 }
2599 let result = f(self);
2600 {
2601 let mut stack = self.local_stack();
2602 Rc::make_mut(&mut *stack).pop();
2603 }
2604 result
2605 }
2606
2607 fn recranpose_group(&self, scope: &RecomposeScope) {
2608 if !scope.is_invalid() {
2614 scope.mark_recomposed();
2615 return;
2616 }
2617 let started = self.with_slots_mut(|slots| slots.begin_recranpose_at_scope(scope.id()));
2618 if started.is_some() {
2619 let previous_hint = self
2620 .core
2621 .recranpose_parent_hint
2622 .replace(scope.parent_hint());
2623 struct HintGuard {
2624 core: Rc<ComposerCore>,
2625 previous: Option<NodeId>,
2626 }
2627 impl Drop for HintGuard {
2628 fn drop(&mut self) {
2629 self.core.recranpose_parent_hint.set(self.previous);
2630 }
2631 }
2632 let _hint_guard = HintGuard {
2633 core: self.clone_core(),
2634 previous: previous_hint,
2635 };
2636 {
2637 let mut stack = self.scope_stack();
2638 stack.push(scope.clone());
2639 }
2640 let saved_locals = self.current_local_stack();
2641 {
2642 let mut locals = self.local_stack();
2643 *locals = scope.local_stack();
2644 }
2645 self.observe_scope(scope, || {
2646 scope.run_recompose(self);
2647 });
2648 {
2649 let mut locals = self.local_stack();
2650 *locals = saved_locals;
2651 }
2652 {
2653 let mut stack = self.scope_stack();
2654 stack.pop();
2655 }
2656 self.with_slots_mut(SlotStorage::end_recompose);
2657 scope.mark_recomposed();
2658 } else {
2659 scope.mark_recomposed();
2660 }
2661 }
2662
2663 pub fn use_state<T: Clone + 'static>(&self, init: impl FnOnce() -> T) -> MutableState<T> {
2664 let runtime = self.runtime_handle();
2665 let state = self.with_slots_mut(|slots| {
2666 slots.remember(|| OwnedMutableState::with_runtime(init(), runtime.clone()))
2667 });
2668 state.with(|state| state.handle())
2669 }
2670
2671 pub fn emit_node<N: Node + 'static>(&self, init: impl FnOnce() -> N) -> NodeId {
2672 let (existing_id, type_matches) = {
2674 if let Some(id) = self.with_slots_mut(|slots| slots.peek_node()) {
2675 let mut applier = self.borrow_applier();
2677 let matches = match applier.get_mut(id) {
2678 Ok(node) => node.as_any_mut().downcast_ref::<N>().is_some(),
2679 Err(_) => false,
2680 };
2681 (Some(id), matches)
2682 } else {
2683 (None, false)
2684 }
2685 };
2686
2687 if let Some(id) = existing_id {
2689 if type_matches {
2690 let reuse_allowed = true;
2694
2695 #[cfg(not(target_arch = "wasm32"))]
2696 if compose_debug_enabled() {
2697 eprintln!("emit_node: candidate #{id} reuse_allowed={reuse_allowed}");
2698 }
2699
2700 if reuse_allowed {
2701 self.core.last_node_reused.set(Some(true));
2702 #[cfg(not(target_arch = "wasm32"))]
2703 if compose_debug_enabled() {
2704 eprintln!(
2705 "emit_node: reusing node #{id} as {}",
2706 std::any::type_name::<N>()
2707 );
2708 }
2709 self.with_slots_mut(|slots| slots.advance_after_node_read());
2710
2711 self.commands_mut().push(Command::update_node::<N>(id));
2712 self.attach_to_parent(id);
2713 return id;
2714 }
2715 }
2716 }
2717
2718 if let Some(old_id) = existing_id {
2720 if !type_matches {
2721 #[cfg(not(target_arch = "wasm32"))]
2722 if compose_debug_enabled() {
2723 eprintln!(
2724 "emit_node: replacing node #{old_id} with new {}",
2725 std::any::type_name::<N>()
2726 );
2727 }
2728 self.commands_mut().push(Command::RemoveNode { id: old_id });
2729 }
2730 }
2731
2732 let id = {
2735 let mut applier = self.borrow_applier();
2736 applier.create(Box::new(init()))
2737 };
2738 self.core.last_node_reused.set(Some(false));
2739 #[cfg(not(target_arch = "wasm32"))]
2740 if compose_debug_enabled() {
2741 eprintln!(
2742 "emit_node: creating node #{} as {}",
2743 id,
2744 std::any::type_name::<N>()
2745 );
2746 }
2747 {
2748 self.with_slots_mut(|slots| slots.record_node(id));
2749 }
2750 self.commands_mut().push(Command::MountNode { id });
2751 self.attach_to_parent(id);
2752 id
2753 }
2754
2755 fn attach_to_parent(&self, id: NodeId) {
2756 let mut parent_stack = self.parent_stack();
2762 if let Some(frame) = parent_stack.last_mut() {
2763 let parent_id = frame.id;
2764 if parent_id == id {
2765 return;
2766 }
2767 frame.new_children.push(id);
2768 drop(parent_stack);
2769
2770 {
2781 let mut applier = self.borrow_applier();
2782 if let Ok(child_node) = applier.get_mut(id) {
2783 let existing_parent = child_node.parent();
2784 let should_set = match existing_parent {
2789 None => true,
2790 Some(existing) => {
2791 let root_id = self.core.root.get();
2793 parent_id != root_id.unwrap_or(0) || existing == root_id.unwrap_or(0)
2794 }
2795 };
2796 if should_set {
2797 child_node.set_parent_for_bubbling(parent_id);
2798 }
2799 }
2800 }
2801 return;
2802 }
2803 drop(parent_stack);
2804
2805 let in_subcompose = !self.subcompose_stack().is_empty();
2807 if in_subcompose {
2808 let has_parent = {
2812 let mut applier = self.borrow_applier();
2813 applier
2814 .get_mut(id)
2815 .map(|node| node.parent().is_some())
2816 .unwrap_or(false)
2817 };
2818
2819 if !has_parent {
2820 let mut subcompose_stack = self.subcompose_stack();
2821 if let Some(frame) = subcompose_stack.last_mut() {
2822 frame.nodes.push(id);
2823 }
2824 }
2825 return;
2826 }
2827
2828 if let Some(parent_hint) = self.core.recranpose_parent_hint.get() {
2830 let parent_status = {
2831 let mut applier = self.borrow_applier();
2832 applier
2833 .get_mut(id)
2834 .map(|node| node.parent())
2835 .unwrap_or(None)
2836 };
2837 match parent_status {
2838 Some(existing) if existing == parent_hint => {}
2839 None => {
2840 self.commands_mut().push(Command::AttachChild {
2841 parent_id: parent_hint,
2842 child_id: id,
2843 bubble: DirtyBubble::LAYOUT_AND_MEASURE,
2844 });
2845 }
2846 Some(_) => {}
2847 }
2848 return;
2849 }
2850
2851 let has_parent = {
2856 let mut applier = self.borrow_applier();
2857 applier
2858 .get_mut(id)
2859 .map(|node| node.parent().is_some())
2860 .unwrap_or(false)
2861 };
2862 if has_parent {
2863 return;
2865 }
2866
2867 self.set_root(Some(id));
2869 }
2870
2871 pub fn with_node_mut<N: Node + 'static, R>(
2872 &self,
2873 id: NodeId,
2874 f: impl FnOnce(&mut N) -> R,
2875 ) -> Result<R, NodeError> {
2876 let mut applier = self.borrow_applier();
2877 let node = applier.get_mut(id)?;
2878 let typed = node
2879 .as_any_mut()
2880 .downcast_mut::<N>()
2881 .ok_or(NodeError::TypeMismatch {
2882 id,
2883 expected: std::any::type_name::<N>(),
2884 })?;
2885 Ok(f(typed))
2886 }
2887
2888 pub fn push_parent(&self, id: NodeId) {
2889 let remembered = self.remember(ParentChildren::default);
2890 let reused = self.core.last_node_reused.take().unwrap_or(true);
2891 let in_subcompose = !self.core.subcompose_stack.borrow().is_empty();
2892
2893 let previous = if reused || in_subcompose {
2896 remembered.with(|entry| entry.children.clone())
2897 } else {
2898 Vec::new()
2899 };
2900
2901 self.parent_stack().push(ParentFrame {
2902 id,
2903 remembered,
2904 previous,
2905 new_children: Vec::new(),
2906 });
2907 }
2908
2909 pub fn pop_parent(&self) {
2910 let frame_opt = {
2911 let mut stack = self.parent_stack();
2912 stack.pop()
2913 };
2914 if let Some(frame) = frame_opt {
2915 let ParentFrame {
2916 id,
2917 remembered,
2918 previous,
2919 new_children,
2920 } = frame;
2921
2922 #[cfg(not(target_arch = "wasm32"))]
2923 if compose_debug_enabled() {
2924 eprintln!("pop_parent: node #{}", id);
2925 eprintln!(" previous children: {:?}", previous);
2926 eprintln!(" new children: {:?}", new_children);
2927 }
2928 let children_changed = previous != new_children;
2929
2930 if children_changed {
2931 let target = &new_children;
2932 let mut target_positions = HashMap::default();
2933 target_positions.reserve(target.len());
2934 for (index, &child) in target.iter().enumerate() {
2935 target_positions.insert(child, index);
2936 }
2937
2938 let mut current = previous;
2939
2940 for index in (0..current.len()).rev() {
2941 let child = current[index];
2942 if !target_positions.contains_key(&child) {
2943 current.remove(index);
2944 self.commands_mut().push(Command::RemoveChild {
2945 parent_id: id,
2946 child_id: child,
2947 });
2948 }
2949 }
2950
2951 let mut current_positions = build_child_positions(¤t);
2952 for (target_index, &child) in target.iter().enumerate() {
2953 if let Some(current_index) = current_positions.get(&child).copied() {
2954 if current_index != target_index {
2955 let from_index = current_index;
2956 let to_index = move_child_in_diff_state(
2957 &mut current,
2958 &mut current_positions,
2959 from_index,
2960 target_index,
2961 );
2962 self.commands_mut().push(Command::MoveChild {
2963 parent_id: id,
2964 from_index,
2965 to_index,
2966 bubble: DirtyBubble::LAYOUT_AND_MEASURE,
2967 });
2968 }
2969 } else {
2970 let insert_index = target_index.min(current.len());
2971 let appended_index = current.len();
2972 insert_child_into_diff_state(
2973 &mut current,
2974 &mut current_positions,
2975 insert_index,
2976 child,
2977 );
2978 self.commands_mut().push(Command::InsertChild {
2979 parent_id: id,
2980 child_id: child,
2981 appended_index,
2982 insert_index,
2983 bubble: DirtyBubble::LAYOUT_AND_MEASURE,
2984 });
2985 }
2986 }
2987 }
2988
2989 let expected_children = new_children.clone();
2990 let needs_dirty_check = !children_changed;
2991 self.commands_mut().push(Command::ReconcileChildren {
2992 parent_id: id,
2993 expected_children,
2994 needs_dirty_check,
2995 });
2996
2997 remembered.update(|entry| entry.children = new_children);
2998 }
2999 }
3000
3001 pub(crate) fn take_commands(&self) -> Vec<Command> {
3002 std::mem::take(&mut *self.commands_mut())
3003 }
3004
3005 pub fn apply_pending_commands(&self) -> Result<(), NodeError> {
3010 let mut commands = self.take_commands();
3011 let runtime_handle = self.runtime_handle();
3012 {
3013 let mut applier = self.borrow_applier();
3014 for command in commands.drain(..) {
3015 command.apply(&mut *applier)?;
3016 }
3017 for update in runtime_handle.take_updates() {
3018 update.apply(&mut *applier)?;
3019 }
3020 }
3021 runtime_handle.drain_ui();
3022 Ok(())
3023 }
3024
3025 pub fn register_side_effect(&self, effect: impl FnOnce() + 'static) {
3026 self.side_effects_mut().push(Box::new(effect));
3027 }
3028
3029 pub fn take_side_effects(&self) -> Vec<Box<dyn FnOnce()>> {
3030 std::mem::take(&mut *self.side_effects_mut())
3031 }
3032
3033 pub(crate) fn root(&self) -> Option<NodeId> {
3034 self.core.root.get()
3035 }
3036
3037 pub(crate) fn set_root(&self, node: Option<NodeId>) {
3038 self.core.root.set(node);
3039 }
3040}
3041
3042#[derive(Default, Clone)]
3043struct ParentChildren {
3044 children: Vec<NodeId>,
3045}
3046
3047fn build_child_positions(children: &[NodeId]) -> HashMap<NodeId, usize> {
3048 let mut positions = HashMap::default();
3049 positions.reserve(children.len());
3050 for (index, &child) in children.iter().enumerate() {
3051 positions.insert(child, index);
3052 }
3053 positions
3054}
3055
3056fn refresh_child_positions(
3057 current: &[NodeId],
3058 positions: &mut HashMap<NodeId, usize>,
3059 start: usize,
3060 end: usize,
3061) {
3062 if current.is_empty() || start >= current.len() {
3063 return;
3064 }
3065 let end = end.min(current.len() - 1);
3066 for (offset, &child) in current[start..=end].iter().enumerate() {
3067 positions.insert(child, start + offset);
3068 }
3069}
3070
3071fn insert_child_into_diff_state(
3072 current: &mut Vec<NodeId>,
3073 positions: &mut HashMap<NodeId, usize>,
3074 index: usize,
3075 child: NodeId,
3076) {
3077 let index = index.min(current.len());
3078 current.insert(index, child);
3079 refresh_child_positions(current, positions, index, current.len() - 1);
3080}
3081
3082fn move_child_in_diff_state(
3083 current: &mut Vec<NodeId>,
3084 positions: &mut HashMap<NodeId, usize>,
3085 from_index: usize,
3086 target_index: usize,
3087) -> usize {
3088 let child = current.remove(from_index);
3089 let to_index = target_index.min(current.len());
3090 current.insert(to_index, child);
3091 refresh_child_positions(
3092 current,
3093 positions,
3094 from_index.min(to_index),
3095 from_index.max(to_index),
3096 );
3097 to_index
3098}
3099
3100struct ParentFrame {
3101 id: NodeId,
3102 remembered: Owned<ParentChildren>,
3103 previous: Vec<NodeId>,
3104 new_children: Vec<NodeId>,
3105}
3106
3107#[derive(Default)]
3108struct SubcomposeFrame {
3109 nodes: Vec<NodeId>,
3110 scopes: Vec<RecomposeScope>,
3111}
3112
3113#[derive(Default, Clone)]
3114struct LocalContext {
3115 values: HashMap<LocalKey, Rc<dyn Any>>,
3116}
3117
3118pub(crate) struct MutableStateInner<T: Clone + 'static> {
3119 state: Arc<SnapshotMutableState<T>>,
3120 watchers: RefCell<HashMap<ScopeId, Weak<RecomposeScopeInner>>>, runtime: RuntimeHandle,
3122}
3123
3124impl<T: Clone + 'static> MutableStateInner<T> {
3125 fn new(value: T, runtime: RuntimeHandle) -> Self {
3126 Self {
3127 state: SnapshotMutableState::new_in_arc(value, Arc::new(NeverEqual)),
3128 watchers: RefCell::new(HashMap::default()),
3129 runtime,
3130 }
3131 }
3132
3133 fn install_snapshot_observer(&self, state_id: StateId) {
3134 let runtime_handle = self.runtime.clone();
3135 self.state.add_apply_observer(Box::new(move || {
3136 let runtime = runtime_handle.clone();
3137 runtime_handle.enqueue_ui_task(Box::new(move || {
3138 runtime.with_state_arena(|arena| {
3139 let _ = arena.with_typed_opt::<T, _>(state_id, |inner| {
3140 inner.invalidate_watchers();
3141 });
3142 });
3143 }));
3144 }));
3145 }
3146
3147 fn with_value<R>(&self, f: impl FnOnce(&T) -> R) -> R {
3148 let value = self.state.get();
3149 f(&value)
3150 }
3151
3152 fn register_scope(&self, scope: &RecomposeScope) -> bool {
3153 let mut watchers = self.watchers.borrow_mut();
3154 match watchers.get(&scope.id()) {
3155 Some(existing) if existing.upgrade().is_some() => false,
3156 _ => {
3157 watchers.insert(scope.id(), scope.downgrade());
3158 true
3159 }
3160 }
3161 }
3162
3163 fn invalidate_watchers(&self) {
3164 let watchers: Vec<RecomposeScope> = {
3165 let mut watchers = self.watchers.borrow_mut();
3166 let mut live = Vec::with_capacity(watchers.len());
3167 watchers.retain(|_, weak| {
3168 if let Some(inner) = weak.upgrade() {
3169 live.push(RecomposeScope { inner });
3170 true
3171 } else {
3172 false
3173 }
3174 });
3175 live
3176 };
3177
3178 if input_debug_enabled() {
3179 let scope_ids: Vec<_> = watchers.iter().map(|scope| scope.id()).collect();
3180 eprintln!(
3181 "[CRANPOSE_INPUT_DEBUG] state {:?} invalidate_watchers count={} scopes={:?}",
3182 self.state.id(),
3183 scope_ids.len(),
3184 scope_ids
3185 );
3186 }
3187
3188 for watcher in watchers {
3189 watcher.invalidate();
3190 }
3191 }
3192}
3193
3194fn register_current_state_scope<T: Clone + 'static>(inner: &MutableStateInner<T>) {
3195 let Some(Some(scope)) =
3196 with_current_composer_opt(|composer| composer.current_recranpose_scope())
3197 else {
3198 return;
3199 };
3200 let inserted = inner.register_scope(&scope);
3201 if inserted && input_debug_enabled() {
3202 let watchers = inner.watchers.borrow();
3203 eprintln!(
3204 "[CRANPOSE_INPUT_DEBUG] state {:?} subscribe scope={} watchers={}",
3205 inner.state.id(),
3206 scope.id(),
3207 watchers.len()
3208 );
3209 }
3210}
3211
3212pub struct State<T: Clone + 'static> {
3214 id: StateId,
3215 runtime_id: runtime::RuntimeId,
3216 _marker: PhantomData<fn() -> T>,
3217}
3218
3219pub struct MutableState<T: Clone + 'static> {
3224 id: StateId,
3225 runtime_id: runtime::RuntimeId,
3226 _marker: PhantomData<fn() -> T>,
3227}
3228
3229#[derive(Clone)]
3235pub struct OwnedMutableState<T: Clone + 'static> {
3236 state: MutableState<T>,
3237 _lease: Rc<runtime::StateHandleLease>,
3238 _marker: PhantomData<fn() -> T>,
3239}
3240
3241impl<T: Clone + 'static> PartialEq for State<T> {
3242 fn eq(&self, other: &Self) -> bool {
3243 self.state_id() == other.state_id() && self.runtime_id() == other.runtime_id()
3244 }
3245}
3246
3247impl<T: Clone + 'static> Eq for State<T> {}
3248
3249impl<T: Clone + 'static> PartialEq for MutableState<T> {
3250 fn eq(&self, other: &Self) -> bool {
3251 self.state_id() == other.state_id() && self.runtime_id() == other.runtime_id()
3252 }
3253}
3254
3255impl<T: Clone + 'static> Eq for MutableState<T> {}
3256
3257impl<T: Clone + 'static> Copy for State<T> {}
3258
3259impl<T: Clone + 'static> Clone for State<T> {
3260 fn clone(&self) -> Self {
3261 *self
3262 }
3263}
3264
3265impl<T: Clone + 'static> Copy for MutableState<T> {}
3266
3267impl<T: Clone + 'static> Clone for MutableState<T> {
3268 fn clone(&self) -> Self {
3269 *self
3270 }
3271}
3272
3273impl<T: Clone + 'static> State<T> {
3274 fn state_id(&self) -> StateId {
3275 self.id
3276 }
3277
3278 fn runtime_id(&self) -> runtime::RuntimeId {
3279 self.runtime_id
3280 }
3281
3282 fn runtime_handle(&self) -> RuntimeHandle {
3283 runtime::runtime_handle_by_id(self.runtime_id())
3284 .unwrap_or_else(|| panic!("runtime {:?} dropped", self.runtime_id()))
3285 }
3286
3287 fn with_inner<R>(&self, f: impl FnOnce(&MutableStateInner<T>) -> R) -> R {
3288 self.runtime_handle()
3289 .with_state_arena(|arena| arena.with_typed::<T, R>(self.state_id(), f))
3290 }
3291
3292 fn subscribe_current_scope(&self) {
3293 self.with_inner(register_current_state_scope::<T>);
3294 }
3295
3296 pub fn with<R>(&self, f: impl FnOnce(&T) -> R) -> R {
3297 self.subscribe_current_scope();
3298 self.with_inner(|inner| inner.with_value(f))
3299 }
3300
3301 pub fn value(&self) -> T {
3302 self.subscribe_current_scope();
3303 self.with_inner(|inner| inner.state.get())
3304 }
3305
3306 pub fn get(&self) -> T {
3307 self.value()
3308 }
3309}
3310
3311impl<T: Clone + 'static> MutableState<T> {
3312 pub fn with_runtime(value: T, runtime: RuntimeHandle) -> Self {
3314 runtime.alloc_persistent_state(value)
3315 }
3316
3317 fn from_parts(id: StateId, runtime_id: runtime::RuntimeId) -> Self {
3318 Self {
3319 id,
3320 runtime_id,
3321 _marker: PhantomData,
3322 }
3323 }
3324
3325 pub(crate) fn from_lease(lease: &Rc<runtime::StateHandleLease>) -> Self {
3326 Self::from_parts(lease.id(), lease.runtime().id())
3327 }
3328
3329 fn state_id(&self) -> StateId {
3330 self.id
3331 }
3332
3333 fn runtime_id(&self) -> runtime::RuntimeId {
3334 self.runtime_id
3335 }
3336
3337 fn runtime_handle(&self) -> RuntimeHandle {
3338 runtime::runtime_handle_by_id(self.runtime_id())
3339 .unwrap_or_else(|| panic!("runtime {:?} dropped", self.runtime_id()))
3340 }
3341
3342 fn with_inner<R>(&self, f: impl FnOnce(&MutableStateInner<T>) -> R) -> R {
3343 self.runtime_handle()
3344 .with_state_arena(|arena| arena.with_typed::<T, R>(self.state_id(), f))
3345 }
3346
3347 fn try_with_inner<R>(&self, f: impl FnOnce(&MutableStateInner<T>) -> R) -> Option<R> {
3348 self.runtime_handle()
3349 .with_state_arena(|arena| arena.with_typed_opt::<T, R>(self.state_id(), f))
3350 }
3351
3352 pub fn is_alive(&self) -> bool {
3354 self.try_with_inner(|_| ()).is_some()
3355 }
3356
3357 pub fn try_with<R>(&self, f: impl FnOnce(&T) -> R) -> Option<R> {
3362 self.try_with_inner(|inner| inner.with_value(f))
3363 }
3364
3365 pub fn try_value(&self) -> Option<T> {
3367 self.try_with_inner(|inner| inner.state.get())
3368 }
3369
3370 pub fn as_state(&self) -> State<T> {
3371 State {
3372 id: self.id,
3373 runtime_id: self.runtime_id,
3374 _marker: PhantomData,
3375 }
3376 }
3377
3378 pub fn try_retain(&self) -> Option<OwnedMutableState<T>> {
3380 let lease = self.runtime_handle().retain_state_lease(self.state_id())?;
3381 Some(OwnedMutableState {
3382 state: *self,
3383 _lease: lease,
3384 _marker: PhantomData,
3385 })
3386 }
3387
3388 pub fn retain(&self) -> OwnedMutableState<T> {
3390 self.try_retain()
3391 .unwrap_or_else(|| panic!("state {:?} is no longer alive", self.state_id()))
3392 }
3393
3394 pub fn with<R>(&self, f: impl FnOnce(&T) -> R) -> R {
3395 self.subscribe_current_scope();
3396 self.with_inner(|inner| inner.with_value(f))
3397 }
3398
3399 pub fn update<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
3400 let runtime = self.runtime_handle();
3401 runtime.assert_ui_thread();
3402 runtime.with_state_arena(|arena| {
3403 arena.with_typed::<T, R>(self.state_id(), |inner| {
3404 let mut value = inner.state.get();
3405 let tracker = UpdateScope::new(inner.state.id());
3406 let result = f(&mut value);
3407 let wrote_elsewhere = tracker.finish();
3408 if !wrote_elsewhere {
3409 inner.state.set(value);
3410 }
3411 inner.invalidate_watchers();
3412 result
3413 })
3414 })
3415 }
3416
3417 pub fn replace(&self, value: T) {
3425 let runtime = self.runtime_handle();
3426 runtime.assert_ui_thread();
3427 runtime.with_state_arena(|arena| {
3428 if arena
3429 .with_typed_opt::<T, ()>(self.state_id(), |inner| {
3430 inner.state.set(value);
3431 inner.invalidate_watchers();
3432 })
3433 .is_none()
3434 {
3435 log::debug!(
3436 "MutableState::replace skipped: state cell released (slot={}, gen={})",
3437 self.state_id().slot(),
3438 self.state_id().generation(),
3439 );
3440 }
3441 });
3442 }
3443
3444 pub fn set_value(&self, value: T) {
3445 self.replace(value);
3446 }
3447
3448 pub fn set(&self, value: T) {
3449 self.replace(value);
3450 }
3451
3452 pub fn value(&self) -> T {
3453 self.subscribe_current_scope();
3454 self.with_inner(|inner| inner.state.get())
3455 }
3456
3457 pub fn get(&self) -> T {
3458 self.value()
3459 }
3460
3461 pub fn get_non_reactive(&self) -> T {
3474 self.with_inner(|inner| inner.state.get())
3476 }
3477
3478 fn subscribe_current_scope(&self) {
3479 self.with_inner(register_current_state_scope::<T>);
3480 }
3481
3482 #[cfg(test)]
3483 pub(crate) fn watcher_count(&self) -> usize {
3484 self.with_inner(|inner| inner.watchers.borrow().len())
3485 }
3486
3487 #[cfg(test)]
3488 pub(crate) fn state_id_for_test(&self) -> StateId {
3489 self.state_id()
3490 }
3491
3492 #[cfg(test)]
3493 pub(crate) fn subscribe_scope_for_test(&self, scope: &RecomposeScope) {
3494 self.as_state().subscribe_scope_for_test(scope);
3495 }
3496}
3497
3498impl<T: Clone + 'static> OwnedMutableState<T> {
3499 pub fn with_runtime(value: T, runtime: RuntimeHandle) -> Self {
3501 let lease = runtime.alloc_state(value);
3502 Self {
3503 state: MutableState::from_lease(&lease),
3504 _lease: lease,
3505 _marker: PhantomData,
3506 }
3507 }
3508
3509 pub fn handle(&self) -> MutableState<T> {
3511 self.state
3512 }
3513
3514 pub fn as_state(&self) -> State<T> {
3516 self.state.as_state()
3517 }
3518}
3519
3520impl<T: Clone + 'static> Deref for OwnedMutableState<T> {
3521 type Target = MutableState<T>;
3522
3523 fn deref(&self) -> &Self::Target {
3524 &self.state
3525 }
3526}
3527
3528#[cfg(test)]
3529impl<T: Clone + 'static> State<T> {
3530 pub(crate) fn subscribe_scope_for_test(&self, scope: &RecomposeScope) {
3531 self.with_inner(|inner| {
3532 inner.register_scope(scope);
3533 });
3534 }
3535}
3536
3537impl<T: fmt::Debug + Clone + 'static> fmt::Debug for MutableState<T> {
3538 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3539 self.with_inner(|inner| {
3540 inner.with_value(|value| {
3541 f.debug_struct("MutableState")
3542 .field("value", value)
3543 .finish()
3544 })
3545 })
3546 }
3547}
3548
3549#[derive(Clone)]
3550pub struct SnapshotStateList<T: Clone + 'static> {
3551 state: OwnedMutableState<Vec<T>>,
3552}
3553
3554impl<T: Clone + 'static> SnapshotStateList<T> {
3555 pub fn with_runtime<I>(values: I, runtime: RuntimeHandle) -> Self
3556 where
3557 I: IntoIterator<Item = T>,
3558 {
3559 let initial: Vec<T> = values.into_iter().collect();
3560 Self {
3561 state: OwnedMutableState::with_runtime(initial, runtime),
3562 }
3563 }
3564
3565 pub fn as_state(&self) -> State<Vec<T>> {
3566 self.state.as_state()
3567 }
3568
3569 pub fn as_mutable_state(&self) -> MutableState<Vec<T>> {
3570 self.state.handle()
3571 }
3572
3573 pub fn len(&self) -> usize {
3574 self.state.with(|values| values.len())
3575 }
3576
3577 pub fn is_empty(&self) -> bool {
3578 self.len() == 0
3579 }
3580
3581 pub fn to_vec(&self) -> Vec<T> {
3582 self.state.with(|values| values.clone())
3583 }
3584
3585 pub fn iter(&self) -> Vec<T> {
3586 self.to_vec()
3587 }
3588
3589 pub fn get(&self, index: usize) -> T {
3590 self.state.with(|values| values[index].clone())
3591 }
3592
3593 pub fn get_opt(&self, index: usize) -> Option<T> {
3594 self.state.with(|values| values.get(index).cloned())
3595 }
3596
3597 pub fn first(&self) -> Option<T> {
3598 self.get_opt(0)
3599 }
3600
3601 pub fn last(&self) -> Option<T> {
3602 self.state.with(|values| values.last().cloned())
3603 }
3604
3605 pub fn push(&self, value: T) {
3606 self.state.update(|values| values.push(value));
3607 }
3608
3609 pub fn extend<I>(&self, iter: I)
3610 where
3611 I: IntoIterator<Item = T>,
3612 {
3613 self.state.update(|values| values.extend(iter));
3614 }
3615
3616 pub fn insert(&self, index: usize, value: T) {
3617 self.state.update(|values| values.insert(index, value));
3618 }
3619
3620 pub fn set(&self, index: usize, value: T) -> T {
3621 self.state
3622 .update(|values| std::mem::replace(&mut values[index], value))
3623 }
3624
3625 pub fn remove(&self, index: usize) -> T {
3626 self.state.update(|values| values.remove(index))
3627 }
3628
3629 pub fn pop(&self) -> Option<T> {
3630 self.state.update(|values| values.pop())
3631 }
3632
3633 pub fn clear(&self) {
3634 self.state.replace(Vec::new());
3635 }
3636
3637 pub fn retain<F>(&self, mut predicate: F)
3638 where
3639 F: FnMut(&T) -> bool,
3640 {
3641 self.state
3642 .update(|values| values.retain(|value| predicate(value)));
3643 }
3644
3645 pub fn replace_with<I>(&self, iter: I)
3646 where
3647 I: IntoIterator<Item = T>,
3648 {
3649 self.state.replace(iter.into_iter().collect());
3650 }
3651}
3652
3653impl<T: fmt::Debug + Clone + 'static> fmt::Debug for SnapshotStateList<T> {
3654 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3655 let contents = self.to_vec();
3656 f.debug_struct("SnapshotStateList")
3657 .field("values", &contents)
3658 .finish()
3659 }
3660}
3661
3662#[derive(Clone)]
3663pub struct SnapshotStateMap<K, V>
3664where
3665 K: Clone + Eq + Hash + 'static,
3666 V: Clone + 'static,
3667{
3668 state: OwnedMutableState<HashMap<K, V>>,
3669}
3670
3671impl<K, V> SnapshotStateMap<K, V>
3672where
3673 K: Clone + Eq + Hash + 'static,
3674 V: Clone + 'static,
3675{
3676 pub fn with_runtime<I>(pairs: I, runtime: RuntimeHandle) -> Self
3677 where
3678 I: IntoIterator<Item = (K, V)>,
3679 {
3680 let map: HashMap<K, V> = pairs.into_iter().collect();
3681 Self {
3682 state: OwnedMutableState::with_runtime(map, runtime),
3683 }
3684 }
3685
3686 pub fn as_state(&self) -> State<HashMap<K, V>> {
3687 self.state.as_state()
3688 }
3689
3690 pub fn as_mutable_state(&self) -> MutableState<HashMap<K, V>> {
3691 self.state.handle()
3692 }
3693
3694 pub fn len(&self) -> usize {
3695 self.state.with(|map| map.len())
3696 }
3697
3698 pub fn is_empty(&self) -> bool {
3699 self.state.with(|map| map.is_empty())
3700 }
3701
3702 pub fn contains_key(&self, key: &K) -> bool {
3703 self.state.with(|map| map.contains_key(key))
3704 }
3705
3706 pub fn get(&self, key: &K) -> Option<V> {
3707 self.state.with(|map| map.get(key).cloned())
3708 }
3709
3710 pub fn to_hash_map(&self) -> HashMap<K, V> {
3711 self.state.with(|map| map.clone())
3712 }
3713
3714 pub fn insert(&self, key: K, value: V) -> Option<V> {
3715 self.state.update(|map| map.insert(key, value))
3716 }
3717
3718 pub fn extend<I>(&self, iter: I)
3719 where
3720 I: IntoIterator<Item = (K, V)>,
3721 {
3722 self.state.update(|map| map.extend(iter));
3723 }
3725
3726 pub fn remove(&self, key: &K) -> Option<V> {
3727 self.state.update(|map| map.remove(key))
3728 }
3729
3730 pub fn clear(&self) {
3731 self.state.replace(HashMap::default());
3732 }
3733
3734 pub fn retain<F>(&self, mut predicate: F)
3735 where
3736 F: FnMut(&K, &mut V) -> bool,
3737 {
3738 self.state.update(|map| map.retain(|k, v| predicate(k, v)));
3739 }
3740}
3741
3742impl<K, V> fmt::Debug for SnapshotStateMap<K, V>
3743where
3744 K: Clone + Eq + Hash + fmt::Debug + 'static,
3745 V: Clone + fmt::Debug + 'static,
3746{
3747 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3748 let contents = self.to_hash_map();
3749 f.debug_struct("SnapshotStateMap")
3750 .field("entries", &contents)
3751 .finish()
3752 }
3753}
3754
3755struct DerivedState<T: Clone + 'static> {
3756 compute: Rc<dyn Fn() -> T>, state: OwnedMutableState<T>,
3758}
3759
3760impl<T: Clone + 'static> DerivedState<T> {
3761 fn new(runtime: RuntimeHandle, compute: Rc<dyn Fn() -> T>) -> Self {
3762 let initial = compute();
3764 Self {
3765 compute,
3766 state: OwnedMutableState::with_runtime(initial, runtime),
3767 }
3768 }
3769
3770 fn set_compute(&mut self, compute: Rc<dyn Fn() -> T>) {
3771 self.compute = compute;
3773 }
3774
3775 fn recompute(&self) {
3776 let value = (self.compute)();
3777 self.state.set_value(value);
3778 }
3779}
3780
3781impl<T: fmt::Debug + Clone + 'static> fmt::Debug for State<T> {
3782 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3783 self.with_inner(|inner| {
3784 inner.with_value(|value| f.debug_struct("State").field("value", value).finish())
3785 })
3786 }
3787}
3788
3789pub struct ParamState<T> {
3790 value: Option<T>,
3791}
3792
3793impl<T> ParamState<T> {
3794 pub fn update(&mut self, new_value: &T) -> bool
3795 where
3796 T: PartialEq + Clone,
3797 {
3798 match &self.value {
3799 Some(old) if old == new_value => false,
3800 _ => {
3801 self.value = Some(new_value.clone());
3802 true
3803 }
3804 }
3805 }
3806
3807 pub fn value(&self) -> Option<T>
3808 where
3809 T: Clone,
3810 {
3811 self.value.clone()
3812 }
3813}
3814
3815pub struct ParamSlot<T> {
3818 val: RefCell<Option<T>>,
3819}
3820
3821impl<T> Default for ParamSlot<T> {
3822 fn default() -> Self {
3823 Self {
3824 val: RefCell::new(None),
3825 }
3826 }
3827}
3828
3829impl<T> ParamSlot<T> {
3830 pub fn set(&self, v: T) {
3831 *self.val.borrow_mut() = Some(v);
3832 }
3833
3834 pub fn take(&self) -> T {
3836 self.val
3837 .borrow_mut()
3838 .take()
3839 .expect("ParamSlot take() called before set")
3840 }
3841}
3842
3843#[derive(Clone)]
3847pub struct CallbackHolder {
3848 rc: Rc<RefCell<Box<dyn FnMut()>>>,
3849}
3850
3851impl CallbackHolder {
3852 pub fn new() -> Self {
3854 Self::default()
3855 }
3856
3857 pub fn update<F>(&self, f: F)
3859 where
3860 F: FnMut() + 'static,
3861 {
3862 *self.rc.borrow_mut() = Box::new(f);
3863 }
3864
3865 pub fn clone_rc(&self) -> impl Fn() + 'static {
3867 let rc = self.rc.clone();
3868 move || {
3869 (rc.borrow_mut())();
3870 }
3871 }
3872}
3873
3874impl Default for CallbackHolder {
3875 fn default() -> Self {
3876 Self {
3877 rc: Rc::new(RefCell::new(Box::new(|| {}) as Box<dyn FnMut()>)),
3878 }
3879 }
3880}
3881
3882#[derive(Clone)]
3885pub struct CallbackHolder1<A: 'static> {
3886 #[allow(clippy::type_complexity)]
3887 rc: Rc<RefCell<Box<dyn FnMut(A)>>>,
3888}
3889
3890impl<A: 'static> CallbackHolder1<A> {
3891 pub fn new() -> Self {
3893 Self::default()
3894 }
3895
3896 pub fn update<F>(&self, f: F)
3898 where
3899 F: FnMut(A) + 'static,
3900 {
3901 *self.rc.borrow_mut() = Box::new(f);
3902 }
3903
3904 pub fn clone_rc(&self) -> impl Fn(A) + 'static {
3906 let rc = self.rc.clone();
3907 move |arg| {
3908 (rc.borrow_mut())(arg);
3909 }
3910 }
3911}
3912
3913impl<A: 'static> Default for CallbackHolder1<A> {
3914 fn default() -> Self {
3915 Self {
3916 rc: Rc::new(RefCell::new(Box::new(|_| {}) as Box<dyn FnMut(A)>)),
3917 }
3918 }
3919}
3920
3921pub struct ReturnSlot<T> {
3922 value: Option<T>,
3923}
3924
3925impl<T: Clone> ReturnSlot<T> {
3926 pub fn store(&mut self, value: T) {
3927 self.value = Some(value);
3928 }
3929
3930 pub fn get(&self) -> Option<T> {
3931 self.value.clone()
3932 }
3933}
3934
3935impl<T> Default for ParamState<T> {
3936 fn default() -> Self {
3937 Self { value: None }
3938 }
3939}
3940
3941impl<T> Default for ReturnSlot<T> {
3942 fn default() -> Self {
3943 Self { value: None }
3944 }
3945}
3946
3947pub struct Composition<A: Applier + 'static> {
3948 slots: Rc<SlotsHost>,
3949 applier: Rc<ConcreteApplierHost<A>>,
3950 runtime: Runtime,
3951 observer: SnapshotStateObserver,
3952 root: Option<NodeId>,
3953}
3954
3955impl<A: Applier + 'static> Composition<A> {
3956 pub fn new(applier: A) -> Self {
3957 Self::with_runtime(applier, Runtime::new(Arc::new(DefaultScheduler)))
3958 }
3959
3960 pub fn with_runtime(applier: A, runtime: Runtime) -> Self {
3961 Self::with_backend(applier, runtime, SlotBackendKind::default())
3962 }
3963
3964 pub fn with_backend(applier: A, runtime: Runtime, backend_kind: SlotBackendKind) -> Self {
3965 let storage = make_backend(backend_kind);
3966 let slots = Rc::new(SlotsHost::new(storage));
3967 let applier = Rc::new(ConcreteApplierHost::new(applier));
3968 let observer_handle = runtime.handle();
3969 let observer = SnapshotStateObserver::new(move |callback| {
3970 observer_handle.enqueue_ui_task(callback);
3971 });
3972 observer.start();
3973 Self {
3974 slots,
3975 applier,
3976 runtime,
3977 observer,
3978 root: None,
3979 }
3980 }
3981
3982 fn slots_host(&self) -> Rc<SlotsHost> {
3983 Rc::clone(&self.slots)
3984 }
3985
3986 fn applier_host(&self) -> Rc<dyn ApplierHost> {
3987 self.applier.clone()
3988 }
3989
3990 pub fn render(&mut self, key: Key, mut content: impl FnMut()) -> Result<(), NodeError> {
3991 self.slots.borrow_mut().reset();
3992 let runtime_handle = self.runtime_handle();
3993 runtime_handle.drain_ui();
3994 let composer = Composer::new(
3995 Rc::clone(&self.slots),
3996 self.applier.clone(),
3997 runtime_handle.clone(),
3998 self.observer.clone(),
3999 self.root,
4000 );
4001 self.observer.begin_frame();
4002 let (root, mut commands, side_effects) = composer.install(|composer| {
4003 composer.with_group(key, |_| content());
4004 let root = composer.root();
4005 let commands = composer.take_commands();
4006 let side_effects = composer.take_side_effects();
4007 (root, commands, side_effects)
4008 });
4009
4010 {
4011 let mut applier = self.applier.borrow_dyn();
4012 for command in commands.drain(..) {
4013 command.apply(&mut *applier)?;
4014 }
4015 for update in runtime_handle.take_updates() {
4016 update.apply(&mut *applier)?;
4017 }
4018 }
4019
4020 runtime_handle.drain_ui();
4021 for effect in side_effects {
4022 effect();
4023 }
4024 runtime_handle.drain_ui();
4025 self.root = root;
4026 {
4027 let mut slots = self.slots.borrow_mut();
4028 let _ = slots.finalize_current_group();
4029 slots.flush();
4030 }
4031 let _ = self.process_invalid_scopes()?;
4032 if !self.runtime.has_updates()
4033 && !runtime_handle.has_invalid_scopes()
4034 && !runtime_handle.has_frame_callbacks()
4035 && !runtime_handle.has_pending_ui()
4036 {
4037 self.runtime.set_needs_frame(false);
4038 }
4039 Ok(())
4040 }
4041
4042 pub fn should_render(&self) -> bool {
4051 self.runtime.needs_frame() || self.runtime.has_updates()
4052 }
4053
4054 pub fn runtime_handle(&self) -> RuntimeHandle {
4055 self.runtime.handle()
4056 }
4057
4058 pub fn applier_mut(&mut self) -> ApplierGuard<'_, A> {
4059 ApplierGuard::new(self.applier.borrow_typed())
4060 }
4061
4062 pub fn root(&self) -> Option<NodeId> {
4063 self.root
4064 }
4065
4066 pub fn debug_dump_slot_table_groups(&self) -> Vec<(usize, Key, Option<ScopeId>, usize)> {
4067 self.slots.borrow().debug_dump_groups()
4068 }
4069
4070 pub fn debug_dump_all_slots(&self) -> Vec<(usize, String)> {
4071 self.slots.borrow().debug_dump_all_slots()
4072 }
4073
4074 pub fn process_invalid_scopes(&mut self) -> Result<bool, NodeError> {
4075 let runtime_handle = self.runtime_handle();
4076 let mut did_recompose = false;
4077 let mut loop_count = 0;
4078 loop {
4079 loop_count += 1;
4080 if loop_count > 100 {
4081 log::error!("process_invalid_scopes looped too many times! Breaking loop to prevent freeze.");
4082 break;
4083 }
4084 runtime_handle.drain_ui();
4085 let pending = runtime_handle.take_invalidated_scopes();
4086 if pending.is_empty() {
4087 break;
4088 }
4089 if input_debug_enabled() {
4090 let pending_ids: Vec<_> = pending.iter().map(|(id, _)| *id).collect();
4091 eprintln!(
4092 "[CRANPOSE_INPUT_DEBUG] process_invalid_scopes pending_ids={:?}",
4093 pending_ids
4094 );
4095 }
4096 let mut scopes = Vec::new();
4097 for (id, weak) in pending {
4098 if let Some(inner) = weak.upgrade() {
4099 scopes.push(RecomposeScope { inner });
4100 } else {
4101 runtime_handle.mark_scope_recomposed(id);
4102 }
4103 }
4104 if scopes.is_empty() {
4105 continue;
4106 }
4107 if input_debug_enabled() {
4108 let scope_ids: Vec<_> = scopes.iter().map(|scope| scope.id()).collect();
4109 eprintln!(
4110 "[CRANPOSE_INPUT_DEBUG] process_invalid_scopes live_scope_ids={:?}",
4111 scope_ids
4112 );
4113 }
4114 did_recompose = true;
4115 let runtime_clone = runtime_handle.clone();
4116 let root_host = self.slots_host();
4117 let mut scope_groups: Vec<(Rc<SlotsHost>, Vec<RecomposeScope>)> = Vec::new();
4118 let mut scope_group_index: HashMap<usize, usize> = HashMap::default();
4119 for scope in scopes {
4120 let host = scope.slots_host().unwrap_or_else(|| Rc::clone(&root_host));
4121 let host_key = Rc::as_ptr(&host) as usize;
4122 if let Some(index) = scope_group_index.get(&host_key).copied() {
4123 scope_groups[index].1.push(scope);
4124 } else {
4125 scope_group_index.insert(host_key, scope_groups.len());
4126 scope_groups.push((host, vec![scope]));
4127 }
4128 }
4129 let (mut commands, side_effects) = {
4130 let composer = Composer::new(
4131 Rc::clone(&root_host),
4132 self.applier_host(),
4133 runtime_clone,
4134 self.observer.clone(),
4135 self.root,
4136 );
4137 self.observer.begin_frame();
4138 composer.install(|composer| {
4139 for (host, scopes) in scope_groups.into_iter() {
4140 if Rc::ptr_eq(&host, &root_host) {
4141 for scope in scopes.iter() {
4142 composer.recranpose_group(scope);
4143 }
4144 } else {
4145 composer.with_slot_override(host, |composer| {
4146 for scope in scopes.iter() {
4147 composer.recranpose_group(scope);
4148 }
4149 });
4150 }
4151 }
4152 let commands = composer.take_commands();
4153 let side_effects = composer.take_side_effects();
4154 (commands, side_effects)
4155 })
4156 };
4157 {
4158 let mut applier = self.applier.borrow_dyn();
4159 for command in commands.drain(..) {
4160 command.apply(&mut *applier)?;
4161 }
4162 for update in runtime_handle.take_updates() {
4163 update.apply(&mut *applier)?;
4164 }
4165 }
4166 for effect in side_effects {
4167 effect();
4168 }
4169 runtime_handle.drain_ui();
4170 }
4171 if !self.runtime.has_updates()
4172 && !runtime_handle.has_invalid_scopes()
4173 && !runtime_handle.has_frame_callbacks()
4174 && !runtime_handle.has_pending_ui()
4175 {
4176 self.runtime.set_needs_frame(false);
4177 }
4178 Ok(did_recompose)
4179 }
4180
4181 pub fn flush_pending_node_updates(&mut self) -> Result<(), NodeError> {
4182 let updates = self.runtime_handle().take_updates();
4183 let mut applier = self.applier.borrow_dyn();
4184 for update in updates {
4185 update.apply(&mut *applier)?;
4186 }
4187 Ok(())
4188 }
4189}
4190
4191impl<A: Applier + 'static> Drop for Composition<A> {
4192 fn drop(&mut self) {
4193 self.observer.stop();
4194 }
4195}
4196pub fn location_key(file: &str, line: u32, column: u32) -> Key {
4197 let base = file.as_ptr() as u64;
4198 base
4199 .wrapping_mul(0x9E37_79B9_7F4A_7C15) ^ ((line as u64) << 32)
4201 ^ (column as u64)
4202}
4203
4204fn hash_key<K: Hash>(key: &K) -> Key {
4205 let mut hasher = hash::default::new();
4206 key.hash(&mut hasher);
4207 hasher.finish()
4208}
4209
4210#[cfg(test)]
4211#[path = "tests/lib_tests.rs"]
4212mod tests;
4213
4214#[cfg(test)]
4215#[path = "tests/recursive_decrease_increase_test.rs"]
4216mod recursive_decrease_increase_test;
4217
4218#[cfg(test)]
4219#[path = "tests/slot_backend_tests.rs"]
4220mod slot_backend_tests;
4221
4222pub mod collections;
4223pub mod hash;