freya_core/lifecycle/
state.rs1use std::{
2 cell::RefCell,
3 mem::MaybeUninit,
4 ops::Deref,
5 rc::Rc,
6};
7
8use generational_box::GenerationalBox;
9use rustc_hash::FxHashSet;
10
11use crate::{
12 current_context::CurrentContext,
13 prelude::use_hook,
14 reactive_context::ReactiveContext,
15 scope_id::ScopeId,
16};
17
18pub trait MutView<'a, T: 'static> {
19 fn read(&mut self) -> ReadRef<'a, T>;
20
21 fn peek(&mut self) -> ReadRef<'a, T>;
22
23 fn write(&mut self) -> WriteRef<'a, T>;
24
25 fn write_if(&mut self, with: impl FnOnce(WriteRef<'a, T>) -> bool);
26}
27
28impl<T: 'static> MutView<'static, T> for State<T> {
29 fn read(&mut self) -> ReadRef<'static, T> {
30 if let Some(mut rc) = ReactiveContext::try_current() {
31 rc.subscribe(&self.subscribers.read());
32 }
33 self.key.read()
34 }
35
36 fn peek(&mut self) -> ReadRef<'static, T> {
37 self.key.read()
38 }
39
40 fn write(&mut self) -> WriteRef<'static, T> {
41 self.subscribers.write().borrow_mut().retain(|s| s.notify());
42 self.key.write()
43 }
44
45 fn write_if(&mut self, with: impl FnOnce(WriteRef<'static, T>) -> bool) {
46 let chnaged = with(self.key.write());
47 if chnaged {
48 self.subscribers.write().borrow_mut().retain(|s| s.notify());
49 }
50 }
51}
52
53pub struct State<T> {
54 key: GenerationalBox<T>,
55 subscribers: GenerationalBox<Rc<RefCell<FxHashSet<ReactiveContext>>>>,
56}
57
58impl<T: 'static> PartialEq for State<T> {
59 fn eq(&self, other: &Self) -> bool {
60 self.key.ptr_eq(&other.key)
61 }
62}
63
64impl<T: 'static> Eq for State<T> {}
65
66impl<T: Copy + 'static> Deref for State<T> {
69 type Target = dyn Fn() -> T;
70
71 fn deref(&self) -> &Self::Target {
72 unsafe { State::deref_impl(self) }
73 }
74}
75
76impl<T> State<T> {
77 #[doc(hidden)]
82 unsafe fn deref_impl<'a>(state: &State<T>) -> &'a dyn Fn() -> T
83 where
84 Self: Sized + 'a,
85 T: Clone + 'static,
86 {
87 let uninit_callable = MaybeUninit::<Self>::uninit();
91 let uninit_closure = move || Self::read(unsafe { &*uninit_callable.as_ptr() }).clone();
93
94 let size_of_closure = std::mem::size_of_val(&uninit_closure);
96 assert_eq!(size_of_closure, std::mem::size_of::<Self>());
97
98 fn cast_lifetime<'a, T>(_a: &T, b: &'a T) -> &'a T {
100 b
101 }
102 let reference_to_closure = cast_lifetime(
103 {
104 &uninit_closure
106 },
107 #[allow(clippy::missing_transmute_annotations)]
108 unsafe {
110 std::mem::transmute(state)
111 },
112 );
113
114 reference_to_closure as &_
116 }
117}
118
119impl<T: std::ops::Not<Output = T> + Clone + 'static> State<T> {
120 pub fn toggled(&mut self) -> T {
121 let value = self.read().clone();
122 let neg_value = !value;
123 self.set(neg_value.clone());
124 neg_value
125 }
126
127 pub fn toggle(&mut self) {
128 self.toggled();
129 }
130}
131
132type ReadStateFunc<T> = Rc<dyn Fn() -> ReadRef<'static, T>>;
133
134#[derive(Clone)]
136pub enum ReadState<T: 'static> {
137 State(State<T>),
138 Func(ReadStateFunc<T>),
139 Owned(T),
140}
141
142impl<T> From<T> for ReadState<T> {
143 fn from(value: T) -> Self {
144 ReadState::Owned(value)
145 }
146}
147
148impl<T> From<State<T>> for ReadState<T> {
149 fn from(value: State<T>) -> Self {
150 ReadState::State(value)
151 }
152}
153
154impl<T: PartialEq> PartialEq for ReadState<T> {
155 fn eq(&self, other: &ReadState<T>) -> bool {
156 match (self, other) {
157 (Self::State(a), Self::State(b)) => a == b,
158 (Self::Func(a), Self::Func(b)) => Rc::ptr_eq(a, b),
159 (Self::Owned(a), Self::Owned(b)) => a == b,
160 _ => false,
161 }
162 }
163}
164impl<T: 'static> ReadState<T> {
165 pub fn read(&'_ self) -> ReadStateCow<'_, T> {
166 match self {
167 Self::Func(f) => ReadStateCow::Ref(f()),
168 Self::State(s) => ReadStateCow::Ref(s.read()),
169 Self::Owned(o) => ReadStateCow::Borrowed(o),
170 }
171 }
172}
173
174pub enum ReadStateCow<'a, T: 'static> {
175 Ref(ReadRef<'static, T>),
176 Borrowed(&'a T),
177}
178
179impl<'a, T> Deref for ReadStateCow<'a, T> {
180 type Target = T;
181 fn deref(&self) -> &Self::Target {
182 match self {
183 Self::Ref(r) => r.deref(),
184 Self::Borrowed(b) => b,
185 }
186 }
187}
188
189pub type ReadRef<'a, T> =
190 <generational_box::UnsyncStorage as generational_box::AnyStorage>::Ref<'a, T>;
191
192pub type WriteRef<'a, T> =
193 <generational_box::UnsyncStorage as generational_box::AnyStorage>::Mut<'a, T>;
194
195impl<T> State<T> {
196 pub fn read(&self) -> ReadRef<'static, T> {
197 if let Some(mut rc) = ReactiveContext::try_current() {
198 rc.subscribe(&self.subscribers.read());
199 }
200 self.key.read()
201 }
202
203 pub fn peek(&self) -> ReadRef<'static, T> {
204 self.key.read()
205 }
206
207 pub fn write(&mut self) -> WriteRef<'static, T> {
208 self.subscribers.write().borrow_mut().retain(|s| s.notify());
209 self.key.write()
210 }
211
212 pub fn with_mut(&mut self, with: impl FnOnce(WriteRef<'static, T>))
213 where
214 T: 'static,
215 {
216 self.subscribers.write().borrow_mut().retain(|s| s.notify());
217 with(self.key.write());
218 }
219
220 pub fn write_unchecked(&self) -> WriteRef<'static, T> {
221 for subscriber in self.subscribers.write().borrow_mut().iter() {
222 subscriber.notify();
223 }
224 self.key.write()
225 }
226
227 pub fn set(&mut self, value: T)
228 where
229 T: 'static,
230 {
231 *self.write() = value;
232 }
233
234 pub fn set_if_modified(&mut self, value: T)
235 where
236 T: 'static + PartialEq,
237 {
238 let is_equal = *self.peek() == value;
239 if !is_equal {
240 self.set(value);
241 }
242 }
243
244 pub fn set_if_modified_and_then(&mut self, value: T, then: impl FnOnce())
245 where
246 T: 'static + PartialEq,
247 {
248 let is_equal = *self.peek() == value;
249 if !is_equal {
250 self.set(value);
251 then();
252 }
253 }
254
255 pub fn create(value: T) -> Self
256 where
257 T: 'static, {
259 Self::create_in_scope(value, None)
260 }
261
262 pub fn create_in_scope(value: T, scope_id: impl Into<Option<ScopeId>>) -> Self
263 where
264 T: 'static,
265 {
266 let owner = CurrentContext::with(|context| {
268 let scopes_storages = context.scopes_storages.borrow_mut();
269
270 let scopes_storage = scopes_storages.get(&scope_id.into().unwrap_or(context.scope_id));
271 scopes_storage.unwrap().owner.clone()
272 });
273 let key = owner.insert(value);
274 let subscribers = owner.insert(Rc::default());
275 State { key, subscribers }
276 }
277}
278
279impl<T> Clone for State<T> {
280 fn clone(&self) -> Self {
281 *self
282 }
283}
284
285impl<T> Copy for State<T> {}
286
287impl<T> State<Option<T>> {
288 pub fn take(&mut self) -> Option<T>
289 where
290 T: 'static,
291 {
292 self.write().take()
293 }
294}
295
296pub fn use_state<T: 'static>(init: impl FnOnce() -> T) -> State<T> {
297 use_hook(|| State::create(init()))
298}