react/use_ref/
use_ref_readonly.rs

1use std::rc::Rc;
2
3use wasm_bindgen::UnwrapThrowExt;
4
5use super::ReadRef;
6
7#[derive(Debug)]
8pub struct ReadRefRc<T: ?Sized>(pub Rc<T>);
9
10impl<T: ?Sized> Clone for ReadRefRc<T> {
11    #[inline]
12    fn clone(&self) -> Self {
13        Self(Rc::clone(&self.0))
14    }
15}
16
17impl<T: ?Sized> PartialEq for ReadRefRc<T> {
18    #[inline]
19    fn eq(&self, other: &Self) -> bool {
20        Rc::ptr_eq(&self.0, &other.0)
21    }
22}
23
24impl<T: ?Sized> Eq for ReadRefRc<T> {}
25
26impl<T: ?Sized> ReadRef<Rc<T>> for ReadRefRc<T> {
27    #[inline]
28    fn current(&self) -> Rc<T> {
29        Rc::clone(&self.0)
30    }
31}
32
33pub fn use_ref_readonly<T: 'static + ?Sized>(initial_rc: Rc<T>) -> ReadRefRc<T> {
34    use_ref_readonly_with(move || initial_rc)
35}
36
37pub fn use_ref_readonly_with<T: 'static + ?Sized, F: FnOnce() -> Rc<T>>(
38    get_initial_rc: F,
39) -> ReadRefRc<T> {
40    let obj = react_sys::use_ref_optional_usize(None);
41
42    let k = obj.current();
43
44    let (k, v) = if let Some(k) = k {
45        let v = unsafe { forgotten::try_get_with_usize::<Rc<T>>(&k) };
46        let v =
47            v.expect_throw("use_ref_readonly ptr is expected to be valid before element unmounted");
48        let v = Rc::clone(v.as_ref());
49        (k, v)
50    } else {
51        let rc: Rc<T> = get_initial_rc();
52        let k = forgotten::forget(Rc::clone(&rc));
53        let k = *k.into_shared().as_usize();
54        obj.set_current(Some(k));
55        (k, rc)
56    };
57
58    // SAFETY: k will never change in the lifetime of the component
59    crate::use_effect_on_mounted(move || {
60        move || {
61            // SAFETY: k is valid and will never change in the lifetime of the component
62            unsafe { forgotten::try_free_with_usize(k) };
63        }
64    });
65
66    ReadRefRc(v)
67}