bloom_html/
dom_ref.rs

1use std::{
2    cell::RefCell,
3    collections::HashMap,
4    hash::Hash,
5    ptr,
6    sync::atomic::{AtomicU16, Ordering},
7};
8
9/// Represents a reference to a DOM element.
10/// Obtain this via
11/// ```
12/// use_ref::<DomRef>();
13/// ```
14#[derive(Debug, Default)]
15pub struct DomRef(AtomicU16);
16
17thread_local! {
18    static HTML_ELEMENT_MAP: RefCell<HashMap<u16, web_sys::Node>> = RefCell::new(HashMap::new());
19}
20
21impl DomRef {
22    pub fn set(&self, element: web_sys::Node) {
23        HTML_ELEMENT_MAP.with(|map| {
24            let mut map = map.borrow_mut();
25            let current_key = self.0.load(Ordering::Relaxed);
26            let key = if current_key != 0 {
27                current_key
28            } else {
29                let mut key = 1;
30                while map.contains_key(&key) {
31                    key += 1;
32                    if key == u16::MAX {
33                        panic!("Element Map Overflow");
34                    }
35                }
36                self.0.store(key, Ordering::Relaxed);
37                key
38            };
39            map.insert(key, element);
40        });
41    }
42
43    /// use this method in an effect to get the actual DOM element:
44    /// ```
45    /// let my_ref = use_ref::<DomRef>();
46    /// use_effect(my_ref, |my_ref| {
47    ///     let dom_element = my_ref.get();
48    ///     // do something with dom_element
49    /// })
50    /// ```
51    pub fn get(&self) -> Option<web_sys::Node> {
52        HTML_ELEMENT_MAP.with(|map| {
53            map.borrow()
54                .get(&self.0.load(Ordering::Relaxed))
55                .map(|element| element.clone())
56        })
57    }
58}
59
60impl Drop for DomRef {
61    fn drop(&mut self) {
62        HTML_ELEMENT_MAP.with(|map| {
63            map.borrow_mut().remove(&self.0.load(Ordering::Relaxed));
64        });
65    }
66}
67
68impl Hash for DomRef {
69    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
70        self.0.load(Ordering::Relaxed).hash(state);
71    }
72}
73
74impl PartialEq for DomRef {
75    fn eq(&self, other: &Self) -> bool {
76        ptr::addr_eq(self.0.as_ptr(), other.0.as_ptr())
77    }
78}