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