Skip to content

Commit

Permalink
Make sure there are no node reference loops
Browse files Browse the repository at this point in the history
  • Loading branch information
mihna123 committed Sep 28, 2023
1 parent b415f94 commit e98d043
Showing 1 changed file with 71 additions and 0 deletions.
71 changes: 71 additions & 0 deletions src/html5_parser/node_arena.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ impl NodeArena {

/// Add the node as a child the parent node
pub fn attach_node(&mut self, parent_id: usize, node_id: usize) {
//check if any children of node have parent as child
if parent_id == node_id || has_child_recursive(self,node_id,parent_id){
return;
}
if let Some(parent_node) = self.nodes.get_mut(&parent_id) {
parent_node.children.push(node_id);
}
Expand Down Expand Up @@ -64,6 +68,46 @@ impl NodeArena {
}
}

fn has_child_recursive(arena: &mut NodeArena, parent_id: usize, child_id: usize) -> bool {
let node = arena.get_mut_node(parent_id).cloned();
if node.is_none(){
return false;
}
let node = node.unwrap();
for id in node.children.iter() {
if *id == child_id {
return true;
}
let child = arena.get_mut_node(*id).cloned();
if has_child(arena, child, child_id){
return true;
}
}
return false;
}

fn has_child(arena: &mut NodeArena, parent: Option<Node>, child_id: usize) -> bool {
let parent_node;
if parent.is_some(){
parent_node = parent.unwrap();
}
else {
return false; } if parent_node.children.len() == 0 {
return false;
}

for id in parent_node.children {
if id == child_id {
return true;
}
let node = arena.get_mut_node(id).cloned();
if has_child(arena, node, child_id){
return true;
}
}
return false;
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -116,6 +160,33 @@ mod tests {
assert_eq!(child.unwrap().parent, Some(parent_id));
}

#[test]
fn test_attach_node_to_itself(){
let mut arena = NodeArena::new();
let node = Node::new_element("some_node", HashMap::new(), HTML_NAMESPACE);
let node_id = arena.add_node(node);
arena.attach_node(node_id, node_id);
let node = arena.get_node(node_id);
assert!(node.is_some());
assert_eq!(node.unwrap().children.len(), 0);
}

#[test]
fn test_attach_node_with_loop_pointer(){
let mut arena = NodeArena::new();
let parent = Node::new_element("parent", HashMap::new(), HTML_NAMESPACE);
let mut child = Node::new_element("child", HashMap::new(), HTML_NAMESPACE);
let parent_id = arena.add_node(parent);
child.children.push(parent_id);
let child_id = arena.add_node(child);
arena.attach_node(parent_id, child_id);
let parent = arena.get_node(parent_id);
let child = arena.get_node(child_id);
assert!(parent.is_some());
assert!(child.is_some());
assert_eq!(parent.unwrap().children.len(), 0);
}

#[test]
fn test_remove_node() {
let mut arena = NodeArena::new();
Expand Down

0 comments on commit e98d043

Please sign in to comment.