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