1use std::{any::Any, collections::HashMap, hash::Hash, ops::Deref, sync::Arc};
2
3use async_channel::{bounded, Sender};
4use async_context::with_async_context_mut;
5
6use crate::{hook::Hook, Element};
7
8pub(crate) struct StateUpdate {
9 update: Box<
10 dyn FnOnce(Option<Arc<dyn Any + Send + Sync>>) -> Arc<dyn Any + Send + Sync>
11 + Send
12 + 'static,
13 >,
14 index: u16,
15}
16
17impl StateUpdate {
18 pub(crate) fn apply(self, state: &mut HashMap<u16, Arc<dyn Any + Send + Sync>>) {
19 let this_state = state.get_mut(&self.index).cloned();
20
21 let update = self.update;
22
23 let new_state = update(this_state);
24
25 state.insert(self.index, new_state);
26 }
27}
28
29#[derive(Clone)]
42pub struct State<T> {
43 value: Arc<T>,
44 signal: Sender<()>,
45 updater: Sender<StateUpdate>,
46 index: u16,
47}
48
49impl<T> Deref for State<T> {
50 type Target = T;
51
52 fn deref(&self) -> &Self::Target {
53 self.value.as_ref()
54 }
55}
56
57impl<T> Hash for State<T> {
58 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
59 Arc::as_ptr(&self.value).hash(state);
60 self.index.hash(state);
61 }
62}
63
64impl<N, E, T> From<State<T>> for Element<N, E>
65where
66 N: From<String>,
67 T: ToString,
68{
69 fn from(value: State<T>) -> Self {
70 let value: &T = &value;
71 Element::Node(N::from(value.to_string()), Vec::new())
72 }
73}
74
75impl<T> State<T>
76where
77 T: Send + Sync + 'static,
78{
79 fn mock(value: T) -> Self {
80 let (mock_signal, _) = bounded(0);
81 let (mock_updater, _) = bounded(0);
82 State {
83 value: Arc::new(value),
84 signal: mock_signal,
85 updater: mock_updater,
86 index: 0,
87 }
88 }
89
90 pub fn update<C, R>(&self, callback: C)
91 where
92 R: Into<Arc<T>>,
93 C: FnOnce(Arc<T>) -> R + Send + Sync + 'static,
94 {
95 let current_value = self.value.clone();
96 self.updater
97 .try_send(StateUpdate {
98 update: Box::new(move |value| {
99 let typed_value = value
100 .map(|value| value.downcast().expect("Invalid state hook"))
101 .unwrap_or(current_value);
102 callback(typed_value).into()
103 }),
104 index: self.index,
105 })
106 .expect("Failed to send update");
107 let _ = self.signal.try_send(());
108 }
109}
110
111pub fn use_state<T, D>(default: D) -> State<T>
115where
116 T: Send + Sync + 'static,
117 D: FnOnce() -> T,
118{
119 with_async_context_mut(|hook: Option<&mut Hook>| {
120 if let Some(hook) = hook {
121 let signal = hook.signal.clone();
122 let updater = hook.updater.clone();
123 let index = hook.state_index;
124 hook.state_index += 1;
125 if let Some(value) = hook.state.get(&index) {
126 let value: Arc<T> = value
127 .clone()
128 .downcast()
129 .expect("Invalid Hook Call: Type mismatch");
130 State {
131 value,
132 signal,
133 updater,
134 index,
135 }
136 } else {
137 let value = Arc::new(default());
138 State {
139 value,
140 signal,
141 updater,
142 index,
143 }
144 }
145 } else {
146 State::mock(default())
147 }
148 })
149}