1mod classes;
4mod component;
5mod conversion;
6mod listener;
7
8pub use classes::*;
9pub use component::*;
10pub use conversion::*;
11pub use listener::*;
12
13use crate::virtual_dom::VNode;
14use cfg_if::cfg_if;
15use cfg_match::cfg_match;
16use std::cell::RefCell;
17use std::rc::Rc;
18cfg_if! {
19 if #[cfg(feature = "std_web")] {
20 use stdweb::unstable::TryFrom;
21 use stdweb::web::Node;
22 } else if #[cfg(feature = "web_sys")] {
23 use wasm_bindgen::JsValue;
24 use web_sys::Node;
25 }
26}
27
28pub type Html = VNode;
30
31#[derive(Debug, Default, Clone)]
82pub struct NodeRef(Rc<RefCell<NodeRefInner>>);
83
84impl PartialEq for NodeRef {
85 fn eq(&self, other: &Self) -> bool {
86 self.0.as_ptr() == other.0.as_ptr() || Some(self) == other.0.borrow().link.as_ref()
87 }
88}
89
90#[derive(PartialEq, Debug, Default, Clone)]
91struct NodeRefInner {
92 node: Option<Node>,
93 link: Option<NodeRef>,
94}
95
96impl NodeRef {
97 pub fn get(&self) -> Option<Node> {
99 let inner = self.0.borrow();
100 inner.node.clone().or_else(|| inner.link.as_ref()?.get())
101 }
102
103 pub fn cast<
105 #[cfg(feature = "std_web")] INTO: TryFrom<Node>,
106 #[cfg(feature = "web_sys")] INTO: AsRef<Node> + From<JsValue>,
107 >(
108 &self,
109 ) -> Option<INTO> {
110 let node = self.get();
111 cfg_match! {
112 feature = "std_web" => node.and_then(|node| INTO::try_from(node).ok()),
113 feature = "web_sys" => node.map(Into::into).map(INTO::from),
114 }
115 }
116
117 pub(crate) fn new(node: Node) -> Self {
119 let node_ref = NodeRef::default();
120 node_ref.set(Some(node));
121 node_ref
122 }
123
124 pub(crate) fn set(&self, node: Option<Node>) {
126 let mut this = self.0.borrow_mut();
127 this.node = node;
128 this.link = None;
129 }
130
131 pub(crate) fn link(&self, node_ref: Self) {
133 if self == &node_ref {
135 return;
136 }
137
138 let mut this = self.0.borrow_mut();
139 this.node = None;
140 this.link = Some(node_ref);
141 }
142
143 pub(crate) fn reuse(&self, node_ref: Self) {
145 if self == &node_ref {
147 return;
148 }
149
150 let mut this = self.0.borrow_mut();
151 let existing = node_ref.0.borrow();
152 this.node = existing.node.clone();
153 this.link = existing.link.clone();
154 }
155}
156
157#[cfg(test)]
158mod tests {
159 use super::*;
160 use crate::utils::document;
161
162 #[cfg(feature = "wasm_test")]
163 use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};
164
165 #[cfg(feature = "wasm_test")]
166 wasm_bindgen_test_configure!(run_in_browser);
167
168 #[test]
169 fn self_linking_node_ref() {
170 let node: Node = document().create_text_node("test node").into();
171 let node_ref = NodeRef::new(node.clone());
172 let node_ref_2 = NodeRef::new(node.clone());
173
174 node_ref.link(node_ref.clone());
176 assert_eq!(node, node_ref.get().unwrap());
177
178 node_ref.link(node_ref_2.clone());
180 node_ref_2.link(node_ref);
181 assert_eq!(node, node_ref_2.get().unwrap());
182 }
183}