gpui_hooks/hooks/
use_state.rs1use super::Hook;
2use std::any::Any;
3use std::cell::{Ref, RefCell, RefMut};
4
5type UseStateResult<T> = (Box<dyn Fn() -> T>, Box<dyn Fn(T)>);
7
8pub struct UseState<T: 'static> {
10 value: RefCell<T>,
11 version: RefCell<usize>,
12}
13
14impl<T: 'static> UseState<T> {
15 pub fn new(initial: T) -> Self {
16 Self {
17 value: RefCell::new(initial),
18 version: RefCell::new(0),
19 }
20 }
21
22 pub fn get(&self) -> Ref<'_, T> {
24 self.value.borrow()
25 }
26
27 pub fn get_mut(&self) -> RefMut<'_, T> {
29 self.value.borrow_mut()
30 }
31
32 pub fn set(&self, new_value: T) {
34 *self.value.borrow_mut() = new_value;
35 *self.version.borrow_mut() += 1;
36 }
37
38 pub fn version(&self) -> usize {
40 *self.version.borrow()
41 }
42}
43
44impl<T: 'static> Hook for UseState<T> {
45 fn as_any(&self) -> &dyn Any {
46 self
47 }
48 fn as_any_mut(&mut self) -> &mut dyn Any {
49 self
50 }
51}
52
53pub trait UseStateHook {
58 fn _hooks_ref(&self) -> &RefCell<Vec<Box<dyn Hook>>>;
60
61 fn _next_hook_index(&self) -> usize;
63
64 fn use_state<T, F>(&self, initial: F) -> UseStateResult<T>
67 where
68 T: Clone + 'static,
69 F: FnOnce() -> T,
70 {
71 let idx = self._next_hook_index();
72 let hooks_ref = self._hooks_ref();
73
74 let hooks_len = hooks_ref.borrow().len();
76 if idx >= hooks_len {
77 let state = UseState::new(initial());
78 hooks_ref.borrow_mut().push(Box::new(state));
79 }
80
81 let hook_ptr: *const dyn Hook = {
83 let hooks = hooks_ref.borrow();
84 let hook = hooks.get(idx).expect("Hook index out of bounds");
85 hook.as_ref() as *const dyn Hook
86 };
87
88 let getter: Box<dyn Fn() -> T> = {
90 let state_ptr = hook_ptr as *const UseState<T>;
91 Box::new(move || unsafe { (*state_ptr).get().clone() })
92 };
93
94 let setter: Box<dyn Fn(T)> = {
96 let state_ptr = hook_ptr as *const UseState<T>;
97 Box::new(move |new_value: T| unsafe {
98 (*state_ptr).set(new_value);
99 })
100 };
101
102 (getter, setter)
103 }
104}