1use std::{
2 any::Any,
3 cell::RefCell,
4 rc::{Rc, Weak},
5};
6
7use super::{RuntimeHandle, StateHandleLease};
8use crate::{
9 MutableStateInner, ScopeId,
10 collections::map::HashMap,
11 state::{MutationPolicy, NeverEqual},
12};
13
14struct TypedStateCell<T: Clone + 'static> {
15 inner: MutableStateInner<T>,
16}
17
18trait ScopeWatchCell {
19 fn unregister_scope(&self, scope_id: ScopeId);
20 fn forget_scope(&self, scope_id: ScopeId);
21 fn invalidate_watchers(&self);
22}
23
24impl<T: Clone + 'static> ScopeWatchCell for TypedStateCell<T> {
25 fn unregister_scope(&self, scope_id: ScopeId) {
26 self.inner.unregister_scope(scope_id);
27 }
28
29 fn forget_scope(&self, scope_id: ScopeId) {
30 self.inner.forget_scope(scope_id);
31 }
32
33 fn invalidate_watchers(&self) {
34 self.inner.invalidate_watchers();
35 }
36}
37
38struct StateArenaSlot {
39 generation: u32,
40 cell: Option<Rc<dyn Any>>,
41 watcher_cell: Option<Rc<dyn ScopeWatchCell>>,
42 lease: Option<Weak<StateHandleLease>>,
43}
44
45#[derive(Default)]
46struct StateArenaInner {
47 cells: Vec<StateArenaSlot>,
48 free: Vec<u32>,
49 derived: HashMap<u32, Weak<dyn DerivedRefresh>>,
51}
52
53pub(crate) trait DerivedRefresh {
55 fn refresh(&self);
58}
59
60#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
63pub struct StateArenaDebugStats {
64 pub cells_len: usize,
66 pub cells_cap: usize,
68 pub free_len: usize,
70 pub free_cap: usize,
72}
73
74#[derive(Default)]
75pub(crate) struct StateArena {
76 inner: RefCell<StateArenaInner>,
77}
78
79impl StateArena {
80 pub(crate) fn alloc<T: Clone + 'static>(&self, value: T, runtime: RuntimeHandle) -> StateId {
81 self.alloc_with_policy(value, runtime, Rc::new(NeverEqual))
82 }
83
84 fn claim_slot(&self) -> StateId {
86 let mut inner = self.inner.borrow_mut();
87 loop {
88 let Some(slot) = inner.free.pop() else {
89 let slot = inner.cells.len() as u32;
90 inner.cells.push(StateArenaSlot {
91 generation: 0,
92 cell: None,
93 watcher_cell: None,
94 lease: None,
95 });
96 return StateId::new(slot, 0);
97 };
98
99 let Some(entry) = inner.cells.get_mut(slot as usize) else {
100 continue;
101 };
102 if entry.cell.is_some() {
103 continue;
104 }
105
106 entry.watcher_cell = None;
107 entry.lease = None;
108 entry.generation = entry.generation.wrapping_add(1);
109 return StateId::new(slot, entry.generation);
110 }
111 }
112
113 pub(crate) fn alloc_with_policy<T: Clone + 'static>(
114 &self,
115 value: T,
116 runtime: RuntimeHandle,
117 policy: Rc<dyn MutationPolicy<T>>,
118 ) -> StateId {
119 let id = self.claim_slot();
120 let slot = id.slot();
121 let inner = MutableStateInner::new_with_policy(value, runtime, policy);
122 inner.install_snapshot_observer(id);
123 let typed_cell = Rc::new(TypedStateCell { inner });
124 let cell: Rc<dyn Any> = Rc::<TypedStateCell<T>>::clone(&typed_cell);
125 let watcher_cell: Rc<dyn ScopeWatchCell> = typed_cell;
126 let mut arena = self.inner.borrow_mut();
127 let slot_entry = &mut arena.cells[slot as usize];
128 slot_entry.cell = Some(cell);
129 slot_entry.watcher_cell = Some(watcher_cell);
130 id
131 }
132
133 pub(crate) fn alloc_plain<T: 'static>(&self, value: T) -> StateId {
136 let id = self.claim_slot();
137 let cell: Rc<dyn Any> = Rc::new(value);
138 self.inner.borrow_mut().cells[id.slot_index()].cell = Some(cell);
139 id
140 }
141
142 pub(crate) fn plain<T: 'static>(&self, id: StateId) -> Option<Rc<T>> {
144 Rc::downcast::<T>(self.get_cell_opt(id)?).ok()
145 }
146
147 fn get_cell_opt(&self, id: StateId) -> Option<Rc<dyn Any>> {
148 self.inner
149 .borrow()
150 .cells
151 .get(id.slot_index())
152 .filter(|cell| cell.generation == id.generation())
153 .and_then(|cell| cell.cell.as_ref())
154 .cloned()
155 }
156
157 fn get_typed<T: Clone + 'static>(&self, id: StateId) -> Rc<TypedStateCell<T>> {
158 match self.get_cell_opt(id) {
159 None => panic!(
160 "state cell missing: slot={}, gen={}, expected={}",
161 id.slot(),
162 id.generation(),
163 std::any::type_name::<T>(),
164 ),
165 Some(cell) => Rc::downcast::<TypedStateCell<T>>(cell).unwrap_or_else(|_| {
166 panic!(
167 "state cell type mismatch: slot={}, gen={}, expected={}",
168 id.slot(),
169 id.generation(),
170 std::any::type_name::<T>(),
171 )
172 }),
173 }
174 }
175
176 fn get_typed_opt<T: Clone + 'static>(&self, id: StateId) -> Option<Rc<TypedStateCell<T>>> {
177 Rc::downcast::<TypedStateCell<T>>(self.get_cell_opt(id)?).ok()
178 }
179
180 pub(crate) fn with_typed<T: Clone + 'static, R>(
181 &self,
182 id: StateId,
183 f: impl FnOnce(&MutableStateInner<T>) -> R,
184 ) -> R {
185 let cell = self.get_typed::<T>(id);
186 f(&cell.inner)
187 }
188
189 pub(crate) fn with_typed_opt<T: Clone + 'static, R>(
190 &self,
191 id: StateId,
192 f: impl FnOnce(&MutableStateInner<T>) -> R,
193 ) -> Option<R> {
194 let cell = self.get_typed_opt::<T>(id)?;
195 Some(f(&cell.inner))
196 }
197
198 pub(crate) fn release(&self, id: StateId) {
199 let cell = {
200 let mut inner = self.inner.borrow_mut();
201 let Some(slot) = inner.cells.get_mut(id.slot_index()) else {
202 return;
203 };
204 if slot.generation != id.generation() {
205 return;
206 }
207 slot.lease = None;
208 slot.watcher_cell = None;
209 let cell = slot.cell.take();
210 if cell.is_some() {
211 inner.free.push(id.slot());
212 if !inner.derived.is_empty() {
213 inner.derived.remove(&id.slot());
214 }
215 }
216 cell
217 };
218 drop(cell);
219 }
220
221 pub(crate) fn register_derived(&self, id: StateId, refresh: Weak<dyn DerivedRefresh>) {
224 self.inner.borrow_mut().derived.insert(id.slot(), refresh);
225 }
226
227 #[cold]
230 pub(crate) fn refresh_derived(&self, id: StateId) {
231 let refresh = {
232 let inner = self.inner.borrow();
233 inner
234 .cells
235 .get(id.slot_index())
236 .filter(|cell| cell.generation == id.generation())
237 .and_then(|_| inner.derived.get(&id.slot()))
238 .and_then(Weak::upgrade)
239 };
240 if let Some(refresh) = refresh {
241 refresh.refresh();
242 }
243 }
244
245 pub(crate) fn stats(&self) -> (usize, usize) {
246 let inner = self.inner.borrow();
247 (inner.cells.len(), inner.free.len())
248 }
249
250 pub(crate) fn debug_stats(&self) -> StateArenaDebugStats {
251 let inner = self.inner.borrow();
252 StateArenaDebugStats {
253 cells_len: inner.cells.len(),
254 cells_cap: inner.cells.capacity(),
255 free_len: inner.free.len(),
256 free_cap: inner.free.capacity(),
257 }
258 }
259
260 pub(crate) fn unregister_scope(&self, id: StateId, scope_id: ScopeId) {
261 if let Some(watcher_cell) = self.watcher_cell(id) {
262 watcher_cell.unregister_scope(scope_id);
263 }
264 }
265
266 pub(crate) fn forget_scope(&self, id: StateId, scope_id: ScopeId) {
268 if let Some(watcher_cell) = self.watcher_cell(id) {
269 watcher_cell.forget_scope(scope_id);
270 }
271 }
272
273 pub(crate) fn invalidate_watchers(&self, id: StateId) {
275 if let Some(watcher_cell) = self.watcher_cell(id) {
276 watcher_cell.invalidate_watchers();
277 }
278 }
279
280 fn watcher_cell(&self, id: StateId) -> Option<Rc<dyn ScopeWatchCell>> {
281 let inner = self.inner.borrow();
282 inner
283 .cells
284 .get(id.slot_index())
285 .filter(|slot| slot.generation == id.generation())
286 .and_then(|slot| slot.watcher_cell.as_ref())
287 .cloned()
288 }
289
290 pub(crate) fn register_lease(&self, id: StateId, lease: &Rc<StateHandleLease>) {
291 let mut inner = self.inner.borrow_mut();
292 let Some(slot) = inner.cells.get_mut(id.slot_index()) else {
293 return;
294 };
295 if slot.generation != id.generation() {
296 return;
297 }
298 slot.lease = Some(Rc::downgrade(lease));
299 }
300
301 pub(crate) fn retain_lease(&self, id: StateId) -> Option<Rc<StateHandleLease>> {
302 let inner = self.inner.borrow();
303 let slot = inner.cells.get(id.slot_index())?;
304 if slot.generation != id.generation() {
305 return None;
306 }
307 slot.lease.as_ref()?.upgrade()
308 }
309}
310
311#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
313pub struct StateId {
314 slot: u32,
315 generation: u32,
316}
317
318impl StateId {
319 const fn new(slot: u32, generation: u32) -> Self {
320 Self { slot, generation }
321 }
322
323 pub(crate) const fn slot(self) -> u32 {
324 self.slot
325 }
326
327 pub(crate) const fn slot_index(self) -> usize {
328 self.slot as usize
329 }
330
331 pub(crate) const fn generation(self) -> u32 {
332 self.generation
333 }
334}
335
336#[cfg(test)]
337#[path = "tests/state_arena_tests.rs"]
338mod tests;