Skip to main content

cranpose_core/
lib.rs

1#![deny(missing_docs)]
2#![doc = include_str!("../README.md")]
3#![deny(unsafe_code)]
4
5pub extern crate self as cranpose_core;
6
7mod applier;
8mod applier_host;
9pub use applier::Applier;
10mod blocking;
11mod bubble_passes;
12mod callbacks;
13mod child_positions;
14mod child_sync;
15pub(crate) use child_positions::{
16    build_child_positions, insert_child_into_diff_state, move_child_in_diff_state,
17};
18pub(crate) use child_sync::{
19    apply_remove_child, attach_child_at, cleanup_detached_child, detach_child_from_parent,
20    insert_child_with_reparenting, remove_child_and_cleanup_now, sync_or_settle_children,
21};
22mod command;
23pub(crate) use command::{
24    Command, CommandCallback, DeferredChildCleanup, DeferredChildCleanupQueue, DirtyBubble,
25};
26mod command_queue;
27pub(crate) use command_queue::{
28    COMMAND_FLUSH_THRESHOLD, ChildList, CommandQueue, SMALL_CHILD_SYNC_LINEAR_THRESHOLD,
29};
30#[cfg(test)]
31pub(crate) use command_queue::{CommandTag, SyncChildrenCommand};
32mod composer;
33/// The composer that is current on this thread, which composable code reaches without passing it as
34/// a parameter.
35pub mod composer_context;
36pub(crate) use composer_context::with_current_composer_opt;
37pub use composer_context::{
38    current_recompose_scope_invalidated_only_by, recompose_current_scope_again, withCurrentComposer,
39};
40mod composition;
41mod composition_locals;
42pub(crate) use composition_locals::{LocalKey, LocalStackSnapshot};
43mod computed_state;
44pub mod concurrency;
45mod debug_trace;
46mod disposable_effect;
47pub use diagnostics::{DIAGNOSTICS, Diagnostic, Diagnostics};
48#[cfg(test)]
49pub(crate) use disposable_effect::DisposableEffectState;
50pub use disposable_effect::{
51    __disposable_effect_impl, DisposableEffect, DisposableEffectResult, DisposableEffectScope,
52    SideEffect,
53};
54mod effect_key;
55mod emit;
56mod event_dispatch;
57pub use event_dispatch::{
58    EventHandlerScopeGuard, dispatch_ui_event, enter_event_handler_scope, in_applied_snapshot,
59    in_event_handler, run_in_mutable_snapshot,
60};
61pub mod debug_toggles;
62pub mod diagnostics;
63#[cfg(any(feature = "internal", test))]
64mod frame_clock;
65mod hooks;
66#[cfg(feature = "internal")]
67mod node_reads;
68pub(crate) use key_group::{explicit_group_key_seed, hash_key};
69mod key_group;
70pub use key_group::{key, with_key};
71mod launched_effect;
72mod layout_dirt_roots;
73mod location_key;
74mod memory_applier;
75pub use memory_applier::{MemoryApplier, MemoryApplierDebugStats, SceneNodeAttachmentScratch};
76mod movable_content;
77mod node;
78#[cfg(any(test, debug_assertions))]
79pub(crate) use location_key::LocationKeyDebugInfo;
80pub(crate) use location_key::{HotOrigin, avalanche_location_key};
81#[cfg(test)]
82pub(crate) use location_key::{
83    hot_call_site_key, location_key_debug_collision_count_for_test,
84    location_key_debug_info_for_test, register_location_key_debug_info_for_test,
85};
86pub use movable_content::{
87    MovableContent, forget_movable, movable, movableContentOf, rememberMovableContentOf,
88};
89pub use node::{
90    Node, bubble_layout_dirty, bubble_layout_dirty_in_composer, bubble_measure_dirty,
91    bubble_measure_dirty_in_composer, bubble_semantics_dirty, bubble_semantics_dirty_in_composer,
92    pop_parent, push_parent, queue_semantics_invalidation, with_node_mut,
93};
94mod node_error;
95mod node_id_cell;
96pub use node_id_cell::NodeIdCell;
97mod node_marks;
98mod phase;
99pub use phase::Phase;
100mod anchor_id;
101pub use anchor_id::AnchorId;
102mod packed_u64;
103pub use node_error::NodeError;
104pub use packed_u64::PackedU64;
105mod process_ids;
106pub use process_ids::ProcessIds;
107/// `Owned`, the handle to a value that a composition remembers.
108pub mod owned;
109mod pausable;
110#[doc(hidden)]
111pub use pausable::{PausableContent, with_pausable_content};
112pub mod platform;
113mod recompose;
114mod recompose_scope;
115pub(crate) use recompose_scope::{BodyRun, RecomposeScopeInner, ScopeRead};
116pub use recompose_scope::{RecomposeOptions, RecomposeScope, RecomposeScopeRegistryDebugStats};
117mod recycle_pool;
118mod recycled_node;
119use recycle_pool::RecyclePool;
120pub use recycled_node::{RecycleOrigin, RecycledNode, RecycledNodeInsertion};
121mod retention;
122/// The runtime in which a composition runs: state cells, UI tasks, frame callbacks and the queue of
123/// invalidated scopes.
124pub mod runtime;
125mod runtime_cell;
126#[cfg(test)]
127pub(crate) use runtime::{TestRuntime, TestScheduler};
128#[expect(clippy::multiple_inherent_impl, reason = "one file per concern")]
129mod slot;
130mod slots_host;
131pub(crate) use slots_host::SlotPassOutcome;
132pub use slots_host::SlotsHost;
133/// A min-heap of snapshot ids that supports removal by handle.
134pub mod snapshot_double_index_heap;
135/// A compact set of snapshot ids.
136pub mod snapshot_id_set;
137/// Tracks the pinned snapshots, which bound the state records that may be reclaimed.
138pub mod snapshot_pinning;
139/// Records which state objects a scope reads and calls back when one of them changes.
140pub mod snapshot_state_observer;
141pub mod snapshot_v2;
142mod snapshot_weak_set;
143pub mod source_trace;
144mod stable_index;
145mod state;
146#[doc(hidden)]
147pub use source_trace::{__inline_source_scope, __source_scope};
148#[doc(hidden)]
149pub use thread_state::with_or_fresh;
150mod stage_times;
151pub mod subcompose;
152mod thread_state;
153#[doc(hidden)]
154pub use stage_times::{StageTimes, stage_ms};
155
156#[cfg(feature = "internal")]
157#[doc(hidden)]
158pub mod internal {
159    pub use crate::{
160        frame_clock::{FrameCallbackRegistration, FrameClock},
161        node_reads::{NodeReads, ReaderGuard},
162    };
163}
164pub use applier_host::{ApplierGuard, ApplierHost, ConcreteApplierHost, NodeDisposal};
165pub use blocking::{
166    BlockingError, BlockingExecutor, BlockingExecutorConfig, BlockingTask, launchBlocking,
167    withBlocking,
168};
169pub use callbacks::{
170    CallbackForwarder, CallbackHolder, ParamReturnState, ParamSlot, ParamState, ReturnSlot,
171    SharedParam, refresh_param, refresh_shared_param, store_param,
172};
173pub use composer::{
174    __branch_group_scope_advance, __branch_group_scope_deferred, BranchGroupGuard,
175    CapturedCompositionContext, ComposableGroup, Composer, ParameterChange, ScopedBranchGroupGuard,
176    ValueSlotHandle,
177};
178pub(crate) use composer::{ComposerCore, EmittedNode, ParentAttachMode, ParentFrame};
179#[cfg(any(test, feature = "leak-debug"))]
180pub use composition::CompositionPassDebugStats;
181pub use composition::{Composition, LayoutBudget, ROOT_RENDER_REPLAY_LIMIT};
182pub use composition_locals::{
183    CompositionLocal, CompositionLocalAccessorScope, CompositionLocalProvider, ProvidedValue,
184    ReadableCompositionLocal, StaticCompositionLocal, compositionLocalOf,
185    compositionLocalOfWithPolicy, compositionLocalWithComputedDefaultOf, staticCompositionLocalOf,
186    staticCompositionLocalOfWithPolicy, staticCompositionLocalWithComputedDefaultOf,
187};
188pub(crate) use composition_locals::{ComputedLocalEntry, LocalStateEntry};
189#[doc(hidden)]
190pub use computed_state::{ComputedState, computedStateOf};
191pub use concurrency::{
192    CollectEvents, CoroutineScope, Delay, EventChannel, EventSender, EventStream, EventStreamNext,
193    ProduceScope, collectAsState, delay, interval, produceState, rememberCoroutineScope,
194    rememberEventStream, spawn_ui_task,
195};
196#[doc(hidden)]
197pub use debug_trace::{
198    debug_label_current_scope, debug_live_recompose_scope_count,
199    debug_recompose_scope_registry_stats, debug_scope_invalidation_sources, debug_scope_label,
200};
201pub use hooks::{
202    derivedStateOf, mutableStateList, mutableStateListOf, mutableStateMap, mutableStateMapOf,
203    mutableStateOf, mutableStateOfNeverEqual, ownedMutableStateOf, ownedMutableStateOfNeverEqual,
204    remember, rememberKeyed, rememberMutableStateOf, rememberMutableStateOfNeverEqual,
205    rememberUpdatedState, try_mutableStateOf,
206};
207#[cfg(feature = "internal")]
208#[doc(hidden)]
209pub use hooks::{withFrameMillis, withFrameNanos};
210pub use launched_effect::{
211    __launched_effect_async_impl, __launched_effect_impl, CancelToken, LaunchedEffect,
212    LaunchedEffectAsync, LaunchedEffectScope, TaskSite,
213};
214pub use location_key::{
215    __constant, HotOriginGuard, branch_location_key, cached_composable_definition_key,
216    caller_location_key, composable_definition_key, composable_identity_key, const_location_key,
217    constant_value_key, hot_branch_key, hot_definition_key, hot_origin, location_key,
218    noted_location_key,
219};
220pub use node_marks::NodeMarks;
221pub use owned::Owned;
222pub use platform::{Clock, RuntimeScheduler, SchedulerRef, scheduler_ref};
223pub use retention::{RetentionBudget, RetentionEvictionPolicy, RetentionMode, RetentionPolicy};
224#[doc(hidden)]
225pub use runtime::{
226    DefaultScheduler, Runtime, RuntimeHandle, StateId, TaskHandle, UiDispatcher,
227    current_runtime_handle, label_next_ui_task, schedule_frame, schedule_node_update,
228};
229pub use runtime_cell::RuntimeCell;
230#[cfg(any(test, feature = "leak-debug"))]
231pub use slot::SlotTableMutationDebugStats;
232pub use slot::{
233    SlotDebugAnchor, SlotDebugEntry, SlotDebugEntryKind, SlotDebugGroup, SlotDebugScope,
234    SlotDebugSnapshot, SlotRetentionDebugStats, SlotTable, SlotTableDebugStats,
235    SlotTableLocalDebugStats,
236};
237pub use snapshot_state_observer::SnapshotStateObserver;
238
239/// Identifies a composition group: the hash of its call site, or of an explicit key together with
240/// its call site. Kept at a 32-bit word's alignment on ESP-IDF, as a [`PackedU64`] is.
241#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
242#[cfg_attr(target_os = "espidf", repr(C, packed(4)))]
243pub struct Key(pub u64);
244
245impl Key {
246    /// This key scoped to `site`, for a group that both identify: the bitwise xor of the two.
247    pub const fn scoped(self, site: Self) -> Self {
248        Self(self.0 ^ site.0)
249    }
250
251    // One FNV-1a step folding `other` into this key.
252    pub(crate) const fn mixed(self, other: Self) -> Self {
253        Self((self.0 ^ other.0).wrapping_mul(0x0000_0100_0000_01b3))
254    }
255}
256
257impl std::fmt::Display for Key {
258    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
259        { self.0 }.fmt(f)
260    }
261}
262/// Identifies a node in an applier.
263#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
264pub struct NodeId(pub usize);
265
266impl NodeId {
267    // The id an applier hands out after this one.
268    pub(crate) const fn next(self) -> Self {
269        Self(self.0.saturating_add(1))
270    }
271}
272
273impl std::str::FromStr for NodeId {
274    type Err = std::num::ParseIntError;
275
276    fn from_str(text: &str) -> Result<Self, Self::Err> {
277        text.parse().map(Self)
278    }
279}
280
281impl std::fmt::Display for NodeId {
282    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
283        self.0.fmt(f)
284    }
285}
286
287pub(crate) type ScopeId = usize;
288pub(crate) type FrameCallbackId = u64;
289pub use composer_context::{
290    __current_composer, note_nested_slots_host, with_composer as with_current_composer,
291};
292pub(crate) use state::MutableStateInner;
293pub use state::{
294    MutableState, OwnedMutableState, SnapshotStateList, SnapshotStateMap, State,
295    StateSubscriptionHold,
296};
297pub use subcompose::{
298    ContentTypeReusePolicy, DefaultSlotReusePolicy, SlotId, SlotReusePolicy, SubcomposeState,
299    TypedSlot,
300};
301
302#[cfg(test)]
303#[path = "tests/mod.rs"]
304mod tests;
305
306#[cfg(test)]
307#[path = "tests/recursive_decrease_increase_test.rs"]
308mod recursive_decrease_increase_test;
309
310pub mod collections;
311/// The hasher type and constructor that the framework uses by default.
312pub mod hash;
313
314/// Where a test writes real files. Behind `test-helpers` so only a test build
315/// of the workspace carries it.
316#[cfg(any(test, feature = "test-helpers"))]
317pub mod test_scratch;
318#[cfg(any(test, feature = "test-helpers"))]
319pub use test_scratch::test_scratch_dir;