mod classes;
mod component;
mod conversion;
mod listener;
pub use classes::*;
pub use component::*;
pub use conversion::*;
pub use listener::*;
use crate::virtual_dom::VNode;
use cfg_if::cfg_if;
use cfg_match::cfg_match;
use std::cell::RefCell;
use std::rc::Rc;
cfg_if! {
if #[cfg(feature = "std_web")] {
use stdweb::unstable::TryFrom;
use stdweb::web::Node;
} else if #[cfg(feature = "web_sys")] {
use wasm_bindgen::JsValue;
use web_sys::Node;
}
}
pub type Html = VNode;
#[derive(Debug, Default, Clone)]
pub struct NodeRef(Rc<RefCell<NodeRefInner>>);
impl PartialEq for NodeRef {
fn eq(&self, other: &Self) -> bool {
self.0.as_ptr() == other.0.as_ptr() || Some(self) == other.0.borrow().link.as_ref()
}
}
#[derive(PartialEq, Debug, Default, Clone)]
struct NodeRefInner {
node: Option<Node>,
link: Option<NodeRef>,
}
impl NodeRef {
pub fn get(&self) -> Option<Node> {
let inner = self.0.borrow();
inner.node.clone().or_else(|| inner.link.as_ref()?.get())
}
pub fn cast<
#[cfg(feature = "std_web")] INTO: TryFrom<Node>,
#[cfg(feature = "web_sys")] INTO: AsRef<Node> + From<JsValue>,
>(
&self,
) -> Option<INTO> {
let node = self.get();
cfg_match! {
feature = "std_web" => node.and_then(|node| INTO::try_from(node).ok()),
feature = "web_sys" => node.map(Into::into).map(INTO::from),
}
}
pub(crate) fn new(node: Node) -> Self {
let node_ref = NodeRef::default();
node_ref.set(Some(node));
node_ref
}
pub(crate) fn set(&self, node: Option<Node>) {
let mut this = self.0.borrow_mut();
this.node = node;
this.link = None;
}
pub(crate) fn link(&self, node_ref: Self) {
if self == &node_ref {
return;
}
let mut this = self.0.borrow_mut();
this.node = None;
this.link = Some(node_ref);
}
pub(crate) fn reuse(&self, node_ref: Self) {
if self == &node_ref {
return;
}
let mut this = self.0.borrow_mut();
let existing = node_ref.0.borrow();
this.node = existing.node.clone();
this.link = existing.link.clone();
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::utils::document;
#[cfg(feature = "wasm_test")]
use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};
#[cfg(feature = "wasm_test")]
wasm_bindgen_test_configure!(run_in_browser);
#[test]
fn self_linking_node_ref() {
let node: Node = document().create_text_node("test node").into();
let node_ref = NodeRef::new(node.clone());
let node_ref_2 = NodeRef::new(node.clone());
node_ref.link(node_ref.clone());
assert_eq!(node, node_ref.get().unwrap());
node_ref.link(node_ref_2.clone());
node_ref_2.link(node_ref);
assert_eq!(node, node_ref_2.get().unwrap());
}
}