1use std::any::Any;
2use std::rc::Rc;
3
4use crate::{Signal, on_unmount, reactive, remember_with_key, scoped_effect, signal};
5
6pub struct MutableState<T: Clone + 'static> {
7 inner: Signal<T>,
8 saver: Option<Box<dyn StateSaver<T>>>,
9}
10
11pub trait StateSaver<T>: 'static {
12 fn save(&self, value: &T) -> Box<dyn Any>;
13 fn restore(&self, saved: &dyn Any) -> Option<T>;
14}
15
16pub fn remember_derived<T: Clone + 'static>(
17 key: impl Into<String>,
18 producer: impl Fn() -> T + 'static + Clone,
19) -> std::rc::Rc<crate::Signal<T>> {
20 let key: String = key.into();
21 produce_state(format!("derived:{key}"), producer)
22}
23
24pub trait StateHolder: 'static {
26 type State: Clone;
27 type Event;
28
29 fn initial_state() -> Self::State;
30 fn reduce(state: &Self::State, event: Self::Event) -> Self::State;
31}
32
33pub fn produce_state<T: Clone + 'static>(
38 key: impl Into<String>,
39 producer: impl Fn() -> T + 'static + Clone,
40) -> Rc<Signal<T>> {
41 let key = key.into();
42 remember_with_key(format!("produce:{key}"), || {
43 let out: Signal<T> = signal(producer());
44 let out_clone = out.clone();
45
46 let obs_id = reactive::new_observer({
47 let producer = producer.clone();
48 move || {
49 let v = producer();
50 out_clone.set(v);
51 }
52 });
53
54 reactive::run_observer_now(obs_id);
56
57 scoped_effect(move || {
58 on_unmount(move || {
59 reactive::remove_observer(obs_id);
60 })
61 });
62
63 out
64 })
65}