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