Skip to main content

gpui_hooks/hooks/
use_ref.rs

1use super::Hook;
2use std::any::Any;
3use std::cell::RefCell;
4use std::rc::Rc;
5
6/// UseRef hook - maintains a mutable reference to a value
7pub struct UseRef<T: 'static> {
8    current: Rc<RefCell<T>>,
9}
10
11impl<T: 'static> UseRef<T> {
12    pub fn new(initial: T) -> Self {
13        Self {
14            current: Rc::new(RefCell::new(initial)),
15        }
16    }
17
18    /// Get a clone of the Rc<RefCell<T>>
19    pub fn get_ref(&self) -> Rc<RefCell<T>> {
20        self.current.clone()
21    }
22}
23
24impl<T: 'static> Hook for UseRef<T> {
25    fn as_any(&self) -> &dyn Any {
26        self
27    }
28    fn as_any_mut(&mut self) -> &mut dyn Any {
29        self
30    }
31}
32
33/// Trait for using ref hooks
34///
35/// This trait is automatically implemented for any type that implements `HasHooks`
36/// (which includes all types using `#[hook_element]`).
37pub trait UseRefHook {
38    /// Get access to the hooks storage (internal use)
39    fn _hooks_ref(&self) -> &RefCell<Vec<Box<dyn Hook>>>;
40
41    /// Get and increment the hook index (internal use)
42    fn _next_hook_index(&self) -> usize;
43
44    /// Use a ref hook
45    /// Returns a shared reference to the mutable value
46    fn use_ref<T, F>(&self, initial: F) -> Rc<RefCell<T>>
47    where
48        T: 'static,
49        F: FnOnce() -> T,
50    {
51        let idx = self._next_hook_index();
52        let hooks_ref = self._hooks_ref();
53
54        // Create hook if it doesn't exist
55        let hooks_len = hooks_ref.borrow().len();
56        if idx >= hooks_len {
57            let hook = UseRef::new(initial());
58            hooks_ref.borrow_mut().push(Box::new(hook));
59        }
60
61        // Get the raw pointer to the hook - it will be stable after creation
62        let hook_ptr: *const dyn Hook = {
63            let hooks = hooks_ref.borrow();
64            let hook = hooks.get(idx).expect("Hook index out of bounds");
65            hook.as_ref() as *const dyn Hook
66        };
67
68        // Get a clone of the Rc<RefCell<T>> from the hook
69        unsafe {
70            let ref_hook = &*(hook_ptr as *const UseRef<T>);
71            ref_hook.get_ref()
72        }
73    }
74}