1use std::{hash::Hash, rc::Rc};
2
3use crate::{
4 composer_context, location_key,
5 owned::Owned,
6 runtime,
7 state::{
8 DerivedState, MutableState, OwnedMutableState, SnapshotStateList, SnapshotStateMap, State,
9 },
10};
11
12pub fn remember<T: 'static>(init: impl FnOnce() -> T) -> Owned<T> {
13 composer_context::with_composer(|composer| composer.remember(init))
14}
15
16#[allow(non_snake_case)]
24pub fn rememberKeyed<K, T>(key: K, init: impl FnOnce(&K) -> T) -> T
25where
26 K: PartialEq + 'static,
27 T: Clone + 'static,
28{
29 let slot = remember(|| std::cell::RefCell::new(None::<(K, T)>));
30 slot.with(|cell| {
31 let mut stored = cell.borrow_mut();
32 match &*stored {
33 Some((stored_key, value)) if *stored_key == key => value.clone(),
34 _ => {
35 let value = init(&key);
36 *stored = Some((key, value.clone()));
37 value
38 }
39 }
40 })
41}
42
43#[allow(non_snake_case)]
71pub fn rememberUpdatedState<T: Clone + 'static>(value: T) -> MutableState<T> {
72 composer_context::with_composer(|composer| {
73 let runtime = composer.runtime_handle();
74 let state = composer.remember(|| OwnedMutableState::with_runtime(value.clone(), runtime));
75 state.with(|s| {
76 s.set(value);
77 s.handle()
78 })
79 })
80}
81
82#[cfg(feature = "internal")]
83#[allow(non_snake_case)]
84pub fn withFrameNanos(
85 callback: impl FnOnce(u64) + 'static,
86) -> crate::internal::FrameCallbackRegistration {
87 composer_context::with_composer(|composer| {
88 composer
89 .runtime_handle()
90 .frame_clock()
91 .with_frame_nanos(callback)
92 })
93}
94
95#[cfg(feature = "internal")]
96#[allow(non_snake_case)]
97pub fn withFrameMillis(
98 callback: impl FnOnce(u64) + 'static,
99) -> crate::internal::FrameCallbackRegistration {
100 composer_context::with_composer(|composer| {
101 composer
102 .runtime_handle()
103 .frame_clock()
104 .with_frame_millis(callback)
105 })
106}
107
108#[allow(non_snake_case)]
144pub fn mutableStateOf<T: Clone + 'static>(initial: T) -> MutableState<T> {
145 let runtime = composer_context::try_with_composer(|composer| composer.runtime_handle())
146 .or_else(runtime::current_runtime_handle)
147 .expect("mutableStateOf requires an active runtime. Create state inside a composition or after a Runtime is created.");
148 runtime.alloc_persistent_state(initial)
149}
150
151#[allow(non_snake_case)]
152pub fn ownedMutableStateOf<T: Clone + 'static>(initial: T) -> OwnedMutableState<T> {
153 let runtime = composer_context::try_with_composer(|composer| composer.runtime_handle())
154 .or_else(runtime::current_runtime_handle)
155 .expect("ownedMutableStateOf requires an active runtime. Create state inside a composition or after a Runtime is created.");
156 OwnedMutableState::with_runtime(initial, runtime)
157}
158
159#[allow(non_snake_case)]
164pub fn try_mutableStateOf<T: Clone + 'static>(initial: T) -> Option<MutableState<T>> {
165 let runtime = composer_context::try_with_composer(|composer| composer.runtime_handle())
166 .or_else(runtime::current_runtime_handle)?;
167 Some(runtime.alloc_persistent_state(initial))
168}
169
170#[allow(non_snake_case)]
171pub fn mutableStateListOf<T, I>(values: I) -> SnapshotStateList<T>
172where
173 T: Clone + 'static,
174 I: IntoIterator<Item = T>,
175{
176 composer_context::with_composer(move |composer| composer.mutable_state_list_of(values))
177}
178
179#[allow(non_snake_case)]
180pub fn mutableStateList<T: Clone + 'static>() -> SnapshotStateList<T> {
181 mutableStateListOf(std::iter::empty::<T>())
182}
183
184#[allow(non_snake_case)]
185pub fn mutableStateMapOf<K, V, I>(pairs: I) -> SnapshotStateMap<K, V>
186where
187 K: Clone + Eq + Hash + 'static,
188 V: Clone + 'static,
189 I: IntoIterator<Item = (K, V)>,
190{
191 composer_context::with_composer(move |composer| composer.mutable_state_map_of(pairs))
192}
193
194#[allow(non_snake_case)]
195pub fn mutableStateMap<K, V>() -> SnapshotStateMap<K, V>
196where
197 K: Clone + Eq + Hash + 'static,
198 V: Clone + 'static,
199{
200 mutableStateMapOf(std::iter::empty::<(K, V)>())
201}
202
203#[allow(non_snake_case)]
231pub fn rememberMutableStateOf<T: Clone + PartialEq + 'static>(
232 init: impl FnOnce() -> T,
233) -> MutableState<T> {
234 composer_context::with_composer(|composer| {
235 let runtime = composer.runtime_handle();
236 composer
237 .remember(|| OwnedMutableState::with_runtime_structural_eq(init(), runtime))
238 .with(|state| state.handle())
239 })
240}
241
242#[allow(non_snake_case)]
243pub fn rememberMutableStateOfNeverEqual<T: Clone + 'static>(
244 init: impl FnOnce() -> T,
245) -> MutableState<T> {
246 composer_context::with_composer(|composer| {
247 let runtime = composer.runtime_handle();
248 composer
249 .remember(|| OwnedMutableState::with_runtime(init(), runtime))
250 .with(|state| state.handle())
251 })
252}
253
254#[allow(non_snake_case)]
255pub fn derivedStateOf<T: 'static + Clone>(compute: impl Fn() -> T + 'static) -> State<T> {
256 composer_context::with_composer(|composer| {
257 let key = location_key(file!(), line!(), column!());
258 composer.with_group(key, |composer| {
259 let should_recompute = composer
260 .current_recompose_scope()
261 .map(|scope| scope.should_recompose())
262 .unwrap_or(true);
263 let runtime = composer.runtime_handle();
264 let compute_rc: Rc<dyn Fn() -> T> = Rc::new(compute);
265 let derived =
266 composer.remember(|| DerivedState::new(runtime.clone(), compute_rc.clone()));
267 derived.update(|derived| {
268 derived.set_compute(compute_rc.clone());
269 if should_recompute {
270 derived.recompute();
271 }
272 });
273 derived.with(|derived| derived.state.as_state())
274 })
275 })
276}