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_measure_dirty_in_composer(node_id: NodeId) {
1177 with_current_composer(|composer| {
1178 composer.commands_mut().push(Command::BubbleDirty {
1179 node_id,
1180 bubble: DirtyBubble {
1181 layout: false,
1182 measure: true,
1183 semantics: false,
1184 },
1185 });
1186 });
1187}
1188
1189pub fn bubble_semantics_dirty_in_composer<N: Node + 'static>(node_id: NodeId) {
1196 bubble_semantics_dirty_composer::<N>(node_id);
1197}
1198
1199fn bubble_layout_dirty_applier(applier: &mut dyn Applier, mut node_id: NodeId) {
1201 if let Ok(node) = applier.get_mut(node_id) {
1204 node.mark_needs_layout();
1205 }
1206
1207 loop {
1209 let parent_id = match applier.get_mut(node_id) {
1211 Ok(node) => node.parent(),
1212 Err(_) => None,
1213 };
1214
1215 match parent_id {
1216 Some(pid) => {
1217 if let Ok(parent) = applier.get_mut(pid) {
1219 if !parent.needs_layout() {
1220 parent.mark_needs_layout();
1221 node_id = pid; } else {
1223 break; }
1225 } else {
1226 break;
1227 }
1228 }
1229 None => break, }
1231 }
1232}
1233
1234fn bubble_measure_dirty_applier(applier: &mut dyn Applier, mut node_id: NodeId) {
1236 if let Ok(node) = applier.get_mut(node_id) {
1238 node.mark_needs_measure();
1239 }
1240
1241 loop {
1243 let parent_id = match applier.get_mut(node_id) {
1245 Ok(node) => node.parent(),
1246 Err(_) => None,
1247 };
1248
1249 match parent_id {
1250 Some(pid) => {
1251 if let Ok(parent) = applier.get_mut(pid) {
1253 if !parent.needs_measure() {
1254 parent.mark_needs_measure();
1255 node_id = pid; } else {
1257 break; }
1259 } else {
1260 break;
1261 }
1262 }
1263 None => {
1264 break; }
1266 }
1267 }
1268}
1269
1270fn bubble_semantics_dirty_applier(applier: &mut dyn Applier, mut node_id: NodeId) {
1272 if let Ok(node) = applier.get_mut(node_id) {
1273 node.mark_needs_semantics();
1274 }
1275
1276 loop {
1277 let parent_id = match applier.get_mut(node_id) {
1278 Ok(node) => node.parent(),
1279 Err(_) => None,
1280 };
1281
1282 match parent_id {
1283 Some(pid) => {
1284 if let Ok(parent) = applier.get_mut(pid) {
1285 if !parent.needs_semantics() {
1286 parent.mark_needs_semantics();
1287 node_id = pid;
1288 } else {
1289 break;
1290 }
1291 } else {
1292 break;
1293 }
1294 }
1295 None => break,
1296 }
1297 }
1298}
1299
1300fn bubble_layout_dirty_composer<N: Node + 'static>(mut node_id: NodeId) {
1304 let _ = with_node_mut(node_id, |node: &mut N| {
1306 node.mark_needs_layout();
1307 });
1308
1309 while let Ok(Some(pid)) = with_node_mut(node_id, |node: &mut N| node.parent()) {
1311 let parent_id = pid;
1312
1313 let should_continue = with_node_mut(parent_id, |node: &mut N| {
1315 if !node.needs_layout() {
1316 node.mark_needs_layout();
1317 true } else {
1319 false }
1321 })
1322 .unwrap_or(false);
1323
1324 if should_continue {
1325 node_id = parent_id;
1326 } else {
1327 break;
1328 }
1329 }
1330}
1331
1332fn bubble_semantics_dirty_composer<N: Node + 'static>(mut node_id: NodeId) {
1334 let _ = with_node_mut(node_id, |node: &mut N| {
1336 node.mark_needs_semantics();
1337 });
1338
1339 while let Ok(Some(pid)) = with_node_mut(node_id, |node: &mut N| node.parent()) {
1340 let parent_id = pid;
1341
1342 let should_continue = with_node_mut(parent_id, |node: &mut N| {
1343 if !node.needs_semantics() {
1344 node.mark_needs_semantics();
1345 true
1346 } else {
1347 false
1348 }
1349 })
1350 .unwrap_or(false);
1351
1352 if should_continue {
1353 node_id = parent_id;
1354 } else {
1355 break;
1356 }
1357 }
1358}
1359
1360impl dyn Node {
1361 pub fn as_any_mut(&mut self) -> &mut dyn Any {
1362 self
1363 }
1364}
1365
1366pub trait Applier: Any {
1367 fn create(&mut self, node: Box<dyn Node>) -> NodeId;
1368 fn get_mut(&mut self, id: NodeId) -> Result<&mut dyn Node, NodeError>;
1369 fn remove(&mut self, id: NodeId) -> Result<(), NodeError>;
1370
1371 fn insert_with_id(&mut self, id: NodeId, node: Box<dyn Node>) -> Result<(), NodeError>;
1379
1380 fn as_any(&self) -> &dyn Any
1381 where
1382 Self: Sized,
1383 {
1384 self
1385 }
1386
1387 fn as_any_mut(&mut self) -> &mut dyn Any
1388 where
1389 Self: Sized,
1390 {
1391 self
1392 }
1393}
1394
1395type TypedNodeUpdate = fn(&mut dyn Node, NodeId) -> Result<(), NodeError>;
1396type CommandCallback = Box<dyn FnOnce(&mut dyn Applier) -> Result<(), NodeError> + 'static>;
1397
1398#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1399pub(crate) struct DirtyBubble {
1400 layout: bool,
1401 measure: bool,
1402 semantics: bool,
1403}
1404
1405impl DirtyBubble {
1406 pub(crate) const LAYOUT_AND_MEASURE: Self = Self {
1407 layout: true,
1408 measure: true,
1409 semantics: false,
1410 };
1411
1412 pub(crate) const SEMANTICS: Self = Self {
1413 layout: false,
1414 measure: false,
1415 semantics: true,
1416 };
1417
1418 fn apply(self, applier: &mut dyn Applier, node_id: NodeId) {
1419 if self.layout {
1420 bubble_layout_dirty(applier, node_id);
1421 }
1422 if self.measure {
1423 bubble_measure_dirty(applier, node_id);
1424 }
1425 if self.semantics {
1426 bubble_semantics_dirty(applier, node_id);
1427 }
1428 }
1429}
1430
1431pub(crate) enum Command {
1432 BubbleDirty {
1433 node_id: NodeId,
1434 bubble: DirtyBubble,
1435 },
1436 UpdateTypedNode {
1437 id: NodeId,
1438 updater: TypedNodeUpdate,
1439 },
1440 RemoveNode {
1441 id: NodeId,
1442 },
1443 MountNode {
1444 id: NodeId,
1445 },
1446 AttachChild {
1447 parent_id: NodeId,
1448 child_id: NodeId,
1449 bubble: DirtyBubble,
1450 },
1451 InsertChild {
1452 parent_id: NodeId,
1453 child_id: NodeId,
1454 appended_index: usize,
1455 insert_index: usize,
1456 bubble: DirtyBubble,
1457 },
1458 MoveChild {
1459 parent_id: NodeId,
1460 from_index: usize,
1461 to_index: usize,
1462 bubble: DirtyBubble,
1463 },
1464 RemoveChild {
1465 parent_id: NodeId,
1466 child_id: NodeId,
1467 },
1468 ReconcileChildren {
1469 parent_id: NodeId,
1470 expected_children: Vec<NodeId>,
1471 needs_dirty_check: bool,
1472 },
1473 Callback(CommandCallback),
1474}
1475
1476impl Command {
1477 pub(crate) fn update_node<N: Node + 'static>(id: NodeId) -> Self {
1478 Self::UpdateTypedNode {
1479 id,
1480 updater: update_typed_node::<N>,
1481 }
1482 }
1483
1484 pub(crate) fn callback(
1485 callback: impl FnOnce(&mut dyn Applier) -> Result<(), NodeError> + 'static,
1486 ) -> Self {
1487 Self::Callback(Box::new(callback))
1488 }
1489
1490 pub(crate) fn apply(self, applier: &mut dyn Applier) -> Result<(), NodeError> {
1491 match self {
1492 Self::BubbleDirty { node_id, bubble } => {
1493 bubble.apply(applier, node_id);
1494 Ok(())
1495 }
1496 Self::UpdateTypedNode { id, updater } => {
1497 let node = match applier.get_mut(id) {
1498 Ok(node) => node,
1499 Err(NodeError::Missing { .. }) => return Ok(()),
1500 Err(err) => return Err(err),
1501 };
1502 updater(node, id)
1503 }
1504 Self::RemoveNode { id } => {
1505 if let Ok(node) = applier.get_mut(id) {
1506 node.unmount();
1507 }
1508 match applier.remove(id) {
1509 Ok(()) | Err(NodeError::Missing { .. }) => Ok(()),
1510 Err(err) => Err(err),
1511 }
1512 }
1513 Self::MountNode { id } => {
1514 let node = match applier.get_mut(id) {
1515 Ok(node) => node,
1516 Err(NodeError::Missing { .. }) => return Ok(()),
1517 Err(err) => return Err(err),
1518 };
1519 node.set_node_id(id);
1520 node.mount();
1521 Ok(())
1522 }
1523 Self::AttachChild {
1524 parent_id,
1525 child_id,
1526 bubble,
1527 } => {
1528 insert_child_with_reparenting(applier, parent_id, child_id);
1529 bubble.apply(applier, parent_id);
1530 Ok(())
1531 }
1532 Self::InsertChild {
1533 parent_id,
1534 child_id,
1535 appended_index,
1536 insert_index,
1537 bubble,
1538 } => {
1539 insert_child_with_reparenting(applier, parent_id, child_id);
1540 bubble.apply(applier, parent_id);
1541 if insert_index != appended_index {
1542 if let Ok(parent_node) = applier.get_mut(parent_id) {
1543 parent_node.move_child(appended_index, insert_index);
1544 }
1545 }
1546 Ok(())
1547 }
1548 Self::MoveChild {
1549 parent_id,
1550 from_index,
1551 to_index,
1552 bubble,
1553 } => {
1554 if let Ok(parent_node) = applier.get_mut(parent_id) {
1555 parent_node.move_child(from_index, to_index);
1556 }
1557 bubble.apply(applier, parent_id);
1558 Ok(())
1559 }
1560 Self::RemoveChild {
1561 parent_id,
1562 child_id,
1563 } => apply_remove_child(applier, parent_id, child_id),
1564 Self::ReconcileChildren {
1565 parent_id,
1566 expected_children,
1567 needs_dirty_check,
1568 } => reconcile_children(applier, parent_id, &expected_children, needs_dirty_check),
1569 Self::Callback(callback) => callback(applier),
1570 }
1571 }
1572}
1573
1574fn update_typed_node<N: Node + 'static>(node: &mut dyn Node, id: NodeId) -> Result<(), NodeError> {
1575 let typed = node
1576 .as_any_mut()
1577 .downcast_mut::<N>()
1578 .ok_or(NodeError::TypeMismatch {
1579 id,
1580 expected: std::any::type_name::<N>(),
1581 })?;
1582 typed.update();
1583 Ok(())
1584}
1585
1586fn insert_child_with_reparenting(applier: &mut dyn Applier, parent_id: NodeId, child_id: NodeId) {
1587 let old_parent = applier
1588 .get_mut(child_id)
1589 .ok()
1590 .and_then(|node| node.parent());
1591 if let Some(old_parent_id) = old_parent {
1592 if old_parent_id != parent_id {
1593 if let Ok(old_parent_node) = applier.get_mut(old_parent_id) {
1594 old_parent_node.remove_child(child_id);
1595 }
1596 if let Ok(child_node) = applier.get_mut(child_id) {
1597 child_node.on_removed_from_parent();
1598 }
1599 bubble_layout_dirty(applier, old_parent_id);
1600 bubble_measure_dirty(applier, old_parent_id);
1601 }
1602 }
1603
1604 if let Ok(parent_node) = applier.get_mut(parent_id) {
1605 parent_node.insert_child(child_id);
1606 }
1607 if let Ok(child_node) = applier.get_mut(child_id) {
1608 child_node.on_attached_to_parent(parent_id);
1609 }
1610}
1611
1612fn apply_remove_child(
1613 applier: &mut dyn Applier,
1614 parent_id: NodeId,
1615 child_id: NodeId,
1616) -> Result<(), NodeError> {
1617 if let Ok(parent_node) = applier.get_mut(parent_id) {
1618 parent_node.remove_child(child_id);
1619 }
1620 bubble_layout_dirty(applier, parent_id);
1621 bubble_measure_dirty(applier, parent_id);
1622
1623 let should_remove = if let Ok(node) = applier.get_mut(child_id) {
1624 match node.parent() {
1625 Some(existing_parent_id) if existing_parent_id == parent_id => {
1626 node.on_removed_from_parent();
1627 node.unmount();
1628 true
1629 }
1630 None => {
1631 node.unmount();
1632 true
1633 }
1634 Some(_) => false,
1635 }
1636 } else {
1637 true
1638 };
1639
1640 if should_remove {
1641 let _ = applier.remove(child_id);
1642 }
1643 Ok(())
1644}
1645
1646fn reconcile_children(
1647 applier: &mut dyn Applier,
1648 parent_id: NodeId,
1649 expected_children: &[NodeId],
1650 needs_dirty_check: bool,
1651) -> Result<(), NodeError> {
1652 let mut repaired = false;
1653 for &child_id in expected_children {
1654 let needs_attach = if let Ok(node) = applier.get_mut(child_id) {
1655 node.parent() != Some(parent_id)
1656 } else {
1657 false
1658 };
1659
1660 if needs_attach {
1661 insert_child_with_reparenting(applier, parent_id, child_id);
1662 repaired = true;
1663 }
1664 }
1665
1666 let is_dirty = if needs_dirty_check {
1667 if let Ok(node) = applier.get_mut(parent_id) {
1668 node.needs_layout()
1669 } else {
1670 false
1671 }
1672 } else {
1673 false
1674 };
1675
1676 if repaired {
1677 bubble_layout_dirty(applier, parent_id);
1678 bubble_measure_dirty(applier, parent_id);
1679 } else if is_dirty {
1680 bubble_layout_dirty(applier, parent_id);
1681 }
1682
1683 Ok(())
1684}
1685
1686#[derive(Default)]
1687pub struct MemoryApplier {
1688 nodes: Vec<Option<Box<dyn Node>>>, high_id_nodes: std::collections::HashMap<NodeId, Box<dyn Node>>,
1692 layout_runtime: Option<RuntimeHandle>,
1693 slots: SlotBackend,
1694}
1695
1696impl MemoryApplier {
1697 pub fn new() -> Self {
1698 Self {
1699 nodes: Vec::new(),
1700 high_id_nodes: std::collections::HashMap::new(),
1701 layout_runtime: None,
1702 slots: SlotBackend::default(),
1703 }
1704 }
1705
1706 pub fn slots(&mut self) -> &mut SlotBackend {
1707 &mut self.slots
1708 }
1709
1710 pub fn with_node<N: Node + 'static, R>(
1711 &mut self,
1712 id: NodeId,
1713 f: impl FnOnce(&mut N) -> R,
1714 ) -> Result<R, NodeError> {
1715 let slot = self
1716 .nodes
1717 .get_mut(id)
1718 .ok_or(NodeError::Missing { id })?
1719 .as_deref_mut()
1720 .ok_or(NodeError::Missing { id })?;
1721 let typed = slot
1722 .as_any_mut()
1723 .downcast_mut::<N>()
1724 .ok_or(NodeError::TypeMismatch {
1725 id,
1726 expected: std::any::type_name::<N>(),
1727 })?;
1728 Ok(f(typed))
1729 }
1730
1731 pub fn len(&self) -> usize {
1732 self.nodes.iter().filter(|n| n.is_some()).count()
1733 }
1734
1735 pub fn is_empty(&self) -> bool {
1736 self.len() == 0
1737 }
1738
1739 pub fn set_runtime_handle(&mut self, handle: RuntimeHandle) {
1740 self.layout_runtime = Some(handle);
1741 }
1742
1743 pub fn clear_runtime_handle(&mut self) {
1744 self.layout_runtime = None;
1745 }
1746
1747 pub fn runtime_handle(&self) -> Option<RuntimeHandle> {
1748 self.layout_runtime.clone()
1749 }
1750
1751 pub fn dump_tree(&self, root: Option<NodeId>) -> String {
1752 let mut output = String::new();
1753 if let Some(root_id) = root {
1754 self.dump_node(&mut output, root_id, 0);
1755 } else {
1756 output.push_str("(no root)\n");
1757 }
1758 output
1759 }
1760
1761 fn dump_node(&self, output: &mut String, id: NodeId, depth: usize) {
1762 let indent = " ".repeat(depth);
1763 if let Some(Some(node)) = self.nodes.get(id) {
1764 let type_name = std::any::type_name_of_val(&**node);
1765 output.push_str(&format!("{}[{}] {}\n", indent, id, type_name));
1766
1767 let children = node.children();
1768 for child_id in children {
1769 self.dump_node(output, child_id, depth + 1);
1770 }
1771 } else {
1772 output.push_str(&format!("{}[{}] (missing)\n", indent, id));
1773 }
1774 }
1775}
1776
1777impl Applier for MemoryApplier {
1778 fn create(&mut self, node: Box<dyn Node>) -> NodeId {
1779 let id = self.nodes.len();
1780 self.nodes.push(Some(node));
1781 id
1782 }
1783
1784 fn get_mut(&mut self, id: NodeId) -> Result<&mut dyn Node, NodeError> {
1785 if id < self.nodes.len() {
1787 let slot = self.nodes[id]
1788 .as_deref_mut()
1789 .ok_or(NodeError::Missing { id })?;
1790 return Ok(slot);
1791 }
1792 self.high_id_nodes
1793 .get_mut(&id)
1794 .map(|n| n.as_mut())
1795 .ok_or(NodeError::Missing { id })
1796 }
1797
1798 fn remove(&mut self, id: NodeId) -> Result<(), NodeError> {
1799 let (children, is_high_id) = if id < self.nodes.len() {
1801 let slot = self.nodes.get(id).ok_or(NodeError::Missing { id })?;
1802 let node = slot.as_ref().ok_or(NodeError::Missing { id })?;
1803 (node.children(), false)
1804 } else if let Some(node) = self.high_id_nodes.get(&id) {
1805 (node.children(), true)
1806 } else {
1807 return Err(NodeError::Missing { id });
1808 };
1809
1810 for child_id in children {
1812 let is_owned = self
1813 .get_mut(child_id)
1814 .map(|child| child.parent() == Some(id))
1815 .unwrap_or(false);
1816 if is_owned {
1817 let _ = self.remove(child_id);
1818 }
1819 }
1820
1821 if is_high_id {
1822 self.high_id_nodes.remove(&id);
1823 } else {
1824 self.nodes[id].take();
1825 }
1826 Ok(())
1827 }
1828
1829 fn insert_with_id(&mut self, id: NodeId, node: Box<dyn Node>) -> Result<(), NodeError> {
1830 const HIGH_ID_THRESHOLD: NodeId = 1_000_000_000; if id >= HIGH_ID_THRESHOLD {
1835 if self.high_id_nodes.contains_key(&id) {
1836 return Err(NodeError::AlreadyExists { id });
1837 }
1838 self.high_id_nodes.insert(id, node);
1839 Ok(())
1840 } else {
1841 if id >= self.nodes.len() {
1843 self.nodes.resize_with(id + 1, || None);
1844 }
1845
1846 if self.nodes[id].is_some() {
1847 return Err(NodeError::AlreadyExists { id });
1848 }
1849
1850 self.nodes[id] = Some(node);
1851 Ok(())
1852 }
1853 }
1854}
1855
1856pub trait ApplierHost {
1857 fn borrow_dyn(&self) -> RefMut<'_, dyn Applier>;
1858}
1859
1860pub struct ConcreteApplierHost<A: Applier + 'static> {
1861 inner: RefCell<A>,
1862}
1863
1864impl<A: Applier + 'static> ConcreteApplierHost<A> {
1865 pub fn new(applier: A) -> Self {
1866 Self {
1867 inner: RefCell::new(applier),
1868 }
1869 }
1870
1871 pub fn borrow_typed(&self) -> RefMut<'_, A> {
1872 self.inner.borrow_mut()
1873 }
1874
1875 pub fn try_borrow_typed(&self) -> Result<RefMut<'_, A>, std::cell::BorrowMutError> {
1876 self.inner.try_borrow_mut()
1877 }
1878
1879 pub fn into_inner(self) -> A {
1880 self.inner.into_inner()
1881 }
1882}
1883
1884impl<A: Applier + 'static> ApplierHost for ConcreteApplierHost<A> {
1885 fn borrow_dyn(&self) -> RefMut<'_, dyn Applier> {
1886 RefMut::map(self.inner.borrow_mut(), |applier| {
1887 applier as &mut dyn Applier
1888 })
1889 }
1890}
1891
1892pub struct ApplierGuard<'a, A: Applier + 'static> {
1893 inner: RefMut<'a, A>,
1894}
1895
1896impl<'a, A: Applier + 'static> ApplierGuard<'a, A> {
1897 fn new(inner: RefMut<'a, A>) -> Self {
1898 Self { inner }
1899 }
1900}
1901
1902impl<'a, A: Applier + 'static> Deref for ApplierGuard<'a, A> {
1903 type Target = A;
1904
1905 fn deref(&self) -> &Self::Target {
1906 &self.inner
1907 }
1908}
1909
1910impl<'a, A: Applier + 'static> DerefMut for ApplierGuard<'a, A> {
1911 fn deref_mut(&mut self) -> &mut Self::Target {
1912 &mut self.inner
1913 }
1914}
1915
1916pub struct SlotsHost {
1917 inner: RefCell<SlotBackend>,
1918}
1919
1920impl SlotsHost {
1921 pub fn new(storage: SlotBackend) -> Self {
1922 Self {
1923 inner: RefCell::new(storage),
1924 }
1925 }
1926
1927 pub fn borrow(&self) -> Ref<'_, SlotBackend> {
1928 self.inner.borrow()
1929 }
1930
1931 pub fn borrow_mut(&self) -> RefMut<'_, SlotBackend> {
1932 self.inner.borrow_mut()
1933 }
1934
1935 pub fn take(&self) -> SlotBackend {
1936 std::mem::take(&mut *self.inner.borrow_mut())
1937 }
1938}
1939
1940pub(crate) struct ComposerCore {
1941 slots: Rc<SlotsHost>,
1942 slots_override: RefCell<Vec<Rc<SlotsHost>>>,
1943 applier: Rc<dyn ApplierHost>,
1944 runtime: RuntimeHandle,
1945 observer: SnapshotStateObserver,
1946 parent_stack: RefCell<Vec<ParentFrame>>,
1947 subcompose_stack: RefCell<Vec<SubcomposeFrame>>,
1948 root: Cell<Option<NodeId>>,
1949 commands: RefCell<Vec<Command>>,
1950 scope_stack: RefCell<Vec<RecomposeScope>>,
1951 local_stack: RefCell<LocalStackSnapshot>,
1952 side_effects: RefCell<Vec<Box<dyn FnOnce()>>>,
1953 pending_scope_options: RefCell<Option<RecomposeOptions>>,
1954 phase: Cell<Phase>,
1955 last_node_reused: Cell<Option<bool>>,
1956 recranpose_parent_hint: Cell<Option<NodeId>>,
1957 _not_send: PhantomData<*const ()>,
1958}
1959
1960impl ComposerCore {
1961 pub fn new(
1962 slots: Rc<SlotsHost>,
1963 applier: Rc<dyn ApplierHost>,
1964 runtime: RuntimeHandle,
1965 observer: SnapshotStateObserver,
1966 root: Option<NodeId>,
1967 ) -> Self {
1968 let parent_stack = if let Some(root_id) = root {
1974 vec![ParentFrame {
1975 id: root_id,
1976 remembered: Owned::new(ParentChildren::default()),
1977 previous: Vec::new(),
1978 new_children: Vec::new(),
1979 }]
1980 } else {
1981 Vec::new()
1982 };
1983
1984 Self {
1985 slots,
1986 slots_override: RefCell::new(Vec::new()),
1987 applier,
1988 runtime,
1989 observer,
1990 parent_stack: RefCell::new(parent_stack),
1991 subcompose_stack: RefCell::new(Vec::new()),
1992 root: Cell::new(root),
1993 commands: RefCell::new(Vec::new()),
1994 scope_stack: RefCell::new(Vec::new()),
1995 local_stack: RefCell::new(Rc::new(Vec::new())),
1996 side_effects: RefCell::new(Vec::new()),
1997 pending_scope_options: RefCell::new(None),
1998 phase: Cell::new(Phase::Compose),
1999 last_node_reused: Cell::new(None),
2000 recranpose_parent_hint: Cell::new(None),
2001 _not_send: PhantomData,
2002 }
2003 }
2004}
2005
2006#[derive(Clone)]
2007pub struct Composer {
2008 core: Rc<ComposerCore>,
2009}
2010
2011impl Composer {
2012 pub fn new(
2013 slots: Rc<SlotsHost>,
2014 applier: Rc<dyn ApplierHost>,
2015 runtime: RuntimeHandle,
2016 observer: SnapshotStateObserver,
2017 root: Option<NodeId>,
2018 ) -> Self {
2019 let core = Rc::new(ComposerCore::new(slots, applier, runtime, observer, root));
2020 Self { core }
2021 }
2022
2023 pub(crate) fn from_core(core: Rc<ComposerCore>) -> Self {
2024 Self { core }
2025 }
2026
2027 pub(crate) fn clone_core(&self) -> Rc<ComposerCore> {
2028 Rc::clone(&self.core)
2029 }
2030
2031 fn observer(&self) -> SnapshotStateObserver {
2032 self.core.observer.clone()
2033 }
2034
2035 fn observe_scope<R>(&self, scope: &RecomposeScope, block: impl FnOnce() -> R) -> R {
2036 let observer = self.observer();
2037 let scope_clone = scope.clone();
2038 observer.observe_reads(scope_clone, move |scope_ref| scope_ref.invalidate(), block)
2039 }
2040
2041 fn active_slots_host(&self) -> Rc<SlotsHost> {
2042 self.core
2043 .slots_override
2044 .borrow()
2045 .last()
2046 .cloned()
2047 .unwrap_or_else(|| Rc::clone(&self.core.slots))
2048 }
2049
2050 fn with_slots<R>(&self, f: impl FnOnce(&SlotBackend) -> R) -> R {
2051 let host = self.active_slots_host();
2052 let slots = host.borrow();
2053 f(&slots)
2054 }
2055
2056 fn with_slots_mut<R>(&self, f: impl FnOnce(&mut SlotBackend) -> R) -> R {
2057 let host = self.active_slots_host();
2058 let mut slots = host.borrow_mut();
2059 f(&mut slots)
2060 }
2061
2062 fn with_slot_override<R>(&self, slots: Rc<SlotsHost>, f: impl FnOnce(&Composer) -> R) -> R {
2063 self.core.slots_override.borrow_mut().push(slots);
2064 struct Guard {
2065 core: Rc<ComposerCore>,
2066 }
2067 impl Drop for Guard {
2068 fn drop(&mut self) {
2069 self.core.slots_override.borrow_mut().pop();
2070 }
2071 }
2072 let guard = Guard {
2073 core: self.clone_core(),
2074 };
2075 let result = f(self);
2076 drop(guard);
2077 result
2078 }
2079
2080 fn parent_stack(&self) -> RefMut<'_, Vec<ParentFrame>> {
2081 self.core.parent_stack.borrow_mut()
2082 }
2083
2084 fn subcompose_stack(&self) -> RefMut<'_, Vec<SubcomposeFrame>> {
2085 self.core.subcompose_stack.borrow_mut()
2086 }
2087
2088 fn commands_mut(&self) -> RefMut<'_, Vec<Command>> {
2089 self.core.commands.borrow_mut()
2090 }
2091
2092 pub(crate) fn enqueue_semantics_invalidation(&self, id: NodeId) {
2093 self.commands_mut().push(Command::BubbleDirty {
2094 node_id: id,
2095 bubble: DirtyBubble::SEMANTICS,
2096 });
2097 }
2098
2099 fn scope_stack(&self) -> RefMut<'_, Vec<RecomposeScope>> {
2100 self.core.scope_stack.borrow_mut()
2101 }
2102
2103 fn local_stack(&self) -> RefMut<'_, LocalStackSnapshot> {
2104 self.core.local_stack.borrow_mut()
2105 }
2106
2107 fn current_local_stack(&self) -> LocalStackSnapshot {
2108 self.core.local_stack.borrow().clone()
2109 }
2110
2111 fn side_effects_mut(&self) -> RefMut<'_, Vec<Box<dyn FnOnce()>>> {
2112 self.core.side_effects.borrow_mut()
2113 }
2114
2115 fn pending_scope_options(&self) -> RefMut<'_, Option<RecomposeOptions>> {
2116 self.core.pending_scope_options.borrow_mut()
2117 }
2118
2119 fn borrow_applier(&self) -> RefMut<'_, dyn Applier> {
2120 self.core.applier.borrow_dyn()
2121 }
2122
2123 pub fn register_virtual_node(
2130 &self,
2131 node_id: NodeId,
2132 node: Box<dyn Node>,
2133 ) -> Result<(), NodeError> {
2134 let mut applier = self.borrow_applier();
2135 applier.insert_with_id(node_id, node)
2136 }
2137
2138 pub fn node_has_no_parent(&self, node_id: NodeId) -> bool {
2141 let mut applier = self.borrow_applier();
2142 match applier.get_mut(node_id) {
2143 Ok(node) => node.parent().is_none(),
2144 Err(_) => true, }
2146 }
2147
2148 pub fn get_node_children(&self, node_id: NodeId) -> Vec<NodeId> {
2153 let mut applier = self.borrow_applier();
2154 match applier.get_mut(node_id) {
2155 Ok(node) => node.children(),
2156 Err(_) => Vec::new(),
2157 }
2158 }
2159
2160 pub fn clear_node_children(&self, node_id: NodeId) {
2166 let mut applier = self.borrow_applier();
2167 if let Ok(node) = applier.get_mut(node_id) {
2168 node.update_children(&[]);
2170 }
2171 }
2172
2173 pub fn install<R>(&self, f: impl FnOnce(&Composer) -> R) -> R {
2174 let _composer_guard = composer_context::enter(self);
2175 runtime::push_active_runtime(&self.core.runtime);
2176 struct Guard;
2177 impl Drop for Guard {
2178 fn drop(&mut self) {
2179 runtime::pop_active_runtime();
2180 }
2181 }
2182 let guard = Guard;
2183 let result = f(self);
2184 drop(guard);
2185 result
2186 }
2187
2188 pub fn with_group<R>(&self, key: Key, f: impl FnOnce(&Composer) -> R) -> R {
2189 let (group, scope_ref, restored_from_gap) = self.with_slots_mut(|slots| {
2190 let StartGroup {
2191 group,
2192 restored_from_gap,
2193 } = slots.begin_group(key);
2194 let scope_ref = slots
2195 .remember(|| RecomposeScope::new(self.runtime_handle()))
2196 .with(|scope| scope.clone());
2197 (group, scope_ref, restored_from_gap)
2198 });
2199
2200 if restored_from_gap {
2201 scope_ref.force_recompose();
2202 }
2203
2204 if let Some(options) = self.pending_scope_options().take() {
2205 if options.force_recompose {
2206 scope_ref.force_recompose();
2207 } else if options.force_reuse {
2208 scope_ref.force_reuse();
2209 }
2210 }
2211
2212 self.with_slots_mut(|slots| {
2213 SlotStorage::set_group_scope(slots, group, scope_ref.id());
2214 });
2215
2216 let slots_host = self.active_slots_host();
2217 scope_ref.set_slots_host(Rc::downgrade(&slots_host));
2218
2219 {
2220 let mut stack = self.scope_stack();
2221 stack.push(scope_ref.clone());
2222 }
2223
2224 {
2225 let mut stack = self.subcompose_stack();
2226 if let Some(frame) = stack.last_mut() {
2227 frame.scopes.push(scope_ref.clone());
2228 }
2229 }
2230
2231 scope_ref.snapshot_locals(self.current_local_stack());
2232 {
2233 let parent_hint = self.parent_stack().last().map(|frame| frame.id);
2234 scope_ref.set_parent_hint(parent_hint);
2235 }
2236
2237 let result = self.observe_scope(&scope_ref, || f(self));
2238
2239 let trimmed = self.with_slots_mut(|slots| slots.finalize_current_group());
2240 if trimmed {
2241 scope_ref.force_recompose();
2242 }
2243
2244 {
2245 let mut stack = self.scope_stack();
2246 stack.pop();
2247 }
2248 scope_ref.mark_recomposed();
2249 self.with_slots_mut(|slots| slots.end_group());
2250 result
2251 }
2252
2253 pub fn cranpose_with_reuse<R>(
2254 &self,
2255 key: Key,
2256 options: RecomposeOptions,
2257 f: impl FnOnce(&Composer) -> R,
2258 ) -> R {
2259 self.pending_scope_options().replace(options);
2260 self.with_group(key, f)
2261 }
2262
2263 pub fn with_key<K: Hash, R>(&self, key: &K, f: impl FnOnce(&Composer) -> R) -> R {
2264 let hashed = hash_key(key);
2265 self.with_group(hashed, f)
2266 }
2267
2268 pub fn remember<T: 'static>(&self, init: impl FnOnce() -> T) -> Owned<T> {
2269 self.with_slots_mut(|slots| slots.remember(init))
2270 }
2271
2272 pub fn use_value_slot<T: 'static>(&self, init: impl FnOnce() -> T) -> usize {
2273 self.with_slots_mut(|slots| slots.alloc_value_slot(init).index())
2274 }
2275
2276 pub fn with_slot_value<T: 'static, R>(&self, idx: usize, f: impl FnOnce(&T) -> R) -> R {
2277 self.with_slots(|slots| {
2278 let value = SlotStorage::read_value(slots, ValueSlotId::new(idx));
2279 f(value)
2280 })
2281 }
2282
2283 pub fn with_slot_value_mut<T: 'static, R>(&self, idx: usize, f: impl FnOnce(&mut T) -> R) -> R {
2284 self.with_slots_mut(|slots| {
2285 let value = SlotStorage::read_value_mut(slots, ValueSlotId::new(idx));
2286 f(value)
2287 })
2288 }
2289
2290 pub fn write_slot_value<T: 'static>(&self, idx: usize, value: T) {
2291 self.with_slots_mut(|slots| slots.write_value(ValueSlotId::new(idx), value));
2292 }
2293
2294 pub fn mutable_state_of<T: Clone + 'static>(&self, initial: T) -> MutableState<T> {
2295 MutableState::with_runtime(initial, self.runtime_handle())
2296 }
2297
2298 pub fn mutable_state_list_of<T, I>(&self, values: I) -> SnapshotStateList<T>
2299 where
2300 T: Clone + 'static,
2301 I: IntoIterator<Item = T>,
2302 {
2303 SnapshotStateList::with_runtime(values, self.runtime_handle())
2304 }
2305
2306 pub fn mutable_state_map_of<K, V, I>(&self, pairs: I) -> SnapshotStateMap<K, V>
2307 where
2308 K: Clone + Eq + Hash + 'static,
2309 V: Clone + 'static,
2310 I: IntoIterator<Item = (K, V)>,
2311 {
2312 SnapshotStateMap::with_runtime(pairs, self.runtime_handle())
2313 }
2314
2315 pub fn read_composition_local<T: Clone + 'static>(&self, local: &CompositionLocal<T>) -> T {
2316 let stack = self.core.local_stack.borrow();
2317 for context in stack.iter().rev() {
2318 if let Some(entry) = context.values.get(&local.key) {
2319 let typed = entry
2320 .clone()
2321 .downcast::<LocalStateEntry<T>>()
2322 .expect("composition local type mismatch");
2323 return typed.value();
2324 }
2325 }
2326 local.default_value()
2327 }
2328
2329 pub fn read_static_composition_local<T: Clone + 'static>(
2330 &self,
2331 local: &StaticCompositionLocal<T>,
2332 ) -> T {
2333 let stack = self.core.local_stack.borrow();
2334 for context in stack.iter().rev() {
2335 if let Some(entry) = context.values.get(&local.key) {
2336 let typed = entry
2337 .clone()
2338 .downcast::<StaticLocalEntry<T>>()
2339 .expect("static composition local type mismatch");
2340 return typed.value();
2341 }
2342 }
2343 local.default_value()
2344 }
2345
2346 pub fn current_recranpose_scope(&self) -> Option<RecomposeScope> {
2347 self.core.scope_stack.borrow().last().cloned()
2348 }
2349
2350 pub fn phase(&self) -> Phase {
2351 self.core.phase.get()
2352 }
2353
2354 pub(crate) fn set_phase(&self, phase: Phase) {
2355 self.core.phase.set(phase);
2356 }
2357
2358 pub fn enter_phase(&self, phase: Phase) {
2359 self.set_phase(phase);
2360 }
2361
2362 pub(crate) fn subcompose<R>(
2363 &self,
2364 state: &mut SubcomposeState,
2365 slot_id: SlotId,
2366 content: impl FnOnce(&Composer) -> R,
2367 ) -> (R, Vec<NodeId>) {
2368 match self.phase() {
2369 Phase::Measure | Phase::Layout => {}
2370 current => panic!(
2371 "subcompose() may only be called during measure or layout; current phase: {:?}",
2372 current
2373 ),
2374 }
2375
2376 self.subcompose_stack().push(SubcomposeFrame::default());
2377 struct StackGuard {
2378 core: Rc<ComposerCore>,
2379 leaked: bool,
2380 }
2381 impl Drop for StackGuard {
2382 fn drop(&mut self) {
2383 if !self.leaked {
2384 self.core.subcompose_stack.borrow_mut().pop();
2385 }
2386 }
2387 }
2388 let mut guard = StackGuard {
2389 core: self.clone_core(),
2390 leaked: false,
2391 };
2392
2393 let slot_host = state.get_or_create_slots(slot_id);
2394 {
2395 let mut slots = slot_host.borrow_mut();
2396 slots.reset();
2397 }
2398 let result = self.with_slot_override(slot_host.clone(), |composer| {
2399 composer.with_group(slot_id.raw(), |composer| content(composer))
2401 });
2402 {
2403 let mut slots = slot_host.borrow_mut();
2404 slots.finalize_current_group();
2405 slots.flush();
2406 }
2407
2408 let frame = {
2409 let mut stack = guard.core.subcompose_stack.borrow_mut();
2410 let frame = stack.pop().expect("subcompose stack underflow");
2411 guard.leaked = true;
2412 frame
2413 };
2414 let nodes = frame.nodes;
2415 let scopes = frame.scopes;
2416 state.register_active(slot_id, &nodes, &scopes);
2417 (result, nodes)
2418 }
2419
2420 pub fn subcompose_measurement<R>(
2421 &self,
2422 state: &mut SubcomposeState,
2423 slot_id: SlotId,
2424 content: impl FnOnce(&Composer) -> R,
2425 ) -> (R, Vec<NodeId>) {
2426 let (result, nodes) = self.subcompose(state, slot_id, content);
2427
2428 let roots = nodes
2432 .into_iter()
2433 .filter(|&id| self.node_has_no_parent(id))
2434 .collect();
2435
2436 (result, roots)
2437 }
2438
2439 pub fn subcompose_in<R>(
2440 &self,
2441 slots: &Rc<SlotsHost>,
2442 root: Option<NodeId>,
2443 f: impl FnOnce(&Composer) -> R,
2444 ) -> Result<R, NodeError> {
2445 let runtime_handle = self.runtime_handle();
2446 slots.borrow_mut().reset();
2447 let phase = self.phase();
2448 let locals = self.current_local_stack();
2449 let core = Rc::new(ComposerCore::new(
2450 Rc::clone(slots),
2451 Rc::clone(&self.core.applier),
2452 runtime_handle.clone(),
2453 self.observer(),
2454 root,
2455 ));
2456 core.phase.set(phase);
2457 *core.local_stack.borrow_mut() = locals;
2458 let composer = Composer::from_core(core);
2459 let (result, mut commands, side_effects) = composer.install(|composer| {
2460 let output = f(composer);
2461 let commands = composer.take_commands();
2462 let side_effects = composer.take_side_effects();
2463 (output, commands, side_effects)
2464 });
2465
2466 {
2467 let mut applier = self.borrow_applier();
2468 for command in commands.drain(..) {
2469 command.apply(&mut *applier)?;
2470 }
2471 for update in runtime_handle.take_updates() {
2472 update.apply(&mut *applier)?;
2473 }
2474 }
2475 runtime_handle.drain_ui();
2476 for effect in side_effects {
2477 effect();
2478 }
2479 runtime_handle.drain_ui();
2480 {
2481 let mut slots_mut = slots.borrow_mut();
2482 slots_mut.finalize_current_group();
2483 slots_mut.flush();
2484 }
2485 Ok(result)
2486 }
2487
2488 pub fn subcompose_slot<R>(
2493 &self,
2494 slots: &Rc<SlotsHost>,
2495 root: Option<NodeId>,
2496 f: impl FnOnce(&Composer) -> R,
2497 ) -> Result<(R, Vec<RecomposeScope>), NodeError> {
2498 let runtime_handle = self.runtime_handle();
2499 slots.borrow_mut().reset();
2502 let phase = self.phase();
2503 let locals = self.current_local_stack();
2504 let core = Rc::new(ComposerCore::new(
2505 Rc::clone(slots),
2506 Rc::clone(&self.core.applier),
2507 runtime_handle.clone(),
2508 self.observer(),
2509 root, ));
2511 core.phase.set(phase);
2512 *core.local_stack.borrow_mut() = locals;
2513 let composer = Composer::from_core(core);
2514 composer.subcompose_stack().push(SubcomposeFrame::default());
2515 struct StackGuard {
2516 core: Rc<ComposerCore>,
2517 leaked: bool,
2518 }
2519 impl Drop for StackGuard {
2520 fn drop(&mut self) {
2521 if !self.leaked {
2522 self.core.subcompose_stack.borrow_mut().pop();
2523 }
2524 }
2525 }
2526 let mut guard = StackGuard {
2527 core: composer.clone_core(),
2528 leaked: false,
2529 };
2530 let (result, mut commands, side_effects) = composer.install(|composer| {
2531 let output = f(composer);
2532 if root.is_some() {
2536 composer.pop_parent();
2537 }
2538 let commands = composer.take_commands();
2539 let side_effects = composer.take_side_effects();
2540 (output, commands, side_effects)
2541 });
2542 let frame = {
2543 let mut stack = guard.core.subcompose_stack.borrow_mut();
2544 let frame = stack.pop().expect("subcompose stack underflow");
2545 guard.leaked = true;
2546 frame
2547 };
2548
2549 {
2550 let mut applier = self.borrow_applier();
2551 for command in commands.drain(..) {
2552 command.apply(&mut *applier)?;
2553 }
2554 for update in runtime_handle.take_updates() {
2555 update.apply(&mut *applier)?;
2556 }
2557 }
2558 runtime_handle.drain_ui();
2559 for effect in side_effects {
2560 effect();
2561 }
2562 runtime_handle.drain_ui();
2563 Ok((result, frame.scopes))
2568 }
2569
2570 pub fn skip_current_group(&self) {
2571 let nodes = self.with_slots(|slots| slots.nodes_in_current_group());
2572 self.with_slots_mut(|slots| slots.skip_current_group());
2573 let current_parent = {
2575 let stack = self.parent_stack();
2576 stack.last().map(|frame| frame.id)
2577 };
2578
2579 let mut applier = self.borrow_applier();
2583 for id in nodes {
2584 if let Ok(node) = applier.get_mut(id) {
2585 let node_parent = node.parent();
2586 if node_parent.is_none() || node_parent == current_parent {
2587 drop(applier);
2588 self.attach_to_parent(id);
2589 applier = self.borrow_applier();
2590 }
2591 }
2592 }
2593 }
2594
2595 pub fn runtime_handle(&self) -> RuntimeHandle {
2596 self.core.runtime.clone()
2597 }
2598
2599 pub fn set_recranpose_callback<F>(&self, callback: F)
2600 where
2601 F: FnMut(&Composer) + 'static,
2602 {
2603 if let Some(scope) = self.current_recranpose_scope() {
2604 let observer = self.observer();
2605 let scope_weak = scope.downgrade();
2606 let mut callback = callback;
2607 scope.set_recompose(Box::new(move |composer: &Composer| {
2608 if let Some(inner) = scope_weak.upgrade() {
2609 let scope_instance = RecomposeScope { inner };
2610 observer.observe_reads(
2611 scope_instance.clone(),
2612 move |scope_ref| scope_ref.invalidate(),
2613 || {
2614 callback(composer);
2615 },
2616 );
2617 }
2618 }));
2619 }
2620 }
2621
2622 pub fn with_composition_locals<R>(
2623 &self,
2624 provided: Vec<ProvidedValue>,
2625 f: impl FnOnce(&Composer) -> R,
2626 ) -> R {
2627 if provided.is_empty() {
2628 return f(self);
2629 }
2630 let mut context = LocalContext::default();
2631 for value in provided {
2632 let (key, entry) = value.into_entry(self);
2633 context.values.insert(key, entry);
2634 }
2635 {
2636 let mut stack = self.local_stack();
2637 Rc::make_mut(&mut *stack).push(context);
2638 }
2639 let result = f(self);
2640 {
2641 let mut stack = self.local_stack();
2642 Rc::make_mut(&mut *stack).pop();
2643 }
2644 result
2645 }
2646
2647 fn recranpose_group(&self, scope: &RecomposeScope) {
2648 if !scope.is_invalid() {
2654 scope.mark_recomposed();
2655 return;
2656 }
2657 let started = self.with_slots_mut(|slots| slots.begin_recranpose_at_scope(scope.id()));
2658 if started.is_some() {
2659 let previous_hint = self
2660 .core
2661 .recranpose_parent_hint
2662 .replace(scope.parent_hint());
2663 struct HintGuard {
2664 core: Rc<ComposerCore>,
2665 previous: Option<NodeId>,
2666 }
2667 impl Drop for HintGuard {
2668 fn drop(&mut self) {
2669 self.core.recranpose_parent_hint.set(self.previous);
2670 }
2671 }
2672 let _hint_guard = HintGuard {
2673 core: self.clone_core(),
2674 previous: previous_hint,
2675 };
2676 {
2677 let mut stack = self.scope_stack();
2678 stack.push(scope.clone());
2679 }
2680 let saved_locals = self.current_local_stack();
2681 {
2682 let mut locals = self.local_stack();
2683 *locals = scope.local_stack();
2684 }
2685 self.observe_scope(scope, || {
2686 scope.run_recompose(self);
2687 });
2688 {
2689 let mut locals = self.local_stack();
2690 *locals = saved_locals;
2691 }
2692 {
2693 let mut stack = self.scope_stack();
2694 stack.pop();
2695 }
2696 self.with_slots_mut(SlotStorage::end_recompose);
2697 scope.mark_recomposed();
2698 } else {
2699 scope.mark_recomposed();
2700 }
2701 }
2702
2703 pub fn use_state<T: Clone + 'static>(&self, init: impl FnOnce() -> T) -> MutableState<T> {
2704 let runtime = self.runtime_handle();
2705 let state = self.with_slots_mut(|slots| {
2706 slots.remember(|| OwnedMutableState::with_runtime(init(), runtime.clone()))
2707 });
2708 state.with(|state| state.handle())
2709 }
2710
2711 pub fn emit_node<N: Node + 'static>(&self, init: impl FnOnce() -> N) -> NodeId {
2712 let (existing_id, type_matches) = {
2714 if let Some(id) = self.with_slots_mut(|slots| slots.peek_node()) {
2715 let mut applier = self.borrow_applier();
2717 let matches = match applier.get_mut(id) {
2718 Ok(node) => node.as_any_mut().downcast_ref::<N>().is_some(),
2719 Err(_) => false,
2720 };
2721 (Some(id), matches)
2722 } else {
2723 (None, false)
2724 }
2725 };
2726
2727 if let Some(id) = existing_id {
2729 if type_matches {
2730 let reuse_allowed = true;
2734
2735 #[cfg(not(target_arch = "wasm32"))]
2736 if compose_debug_enabled() {
2737 eprintln!("emit_node: candidate #{id} reuse_allowed={reuse_allowed}");
2738 }
2739
2740 if reuse_allowed {
2741 self.core.last_node_reused.set(Some(true));
2742 #[cfg(not(target_arch = "wasm32"))]
2743 if compose_debug_enabled() {
2744 eprintln!(
2745 "emit_node: reusing node #{id} as {}",
2746 std::any::type_name::<N>()
2747 );
2748 }
2749 self.with_slots_mut(|slots| slots.advance_after_node_read());
2750
2751 self.commands_mut().push(Command::update_node::<N>(id));
2752 self.attach_to_parent(id);
2753 return id;
2754 }
2755 }
2756 }
2757
2758 if let Some(old_id) = existing_id {
2760 if !type_matches {
2761 #[cfg(not(target_arch = "wasm32"))]
2762 if compose_debug_enabled() {
2763 eprintln!(
2764 "emit_node: replacing node #{old_id} with new {}",
2765 std::any::type_name::<N>()
2766 );
2767 }
2768 self.commands_mut().push(Command::RemoveNode { id: old_id });
2769 }
2770 }
2771
2772 let id = {
2775 let mut applier = self.borrow_applier();
2776 applier.create(Box::new(init()))
2777 };
2778 self.core.last_node_reused.set(Some(false));
2779 #[cfg(not(target_arch = "wasm32"))]
2780 if compose_debug_enabled() {
2781 eprintln!(
2782 "emit_node: creating node #{} as {}",
2783 id,
2784 std::any::type_name::<N>()
2785 );
2786 }
2787 {
2788 self.with_slots_mut(|slots| slots.record_node(id));
2789 }
2790 self.commands_mut().push(Command::MountNode { id });
2791 self.attach_to_parent(id);
2792 id
2793 }
2794
2795 fn attach_to_parent(&self, id: NodeId) {
2796 let mut parent_stack = self.parent_stack();
2802 if let Some(frame) = parent_stack.last_mut() {
2803 let parent_id = frame.id;
2804 if parent_id == id {
2805 return;
2806 }
2807 frame.new_children.push(id);
2808 drop(parent_stack);
2809
2810 {
2821 let mut applier = self.borrow_applier();
2822 if let Ok(child_node) = applier.get_mut(id) {
2823 let existing_parent = child_node.parent();
2824 let should_set = match existing_parent {
2829 None => true,
2830 Some(existing) => {
2831 let root_id = self.core.root.get();
2833 parent_id != root_id.unwrap_or(0) || existing == root_id.unwrap_or(0)
2834 }
2835 };
2836 if should_set {
2837 child_node.set_parent_for_bubbling(parent_id);
2838 }
2839 }
2840 }
2841 return;
2842 }
2843 drop(parent_stack);
2844
2845 let in_subcompose = !self.subcompose_stack().is_empty();
2847 if in_subcompose {
2848 let has_parent = {
2852 let mut applier = self.borrow_applier();
2853 applier
2854 .get_mut(id)
2855 .map(|node| node.parent().is_some())
2856 .unwrap_or(false)
2857 };
2858
2859 if !has_parent {
2860 let mut subcompose_stack = self.subcompose_stack();
2861 if let Some(frame) = subcompose_stack.last_mut() {
2862 frame.nodes.push(id);
2863 }
2864 }
2865 return;
2866 }
2867
2868 if let Some(parent_hint) = self.core.recranpose_parent_hint.get() {
2870 let parent_status = {
2871 let mut applier = self.borrow_applier();
2872 applier
2873 .get_mut(id)
2874 .map(|node| node.parent())
2875 .unwrap_or(None)
2876 };
2877 match parent_status {
2878 Some(existing) if existing == parent_hint => {}
2879 None => {
2880 self.commands_mut().push(Command::AttachChild {
2881 parent_id: parent_hint,
2882 child_id: id,
2883 bubble: DirtyBubble::LAYOUT_AND_MEASURE,
2884 });
2885 }
2886 Some(_) => {}
2887 }
2888 return;
2889 }
2890
2891 let has_parent = {
2896 let mut applier = self.borrow_applier();
2897 applier
2898 .get_mut(id)
2899 .map(|node| node.parent().is_some())
2900 .unwrap_or(false)
2901 };
2902 if has_parent {
2903 return;
2905 }
2906
2907 self.set_root(Some(id));
2909 }
2910
2911 pub fn with_node_mut<N: Node + 'static, R>(
2912 &self,
2913 id: NodeId,
2914 f: impl FnOnce(&mut N) -> R,
2915 ) -> Result<R, NodeError> {
2916 let mut applier = self.borrow_applier();
2917 let node = applier.get_mut(id)?;
2918 let typed = node
2919 .as_any_mut()
2920 .downcast_mut::<N>()
2921 .ok_or(NodeError::TypeMismatch {
2922 id,
2923 expected: std::any::type_name::<N>(),
2924 })?;
2925 Ok(f(typed))
2926 }
2927
2928 pub fn push_parent(&self, id: NodeId) {
2929 let remembered = self.remember(ParentChildren::default);
2930 let reused = self.core.last_node_reused.take().unwrap_or(true);
2931 let in_subcompose = !self.core.subcompose_stack.borrow().is_empty();
2932
2933 let previous = if reused || in_subcompose {
2936 remembered.with(|entry| entry.children.clone())
2937 } else {
2938 Vec::new()
2939 };
2940
2941 self.parent_stack().push(ParentFrame {
2942 id,
2943 remembered,
2944 previous,
2945 new_children: Vec::new(),
2946 });
2947 }
2948
2949 pub fn pop_parent(&self) {
2950 let frame_opt = {
2951 let mut stack = self.parent_stack();
2952 stack.pop()
2953 };
2954 if let Some(frame) = frame_opt {
2955 let ParentFrame {
2956 id,
2957 remembered,
2958 previous,
2959 new_children,
2960 } = frame;
2961
2962 #[cfg(not(target_arch = "wasm32"))]
2963 if compose_debug_enabled() {
2964 eprintln!("pop_parent: node #{}", id);
2965 eprintln!(" previous children: {:?}", previous);
2966 eprintln!(" new children: {:?}", new_children);
2967 }
2968 let children_changed = previous != new_children;
2969
2970 if children_changed {
2971 let target = &new_children;
2972 let mut target_positions = HashMap::default();
2973 target_positions.reserve(target.len());
2974 for (index, &child) in target.iter().enumerate() {
2975 target_positions.insert(child, index);
2976 }
2977
2978 let mut current = previous;
2979
2980 for index in (0..current.len()).rev() {
2981 let child = current[index];
2982 if !target_positions.contains_key(&child) {
2983 current.remove(index);
2984 self.commands_mut().push(Command::RemoveChild {
2985 parent_id: id,
2986 child_id: child,
2987 });
2988 }
2989 }
2990
2991 let mut current_positions = build_child_positions(¤t);
2992 for (target_index, &child) in target.iter().enumerate() {
2993 if let Some(current_index) = current_positions.get(&child).copied() {
2994 if current_index != target_index {
2995 let from_index = current_index;
2996 let to_index = move_child_in_diff_state(
2997 &mut current,
2998 &mut current_positions,
2999 from_index,
3000 target_index,
3001 );
3002 self.commands_mut().push(Command::MoveChild {
3003 parent_id: id,
3004 from_index,
3005 to_index,
3006 bubble: DirtyBubble::LAYOUT_AND_MEASURE,
3007 });
3008 }
3009 } else {
3010 let insert_index = target_index.min(current.len());
3011 let appended_index = current.len();
3012 insert_child_into_diff_state(
3013 &mut current,
3014 &mut current_positions,
3015 insert_index,
3016 child,
3017 );
3018 self.commands_mut().push(Command::InsertChild {
3019 parent_id: id,
3020 child_id: child,
3021 appended_index,
3022 insert_index,
3023 bubble: DirtyBubble::LAYOUT_AND_MEASURE,
3024 });
3025 }
3026 }
3027 }
3028
3029 let expected_children = new_children.clone();
3030 let needs_dirty_check = !children_changed;
3031 self.commands_mut().push(Command::ReconcileChildren {
3032 parent_id: id,
3033 expected_children,
3034 needs_dirty_check,
3035 });
3036
3037 remembered.update(|entry| entry.children = new_children);
3038 }
3039 }
3040
3041 pub(crate) fn take_commands(&self) -> Vec<Command> {
3042 std::mem::take(&mut *self.commands_mut())
3043 }
3044
3045 pub fn apply_pending_commands(&self) -> Result<(), NodeError> {
3050 let mut commands = self.take_commands();
3051 let runtime_handle = self.runtime_handle();
3052 {
3053 let mut applier = self.borrow_applier();
3054 for command in commands.drain(..) {
3055 command.apply(&mut *applier)?;
3056 }
3057 for update in runtime_handle.take_updates() {
3058 update.apply(&mut *applier)?;
3059 }
3060 }
3061 runtime_handle.drain_ui();
3062 Ok(())
3063 }
3064
3065 pub fn register_side_effect(&self, effect: impl FnOnce() + 'static) {
3066 self.side_effects_mut().push(Box::new(effect));
3067 }
3068
3069 pub fn take_side_effects(&self) -> Vec<Box<dyn FnOnce()>> {
3070 std::mem::take(&mut *self.side_effects_mut())
3071 }
3072
3073 pub(crate) fn root(&self) -> Option<NodeId> {
3074 self.core.root.get()
3075 }
3076
3077 pub(crate) fn set_root(&self, node: Option<NodeId>) {
3078 self.core.root.set(node);
3079 }
3080}
3081
3082#[derive(Default, Clone)]
3083struct ParentChildren {
3084 children: Vec<NodeId>,
3085}
3086
3087fn build_child_positions(children: &[NodeId]) -> HashMap<NodeId, usize> {
3088 let mut positions = HashMap::default();
3089 positions.reserve(children.len());
3090 for (index, &child) in children.iter().enumerate() {
3091 positions.insert(child, index);
3092 }
3093 positions
3094}
3095
3096fn refresh_child_positions(
3097 current: &[NodeId],
3098 positions: &mut HashMap<NodeId, usize>,
3099 start: usize,
3100 end: usize,
3101) {
3102 if current.is_empty() || start >= current.len() {
3103 return;
3104 }
3105 let end = end.min(current.len() - 1);
3106 for (offset, &child) in current[start..=end].iter().enumerate() {
3107 positions.insert(child, start + offset);
3108 }
3109}
3110
3111fn insert_child_into_diff_state(
3112 current: &mut Vec<NodeId>,
3113 positions: &mut HashMap<NodeId, usize>,
3114 index: usize,
3115 child: NodeId,
3116) {
3117 let index = index.min(current.len());
3118 current.insert(index, child);
3119 refresh_child_positions(current, positions, index, current.len() - 1);
3120}
3121
3122fn move_child_in_diff_state(
3123 current: &mut Vec<NodeId>,
3124 positions: &mut HashMap<NodeId, usize>,
3125 from_index: usize,
3126 target_index: usize,
3127) -> usize {
3128 let child = current.remove(from_index);
3129 let to_index = target_index.min(current.len());
3130 current.insert(to_index, child);
3131 refresh_child_positions(
3132 current,
3133 positions,
3134 from_index.min(to_index),
3135 from_index.max(to_index),
3136 );
3137 to_index
3138}
3139
3140struct ParentFrame {
3141 id: NodeId,
3142 remembered: Owned<ParentChildren>,
3143 previous: Vec<NodeId>,
3144 new_children: Vec<NodeId>,
3145}
3146
3147#[derive(Default)]
3148struct SubcomposeFrame {
3149 nodes: Vec<NodeId>,
3150 scopes: Vec<RecomposeScope>,
3151}
3152
3153#[derive(Default, Clone)]
3154struct LocalContext {
3155 values: HashMap<LocalKey, Rc<dyn Any>>,
3156}
3157
3158pub(crate) struct MutableStateInner<T: Clone + 'static> {
3159 state: Arc<SnapshotMutableState<T>>,
3160 watchers: RefCell<HashMap<ScopeId, Weak<RecomposeScopeInner>>>, runtime: RuntimeHandle,
3162}
3163
3164impl<T: Clone + 'static> MutableStateInner<T> {
3165 fn new(value: T, runtime: RuntimeHandle) -> Self {
3166 Self {
3167 state: SnapshotMutableState::new_in_arc(value, Arc::new(NeverEqual)),
3168 watchers: RefCell::new(HashMap::default()),
3169 runtime,
3170 }
3171 }
3172
3173 fn install_snapshot_observer(&self, state_id: StateId) {
3174 let runtime_handle = self.runtime.clone();
3175 self.state.add_apply_observer(Box::new(move || {
3176 let runtime = runtime_handle.clone();
3177 runtime_handle.enqueue_ui_task(Box::new(move || {
3178 runtime.with_state_arena(|arena| {
3179 let _ = arena.with_typed_opt::<T, _>(state_id, |inner| {
3180 inner.invalidate_watchers();
3181 });
3182 });
3183 }));
3184 }));
3185 }
3186
3187 fn with_value<R>(&self, f: impl FnOnce(&T) -> R) -> R {
3188 let value = self.state.get();
3189 f(&value)
3190 }
3191
3192 fn register_scope(&self, scope: &RecomposeScope) -> bool {
3193 let mut watchers = self.watchers.borrow_mut();
3194 match watchers.get(&scope.id()) {
3195 Some(existing) if existing.upgrade().is_some() => false,
3196 _ => {
3197 watchers.insert(scope.id(), scope.downgrade());
3198 true
3199 }
3200 }
3201 }
3202
3203 fn invalidate_watchers(&self) {
3204 let watchers: Vec<RecomposeScope> = {
3205 let mut watchers = self.watchers.borrow_mut();
3206 let mut live = Vec::with_capacity(watchers.len());
3207 watchers.retain(|_, weak| {
3208 if let Some(inner) = weak.upgrade() {
3209 live.push(RecomposeScope { inner });
3210 true
3211 } else {
3212 false
3213 }
3214 });
3215 live
3216 };
3217
3218 if input_debug_enabled() {
3219 let scope_ids: Vec<_> = watchers.iter().map(|scope| scope.id()).collect();
3220 eprintln!(
3221 "[CRANPOSE_INPUT_DEBUG] state {:?} invalidate_watchers count={} scopes={:?}",
3222 self.state.id(),
3223 scope_ids.len(),
3224 scope_ids
3225 );
3226 }
3227
3228 for watcher in watchers {
3229 watcher.invalidate();
3230 }
3231 }
3232}
3233
3234fn register_current_state_scope<T: Clone + 'static>(inner: &MutableStateInner<T>) {
3235 let Some(Some(scope)) =
3236 with_current_composer_opt(|composer| composer.current_recranpose_scope())
3237 else {
3238 return;
3239 };
3240 let inserted = inner.register_scope(&scope);
3241 if inserted && input_debug_enabled() {
3242 let watchers = inner.watchers.borrow();
3243 eprintln!(
3244 "[CRANPOSE_INPUT_DEBUG] state {:?} subscribe scope={} watchers={}",
3245 inner.state.id(),
3246 scope.id(),
3247 watchers.len()
3248 );
3249 }
3250}
3251
3252pub struct State<T: Clone + 'static> {
3254 id: StateId,
3255 runtime_id: runtime::RuntimeId,
3256 _marker: PhantomData<fn() -> T>,
3257}
3258
3259pub struct MutableState<T: Clone + 'static> {
3264 id: StateId,
3265 runtime_id: runtime::RuntimeId,
3266 _marker: PhantomData<fn() -> T>,
3267}
3268
3269#[derive(Clone)]
3275pub struct OwnedMutableState<T: Clone + 'static> {
3276 state: MutableState<T>,
3277 _lease: Rc<runtime::StateHandleLease>,
3278 _marker: PhantomData<fn() -> T>,
3279}
3280
3281impl<T: Clone + 'static> PartialEq for State<T> {
3282 fn eq(&self, other: &Self) -> bool {
3283 self.state_id() == other.state_id() && self.runtime_id() == other.runtime_id()
3284 }
3285}
3286
3287impl<T: Clone + 'static> Eq for State<T> {}
3288
3289impl<T: Clone + 'static> PartialEq for MutableState<T> {
3290 fn eq(&self, other: &Self) -> bool {
3291 self.state_id() == other.state_id() && self.runtime_id() == other.runtime_id()
3292 }
3293}
3294
3295impl<T: Clone + 'static> Eq for MutableState<T> {}
3296
3297impl<T: Clone + 'static> Copy for State<T> {}
3298
3299impl<T: Clone + 'static> Clone for State<T> {
3300 fn clone(&self) -> Self {
3301 *self
3302 }
3303}
3304
3305impl<T: Clone + 'static> Copy for MutableState<T> {}
3306
3307impl<T: Clone + 'static> Clone for MutableState<T> {
3308 fn clone(&self) -> Self {
3309 *self
3310 }
3311}
3312
3313impl<T: Clone + 'static> State<T> {
3314 fn state_id(&self) -> StateId {
3315 self.id
3316 }
3317
3318 fn runtime_id(&self) -> runtime::RuntimeId {
3319 self.runtime_id
3320 }
3321
3322 fn runtime_handle(&self) -> RuntimeHandle {
3323 runtime::runtime_handle_by_id(self.runtime_id())
3324 .unwrap_or_else(|| panic!("runtime {:?} dropped", self.runtime_id()))
3325 }
3326
3327 fn with_inner<R>(&self, f: impl FnOnce(&MutableStateInner<T>) -> R) -> R {
3328 self.runtime_handle()
3329 .with_state_arena(|arena| arena.with_typed::<T, R>(self.state_id(), f))
3330 }
3331
3332 fn subscribe_current_scope(&self) {
3333 self.with_inner(register_current_state_scope::<T>);
3334 }
3335
3336 pub fn with<R>(&self, f: impl FnOnce(&T) -> R) -> R {
3337 self.subscribe_current_scope();
3338 self.with_inner(|inner| inner.with_value(f))
3339 }
3340
3341 pub fn value(&self) -> T {
3342 self.subscribe_current_scope();
3343 self.with_inner(|inner| inner.state.get())
3344 }
3345
3346 pub fn get(&self) -> T {
3347 self.value()
3348 }
3349}
3350
3351impl<T: Clone + 'static> MutableState<T> {
3352 pub fn with_runtime(value: T, runtime: RuntimeHandle) -> Self {
3354 runtime.alloc_persistent_state(value)
3355 }
3356
3357 fn from_parts(id: StateId, runtime_id: runtime::RuntimeId) -> Self {
3358 Self {
3359 id,
3360 runtime_id,
3361 _marker: PhantomData,
3362 }
3363 }
3364
3365 pub(crate) fn from_lease(lease: &Rc<runtime::StateHandleLease>) -> Self {
3366 Self::from_parts(lease.id(), lease.runtime().id())
3367 }
3368
3369 fn state_id(&self) -> StateId {
3370 self.id
3371 }
3372
3373 fn runtime_id(&self) -> runtime::RuntimeId {
3374 self.runtime_id
3375 }
3376
3377 fn runtime_handle(&self) -> RuntimeHandle {
3378 runtime::runtime_handle_by_id(self.runtime_id())
3379 .unwrap_or_else(|| panic!("runtime {:?} dropped", self.runtime_id()))
3380 }
3381
3382 fn with_inner<R>(&self, f: impl FnOnce(&MutableStateInner<T>) -> R) -> R {
3383 self.runtime_handle()
3384 .with_state_arena(|arena| arena.with_typed::<T, R>(self.state_id(), f))
3385 }
3386
3387 fn try_with_inner<R>(&self, f: impl FnOnce(&MutableStateInner<T>) -> R) -> Option<R> {
3388 self.runtime_handle()
3389 .with_state_arena(|arena| arena.with_typed_opt::<T, R>(self.state_id(), f))
3390 }
3391
3392 pub fn is_alive(&self) -> bool {
3394 self.try_with_inner(|_| ()).is_some()
3395 }
3396
3397 pub fn try_with<R>(&self, f: impl FnOnce(&T) -> R) -> Option<R> {
3402 self.try_with_inner(|inner| inner.with_value(f))
3403 }
3404
3405 pub fn try_value(&self) -> Option<T> {
3407 self.try_with_inner(|inner| inner.state.get())
3408 }
3409
3410 pub fn as_state(&self) -> State<T> {
3411 State {
3412 id: self.id,
3413 runtime_id: self.runtime_id,
3414 _marker: PhantomData,
3415 }
3416 }
3417
3418 pub fn try_retain(&self) -> Option<OwnedMutableState<T>> {
3420 let lease = self.runtime_handle().retain_state_lease(self.state_id())?;
3421 Some(OwnedMutableState {
3422 state: *self,
3423 _lease: lease,
3424 _marker: PhantomData,
3425 })
3426 }
3427
3428 pub fn retain(&self) -> OwnedMutableState<T> {
3430 self.try_retain()
3431 .unwrap_or_else(|| panic!("state {:?} is no longer alive", self.state_id()))
3432 }
3433
3434 pub fn with<R>(&self, f: impl FnOnce(&T) -> R) -> R {
3435 self.subscribe_current_scope();
3436 self.with_inner(|inner| inner.with_value(f))
3437 }
3438
3439 pub fn update<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
3440 let runtime = self.runtime_handle();
3441 runtime.assert_ui_thread();
3442 runtime.with_state_arena(|arena| {
3443 arena.with_typed::<T, R>(self.state_id(), |inner| {
3444 let mut value = inner.state.get();
3445 let tracker = UpdateScope::new(inner.state.id());
3446 let result = f(&mut value);
3447 let wrote_elsewhere = tracker.finish();
3448 if !wrote_elsewhere {
3449 inner.state.set(value);
3450 }
3451 inner.invalidate_watchers();
3452 result
3453 })
3454 })
3455 }
3456
3457 pub fn replace(&self, value: T) {
3465 let runtime = self.runtime_handle();
3466 runtime.assert_ui_thread();
3467 runtime.with_state_arena(|arena| {
3468 if arena
3469 .with_typed_opt::<T, ()>(self.state_id(), |inner| {
3470 inner.state.set(value);
3471 inner.invalidate_watchers();
3472 })
3473 .is_none()
3474 {
3475 log::debug!(
3476 "MutableState::replace skipped: state cell released (slot={}, gen={})",
3477 self.state_id().slot(),
3478 self.state_id().generation(),
3479 );
3480 }
3481 });
3482 }
3483
3484 pub fn set_value(&self, value: T) {
3485 self.replace(value);
3486 }
3487
3488 pub fn set(&self, value: T) {
3489 self.replace(value);
3490 }
3491
3492 pub fn value(&self) -> T {
3493 self.subscribe_current_scope();
3494 self.with_inner(|inner| inner.state.get())
3495 }
3496
3497 pub fn get(&self) -> T {
3498 self.value()
3499 }
3500
3501 pub fn get_non_reactive(&self) -> T {
3514 self.with_inner(|inner| inner.state.get())
3516 }
3517
3518 fn subscribe_current_scope(&self) {
3519 self.with_inner(register_current_state_scope::<T>);
3520 }
3521
3522 #[cfg(test)]
3523 pub(crate) fn watcher_count(&self) -> usize {
3524 self.with_inner(|inner| inner.watchers.borrow().len())
3525 }
3526
3527 #[cfg(test)]
3528 pub(crate) fn state_id_for_test(&self) -> StateId {
3529 self.state_id()
3530 }
3531
3532 #[cfg(test)]
3533 pub(crate) fn subscribe_scope_for_test(&self, scope: &RecomposeScope) {
3534 self.as_state().subscribe_scope_for_test(scope);
3535 }
3536}
3537
3538impl<T: Clone + 'static> OwnedMutableState<T> {
3539 pub fn with_runtime(value: T, runtime: RuntimeHandle) -> Self {
3541 let lease = runtime.alloc_state(value);
3542 Self {
3543 state: MutableState::from_lease(&lease),
3544 _lease: lease,
3545 _marker: PhantomData,
3546 }
3547 }
3548
3549 pub fn handle(&self) -> MutableState<T> {
3551 self.state
3552 }
3553
3554 pub fn as_state(&self) -> State<T> {
3556 self.state.as_state()
3557 }
3558}
3559
3560impl<T: Clone + 'static> Deref for OwnedMutableState<T> {
3561 type Target = MutableState<T>;
3562
3563 fn deref(&self) -> &Self::Target {
3564 &self.state
3565 }
3566}
3567
3568#[cfg(test)]
3569impl<T: Clone + 'static> State<T> {
3570 pub(crate) fn subscribe_scope_for_test(&self, scope: &RecomposeScope) {
3571 self.with_inner(|inner| {
3572 inner.register_scope(scope);
3573 });
3574 }
3575}
3576
3577impl<T: fmt::Debug + Clone + 'static> fmt::Debug for MutableState<T> {
3578 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3579 self.with_inner(|inner| {
3580 inner.with_value(|value| {
3581 f.debug_struct("MutableState")
3582 .field("value", value)
3583 .finish()
3584 })
3585 })
3586 }
3587}
3588
3589#[derive(Clone)]
3590pub struct SnapshotStateList<T: Clone + 'static> {
3591 state: OwnedMutableState<Vec<T>>,
3592}
3593
3594impl<T: Clone + 'static> SnapshotStateList<T> {
3595 pub fn with_runtime<I>(values: I, runtime: RuntimeHandle) -> Self
3596 where
3597 I: IntoIterator<Item = T>,
3598 {
3599 let initial: Vec<T> = values.into_iter().collect();
3600 Self {
3601 state: OwnedMutableState::with_runtime(initial, runtime),
3602 }
3603 }
3604
3605 pub fn as_state(&self) -> State<Vec<T>> {
3606 self.state.as_state()
3607 }
3608
3609 pub fn as_mutable_state(&self) -> MutableState<Vec<T>> {
3610 self.state.handle()
3611 }
3612
3613 pub fn len(&self) -> usize {
3614 self.state.with(|values| values.len())
3615 }
3616
3617 pub fn is_empty(&self) -> bool {
3618 self.len() == 0
3619 }
3620
3621 pub fn to_vec(&self) -> Vec<T> {
3622 self.state.with(|values| values.clone())
3623 }
3624
3625 pub fn iter(&self) -> Vec<T> {
3626 self.to_vec()
3627 }
3628
3629 pub fn get(&self, index: usize) -> T {
3630 self.state.with(|values| values[index].clone())
3631 }
3632
3633 pub fn get_opt(&self, index: usize) -> Option<T> {
3634 self.state.with(|values| values.get(index).cloned())
3635 }
3636
3637 pub fn first(&self) -> Option<T> {
3638 self.get_opt(0)
3639 }
3640
3641 pub fn last(&self) -> Option<T> {
3642 self.state.with(|values| values.last().cloned())
3643 }
3644
3645 pub fn push(&self, value: T) {
3646 self.state.update(|values| values.push(value));
3647 }
3648
3649 pub fn extend<I>(&self, iter: I)
3650 where
3651 I: IntoIterator<Item = T>,
3652 {
3653 self.state.update(|values| values.extend(iter));
3654 }
3655
3656 pub fn insert(&self, index: usize, value: T) {
3657 self.state.update(|values| values.insert(index, value));
3658 }
3659
3660 pub fn set(&self, index: usize, value: T) -> T {
3661 self.state
3662 .update(|values| std::mem::replace(&mut values[index], value))
3663 }
3664
3665 pub fn remove(&self, index: usize) -> T {
3666 self.state.update(|values| values.remove(index))
3667 }
3668
3669 pub fn pop(&self) -> Option<T> {
3670 self.state.update(|values| values.pop())
3671 }
3672
3673 pub fn clear(&self) {
3674 self.state.replace(Vec::new());
3675 }
3676
3677 pub fn retain<F>(&self, mut predicate: F)
3678 where
3679 F: FnMut(&T) -> bool,
3680 {
3681 self.state
3682 .update(|values| values.retain(|value| predicate(value)));
3683 }
3684
3685 pub fn replace_with<I>(&self, iter: I)
3686 where
3687 I: IntoIterator<Item = T>,
3688 {
3689 self.state.replace(iter.into_iter().collect());
3690 }
3691}
3692
3693impl<T: fmt::Debug + Clone + 'static> fmt::Debug for SnapshotStateList<T> {
3694 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3695 let contents = self.to_vec();
3696 f.debug_struct("SnapshotStateList")
3697 .field("values", &contents)
3698 .finish()
3699 }
3700}
3701
3702#[derive(Clone)]
3703pub struct SnapshotStateMap<K, V>
3704where
3705 K: Clone + Eq + Hash + 'static,
3706 V: Clone + 'static,
3707{
3708 state: OwnedMutableState<HashMap<K, V>>,
3709}
3710
3711impl<K, V> SnapshotStateMap<K, V>
3712where
3713 K: Clone + Eq + Hash + 'static,
3714 V: Clone + 'static,
3715{
3716 pub fn with_runtime<I>(pairs: I, runtime: RuntimeHandle) -> Self
3717 where
3718 I: IntoIterator<Item = (K, V)>,
3719 {
3720 let map: HashMap<K, V> = pairs.into_iter().collect();
3721 Self {
3722 state: OwnedMutableState::with_runtime(map, runtime),
3723 }
3724 }
3725
3726 pub fn as_state(&self) -> State<HashMap<K, V>> {
3727 self.state.as_state()
3728 }
3729
3730 pub fn as_mutable_state(&self) -> MutableState<HashMap<K, V>> {
3731 self.state.handle()
3732 }
3733
3734 pub fn len(&self) -> usize {
3735 self.state.with(|map| map.len())
3736 }
3737
3738 pub fn is_empty(&self) -> bool {
3739 self.state.with(|map| map.is_empty())
3740 }
3741
3742 pub fn contains_key(&self, key: &K) -> bool {
3743 self.state.with(|map| map.contains_key(key))
3744 }
3745
3746 pub fn get(&self, key: &K) -> Option<V> {
3747 self.state.with(|map| map.get(key).cloned())
3748 }
3749
3750 pub fn to_hash_map(&self) -> HashMap<K, V> {
3751 self.state.with(|map| map.clone())
3752 }
3753
3754 pub fn insert(&self, key: K, value: V) -> Option<V> {
3755 self.state.update(|map| map.insert(key, value))
3756 }
3757
3758 pub fn extend<I>(&self, iter: I)
3759 where
3760 I: IntoIterator<Item = (K, V)>,
3761 {
3762 self.state.update(|map| map.extend(iter));
3763 }
3765
3766 pub fn remove(&self, key: &K) -> Option<V> {
3767 self.state.update(|map| map.remove(key))
3768 }
3769
3770 pub fn clear(&self) {
3771 self.state.replace(HashMap::default());
3772 }
3773
3774 pub fn retain<F>(&self, mut predicate: F)
3775 where
3776 F: FnMut(&K, &mut V) -> bool,
3777 {
3778 self.state.update(|map| map.retain(|k, v| predicate(k, v)));
3779 }
3780}
3781
3782impl<K, V> fmt::Debug for SnapshotStateMap<K, V>
3783where
3784 K: Clone + Eq + Hash + fmt::Debug + 'static,
3785 V: Clone + fmt::Debug + 'static,
3786{
3787 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3788 let contents = self.to_hash_map();
3789 f.debug_struct("SnapshotStateMap")
3790 .field("entries", &contents)
3791 .finish()
3792 }
3793}
3794
3795struct DerivedState<T: Clone + 'static> {
3796 compute: Rc<dyn Fn() -> T>, state: OwnedMutableState<T>,
3798}
3799
3800impl<T: Clone + 'static> DerivedState<T> {
3801 fn new(runtime: RuntimeHandle, compute: Rc<dyn Fn() -> T>) -> Self {
3802 let initial = compute();
3804 Self {
3805 compute,
3806 state: OwnedMutableState::with_runtime(initial, runtime),
3807 }
3808 }
3809
3810 fn set_compute(&mut self, compute: Rc<dyn Fn() -> T>) {
3811 self.compute = compute;
3813 }
3814
3815 fn recompute(&self) {
3816 let value = (self.compute)();
3817 self.state.set_value(value);
3818 }
3819}
3820
3821impl<T: fmt::Debug + Clone + 'static> fmt::Debug for State<T> {
3822 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3823 self.with_inner(|inner| {
3824 inner.with_value(|value| f.debug_struct("State").field("value", value).finish())
3825 })
3826 }
3827}
3828
3829pub struct ParamState<T> {
3830 value: Option<T>,
3831}
3832
3833impl<T> ParamState<T> {
3834 pub fn update(&mut self, new_value: &T) -> bool
3835 where
3836 T: PartialEq + Clone,
3837 {
3838 match &self.value {
3839 Some(old) if old == new_value => false,
3840 _ => {
3841 self.value = Some(new_value.clone());
3842 true
3843 }
3844 }
3845 }
3846
3847 pub fn value(&self) -> Option<T>
3848 where
3849 T: Clone,
3850 {
3851 self.value.clone()
3852 }
3853}
3854
3855pub struct ParamSlot<T> {
3858 val: RefCell<Option<T>>,
3859}
3860
3861impl<T> Default for ParamSlot<T> {
3862 fn default() -> Self {
3863 Self {
3864 val: RefCell::new(None),
3865 }
3866 }
3867}
3868
3869impl<T> ParamSlot<T> {
3870 pub fn set(&self, v: T) {
3871 *self.val.borrow_mut() = Some(v);
3872 }
3873
3874 pub fn take(&self) -> T {
3876 self.val
3877 .borrow_mut()
3878 .take()
3879 .expect("ParamSlot take() called before set")
3880 }
3881}
3882
3883#[derive(Clone)]
3887pub struct CallbackHolder {
3888 rc: Rc<RefCell<Box<dyn FnMut()>>>,
3889}
3890
3891impl CallbackHolder {
3892 pub fn new() -> Self {
3894 Self::default()
3895 }
3896
3897 pub fn update<F>(&self, f: F)
3899 where
3900 F: FnMut() + 'static,
3901 {
3902 *self.rc.borrow_mut() = Box::new(f);
3903 }
3904
3905 pub fn clone_rc(&self) -> impl Fn() + 'static {
3907 let rc = self.rc.clone();
3908 move || {
3909 (rc.borrow_mut())();
3910 }
3911 }
3912}
3913
3914impl Default for CallbackHolder {
3915 fn default() -> Self {
3916 Self {
3917 rc: Rc::new(RefCell::new(Box::new(|| {}) as Box<dyn FnMut()>)),
3918 }
3919 }
3920}
3921
3922#[derive(Clone)]
3925pub struct CallbackHolder1<A: 'static> {
3926 #[allow(clippy::type_complexity)]
3927 rc: Rc<RefCell<Box<dyn FnMut(A)>>>,
3928}
3929
3930impl<A: 'static> CallbackHolder1<A> {
3931 pub fn new() -> Self {
3933 Self::default()
3934 }
3935
3936 pub fn update<F>(&self, f: F)
3938 where
3939 F: FnMut(A) + 'static,
3940 {
3941 *self.rc.borrow_mut() = Box::new(f);
3942 }
3943
3944 pub fn clone_rc(&self) -> impl Fn(A) + 'static {
3946 let rc = self.rc.clone();
3947 move |arg| {
3948 (rc.borrow_mut())(arg);
3949 }
3950 }
3951}
3952
3953impl<A: 'static> Default for CallbackHolder1<A> {
3954 fn default() -> Self {
3955 Self {
3956 rc: Rc::new(RefCell::new(Box::new(|_| {}) as Box<dyn FnMut(A)>)),
3957 }
3958 }
3959}
3960
3961pub struct ReturnSlot<T> {
3962 value: Option<T>,
3963}
3964
3965impl<T: Clone> ReturnSlot<T> {
3966 pub fn store(&mut self, value: T) {
3967 self.value = Some(value);
3968 }
3969
3970 pub fn get(&self) -> Option<T> {
3971 self.value.clone()
3972 }
3973}
3974
3975impl<T> Default for ParamState<T> {
3976 fn default() -> Self {
3977 Self { value: None }
3978 }
3979}
3980
3981impl<T> Default for ReturnSlot<T> {
3982 fn default() -> Self {
3983 Self { value: None }
3984 }
3985}
3986
3987pub struct Composition<A: Applier + 'static> {
3988 slots: Rc<SlotsHost>,
3989 applier: Rc<ConcreteApplierHost<A>>,
3990 runtime: Runtime,
3991 observer: SnapshotStateObserver,
3992 root: Option<NodeId>,
3993}
3994
3995impl<A: Applier + 'static> Composition<A> {
3996 pub fn new(applier: A) -> Self {
3997 Self::with_runtime(applier, Runtime::new(Arc::new(DefaultScheduler)))
3998 }
3999
4000 pub fn with_runtime(applier: A, runtime: Runtime) -> Self {
4001 Self::with_backend(applier, runtime, SlotBackendKind::default())
4002 }
4003
4004 pub fn with_backend(applier: A, runtime: Runtime, backend_kind: SlotBackendKind) -> Self {
4005 let storage = make_backend(backend_kind);
4006 let slots = Rc::new(SlotsHost::new(storage));
4007 let applier = Rc::new(ConcreteApplierHost::new(applier));
4008 let observer_handle = runtime.handle();
4009 let observer = SnapshotStateObserver::new(move |callback| {
4010 observer_handle.enqueue_ui_task(callback);
4011 });
4012 observer.start();
4013 Self {
4014 slots,
4015 applier,
4016 runtime,
4017 observer,
4018 root: None,
4019 }
4020 }
4021
4022 fn slots_host(&self) -> Rc<SlotsHost> {
4023 Rc::clone(&self.slots)
4024 }
4025
4026 fn applier_host(&self) -> Rc<dyn ApplierHost> {
4027 self.applier.clone()
4028 }
4029
4030 pub fn render(&mut self, key: Key, mut content: impl FnMut()) -> Result<(), NodeError> {
4031 self.slots.borrow_mut().reset();
4032 let runtime_handle = self.runtime_handle();
4033 runtime_handle.drain_ui();
4034 let composer = Composer::new(
4035 Rc::clone(&self.slots),
4036 self.applier.clone(),
4037 runtime_handle.clone(),
4038 self.observer.clone(),
4039 self.root,
4040 );
4041 self.observer.begin_frame();
4042 let (root, mut commands, side_effects) = composer.install(|composer| {
4043 composer.with_group(key, |_| content());
4044 let root = composer.root();
4045 let commands = composer.take_commands();
4046 let side_effects = composer.take_side_effects();
4047 (root, commands, side_effects)
4048 });
4049
4050 {
4051 let mut applier = self.applier.borrow_dyn();
4052 for command in commands.drain(..) {
4053 command.apply(&mut *applier)?;
4054 }
4055 for update in runtime_handle.take_updates() {
4056 update.apply(&mut *applier)?;
4057 }
4058 }
4059
4060 runtime_handle.drain_ui();
4061 for effect in side_effects {
4062 effect();
4063 }
4064 runtime_handle.drain_ui();
4065 self.root = root;
4066 {
4067 let mut slots = self.slots.borrow_mut();
4068 let _ = slots.finalize_current_group();
4069 slots.flush();
4070 }
4071 let _ = self.process_invalid_scopes()?;
4072 if !self.runtime.has_updates()
4073 && !runtime_handle.has_invalid_scopes()
4074 && !runtime_handle.has_frame_callbacks()
4075 && !runtime_handle.has_pending_ui()
4076 {
4077 self.runtime.set_needs_frame(false);
4078 }
4079 Ok(())
4080 }
4081
4082 pub fn should_render(&self) -> bool {
4091 self.runtime.needs_frame() || self.runtime.has_updates()
4092 }
4093
4094 pub fn runtime_handle(&self) -> RuntimeHandle {
4095 self.runtime.handle()
4096 }
4097
4098 pub fn applier_mut(&mut self) -> ApplierGuard<'_, A> {
4099 ApplierGuard::new(self.applier.borrow_typed())
4100 }
4101
4102 pub fn root(&self) -> Option<NodeId> {
4103 self.root
4104 }
4105
4106 pub fn debug_dump_slot_table_groups(&self) -> Vec<(usize, Key, Option<ScopeId>, usize)> {
4107 self.slots.borrow().debug_dump_groups()
4108 }
4109
4110 pub fn debug_dump_all_slots(&self) -> Vec<(usize, String)> {
4111 self.slots.borrow().debug_dump_all_slots()
4112 }
4113
4114 pub fn process_invalid_scopes(&mut self) -> Result<bool, NodeError> {
4115 let runtime_handle = self.runtime_handle();
4116 let mut did_recompose = false;
4117 let mut loop_count = 0;
4118 loop {
4119 loop_count += 1;
4120 if loop_count > 100 {
4121 log::error!("process_invalid_scopes looped too many times! Breaking loop to prevent freeze.");
4122 break;
4123 }
4124 runtime_handle.drain_ui();
4125 let pending = runtime_handle.take_invalidated_scopes();
4126 if pending.is_empty() {
4127 break;
4128 }
4129 if input_debug_enabled() {
4130 let pending_ids: Vec<_> = pending.iter().map(|(id, _)| *id).collect();
4131 eprintln!(
4132 "[CRANPOSE_INPUT_DEBUG] process_invalid_scopes pending_ids={:?}",
4133 pending_ids
4134 );
4135 }
4136 let mut scopes = Vec::new();
4137 for (id, weak) in pending {
4138 if let Some(inner) = weak.upgrade() {
4139 scopes.push(RecomposeScope { inner });
4140 } else {
4141 runtime_handle.mark_scope_recomposed(id);
4142 }
4143 }
4144 if scopes.is_empty() {
4145 continue;
4146 }
4147 if input_debug_enabled() {
4148 let scope_ids: Vec<_> = scopes.iter().map(|scope| scope.id()).collect();
4149 eprintln!(
4150 "[CRANPOSE_INPUT_DEBUG] process_invalid_scopes live_scope_ids={:?}",
4151 scope_ids
4152 );
4153 }
4154 did_recompose = true;
4155 let runtime_clone = runtime_handle.clone();
4156 let root_host = self.slots_host();
4157 let mut scope_groups: Vec<(Rc<SlotsHost>, Vec<RecomposeScope>)> = Vec::new();
4158 let mut scope_group_index: HashMap<usize, usize> = HashMap::default();
4159 for scope in scopes {
4160 let host = scope.slots_host().unwrap_or_else(|| Rc::clone(&root_host));
4161 let host_key = Rc::as_ptr(&host) as usize;
4162 if let Some(index) = scope_group_index.get(&host_key).copied() {
4163 scope_groups[index].1.push(scope);
4164 } else {
4165 scope_group_index.insert(host_key, scope_groups.len());
4166 scope_groups.push((host, vec![scope]));
4167 }
4168 }
4169 let (mut commands, side_effects) = {
4170 let composer = Composer::new(
4171 Rc::clone(&root_host),
4172 self.applier_host(),
4173 runtime_clone,
4174 self.observer.clone(),
4175 self.root,
4176 );
4177 self.observer.begin_frame();
4178 composer.install(|composer| {
4179 for (host, scopes) in scope_groups.into_iter() {
4180 if Rc::ptr_eq(&host, &root_host) {
4181 for scope in scopes.iter() {
4182 composer.recranpose_group(scope);
4183 }
4184 } else {
4185 composer.with_slot_override(host, |composer| {
4186 for scope in scopes.iter() {
4187 composer.recranpose_group(scope);
4188 }
4189 });
4190 }
4191 }
4192 let commands = composer.take_commands();
4193 let side_effects = composer.take_side_effects();
4194 (commands, side_effects)
4195 })
4196 };
4197 {
4198 let mut applier = self.applier.borrow_dyn();
4199 for command in commands.drain(..) {
4200 command.apply(&mut *applier)?;
4201 }
4202 for update in runtime_handle.take_updates() {
4203 update.apply(&mut *applier)?;
4204 }
4205 }
4206 for effect in side_effects {
4207 effect();
4208 }
4209 runtime_handle.drain_ui();
4210 }
4211 if !self.runtime.has_updates()
4212 && !runtime_handle.has_invalid_scopes()
4213 && !runtime_handle.has_frame_callbacks()
4214 && !runtime_handle.has_pending_ui()
4215 {
4216 self.runtime.set_needs_frame(false);
4217 }
4218 Ok(did_recompose)
4219 }
4220
4221 pub fn flush_pending_node_updates(&mut self) -> Result<(), NodeError> {
4222 let updates = self.runtime_handle().take_updates();
4223 let mut applier = self.applier.borrow_dyn();
4224 for update in updates {
4225 update.apply(&mut *applier)?;
4226 }
4227 Ok(())
4228 }
4229}
4230
4231impl<A: Applier + 'static> Drop for Composition<A> {
4232 fn drop(&mut self) {
4233 self.observer.stop();
4234 }
4235}
4236pub fn location_key(file: &str, line: u32, column: u32) -> Key {
4237 let base = file.as_ptr() as u64;
4238 base
4239 .wrapping_mul(0x9E37_79B9_7F4A_7C15) ^ ((line as u64) << 32)
4241 ^ (column as u64)
4242}
4243
4244fn hash_key<K: Hash>(key: &K) -> Key {
4245 let mut hasher = hash::default::new();
4246 key.hash(&mut hasher);
4247 hasher.finish()
4248}
4249
4250#[cfg(test)]
4251#[path = "tests/lib_tests.rs"]
4252mod tests;
4253
4254#[cfg(test)]
4255#[path = "tests/recursive_decrease_increase_test.rs"]
4256mod recursive_decrease_increase_test;
4257
4258#[cfg(test)]
4259#[path = "tests/slot_backend_tests.rs"]
4260mod slot_backend_tests;
4261
4262pub mod collections;
4263pub mod hash;