Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get NodeId for DomNode lazily (only when getting Hash for DomNode) #136

Merged
merged 2 commits into from
Jun 30, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 32 additions & 14 deletions packages/sycamore/src/generic_node/dom_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ use crate::template::Template;
// TODO: remove js snippet
#[wasm_bindgen(inline_js = "\
export function set_node_id(node, id) {\
node.__sycamoreNodeId = id\
node.$$$nodeId = id\
}\
export function get_node_id(node) {\
return node.__sycamoreNodeId\
return node.$$$nodeId\
}\
")]
extern "C" {
Expand All @@ -29,12 +29,18 @@ extern "C" {
}

/// An unique id for every node.
#[derive(Clone, PartialEq, Eq, Hash)]
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
struct NodeId(usize);

impl Default for NodeId {
fn default() -> Self {
Self(0)
}
}

impl NodeId {
fn new_with_node(node: &Node) -> Self {
thread_local!(static NODE_ID_COUNTER: Cell<usize> = Cell::new(0));
thread_local!(static NODE_ID_COUNTER: Cell<usize> = Cell::new(1)); // 0 is reserved for default value.

let id = NODE_ID_COUNTER.with(|x| {
let tmp = x.get();
Expand All @@ -51,7 +57,7 @@ impl NodeId {
/// _This API requires the following crate features to be activated: `dom`_
#[derive(Clone)]
pub struct DomNode {
id: NodeId,
id: Cell<NodeId>,
node: Rc<Node>,
}

Expand All @@ -63,19 +69,31 @@ impl DomNode {
pub fn unchecked_into<T: JsCast>(self) -> T {
(*self.node).clone().unchecked_into()
}

fn get_node_id(&self) -> NodeId {
if self.id.get().0 == 0 {
// self.id not yet initialized.
if let Some(id) = get_node_id(&self.node) {
self.id.set(NodeId(id));
} else {
self.id.set(NodeId::new_with_node(&self.node));
}
}
self.id.get()
}
}

impl PartialEq for DomNode {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
self.node == other.node
}
}

impl Eq for DomNode {}

impl Hash for DomNode {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state);
self.get_node_id().hash(state);
}
}

Expand Down Expand Up @@ -121,23 +139,23 @@ impl GenericNode for DomNode {
.unwrap(),
);
DomNode {
id: NodeId::new_with_node(&node),
id: Default::default(),
node,
}
}

fn text_node(text: &str) -> Self {
let node = Rc::new(document().create_text_node(text).into());
DomNode {
id: NodeId::new_with_node(&node),
id: Default::default(),
node,
}
}

fn marker() -> Self {
let node = Rc::new(document().create_comment("").into());
DomNode {
id: NodeId::new_with_node(&node),
id: Default::default(),
node,
}
}
Expand Down Expand Up @@ -180,14 +198,14 @@ impl GenericNode for DomNode {

fn parent_node(&self) -> Option<Self> {
self.node.parent_node().map(|node| Self {
id: NodeId(get_node_id(&node).unwrap()),
id: Default::default(),
node: Rc::new(node),
})
}

fn next_sibling(&self) -> Option<Self> {
self.node.next_sibling().map(|node| Self {
id: NodeId(get_node_id(&node).unwrap()),
id: Default::default(),
node: Rc::new(node),
})
}
Expand Down Expand Up @@ -231,7 +249,7 @@ pub fn render_to(template: impl FnOnce() -> Template<DomNode>, parent: &Node) {
let scope = create_root(|| {
insert(
&DomNode {
id: NodeId::new_with_node(parent),
id: Default::default(),
node: Rc::new(parent.clone()),
},
template(),
Expand Down Expand Up @@ -296,7 +314,7 @@ pub fn hydrate_to(template: impl FnOnce() -> Template<DomNode>, parent: &Node) {
let scope = create_root(|| {
insert(
&DomNode {
id: NodeId::new_with_node(&parent),
id: Default::default(),
node: Rc::new(parent.clone()),
},
template(),
Expand Down