use mt_dom::*;
use std::fmt::Debug;
type MyNode =
Node<&'static str, &'static str, &'static str, &'static str, &'static str>;
#[derive(Clone, Debug, PartialEq)]
pub struct Zipper {
node: MyNode,
parent: Option<Box<Zipper>>,
index_in_parent: usize,
}
impl Zipper {
pub fn new(node: MyNode) -> Zipper {
Zipper {
node,
parent: None,
index_in_parent: 0,
}
}
pub fn child(mut self, index: usize) -> Option<Zipper> {
if self.node.children().get(index).is_some() {
let child = self.node.swap_remove_child(index);
Some(Zipper {
node: child,
parent: Some(Box::new(self)),
index_in_parent: index,
})
} else {
None
}
}
pub fn parent(self) -> Zipper {
let Zipper {
node,
parent,
index_in_parent,
} = self;
let Zipper {
node: mut parent_node,
parent: parent_parent,
index_in_parent: parent_index_in_parent,
} = *parent.unwrap();
parent_node
.add_children(vec![node])
.expect("add child node");
let len = parent_node.children_count();
parent_node.swap_children(index_in_parent, len - 1);
Zipper {
node: parent_node,
parent: parent_parent,
index_in_parent: parent_index_in_parent,
}
}
pub fn finish(mut self) -> MyNode {
while let Some(_) = self.parent {
self = self.parent();
}
self.node
}
}
fn zipper_traverse_node(node: MyNode, path: &mut Vec<usize>) -> Option<MyNode> {
if path.is_empty() {
Some(node)
} else {
let zipper = Zipper::new(node);
let idx = path.remove(0);
if let Some(child_zipper) = zipper.child(idx) {
zipper_traverse_node(child_zipper.node, path)
} else {
None
}
}
}
fn find_node_by_zipper(node: MyNode, path: &[usize]) -> Option<MyNode> {
let mut path = path.to_vec();
let root_idx = path.remove(0); assert_eq!(0, root_idx, "path must start with 0");
let node = node.clone();
zipper_traverse_node(node, &mut path)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::*;
fn sample_node() -> MyNode {
let node: MyNode = element(
"div",
vec![attr("class", "[0]"), attr("id", "0")],
vec![
element(
"div",
vec![attr("class", "[0,0]"), attr("id", "1")],
vec![
element(
"div",
vec![attr("class", "[0,0,0]"), attr("id", "2")],
vec![],
),
element(
"div",
vec![attr("class", "[0,0,1]"), attr("id", "3")],
vec![],
),
],
),
element(
"div",
vec![attr("class", "[0,1]"), attr("id", "4")],
vec![
element(
"div",
vec![attr("class", "[0,1,0]"), attr("id", "5")],
vec![],
),
element(
"div",
vec![attr("class", "[0,1,1]"), attr("id", "6")],
vec![],
),
element(
"div",
vec![attr("class", "[0,1,2]"), attr("id", "7")],
vec![],
),
],
),
],
);
node
}
#[test]
fn should_traverse_correctly() {
let node = sample_node();
let expected = element(
"div",
vec![attr("class", "[0,0]"), attr("id", "1")],
vec![
element(
"div",
vec![attr("class", "[0,0,0]"), attr("id", "2")],
vec![],
),
element(
"div",
vec![attr("class", "[0,0,1]"), attr("id", "3")],
vec![],
),
],
);
assert_eq!(Some(expected), find_node_by_zipper(node, &[0, 0]));
}
#[test]
fn should_find_root_node() {
let node = sample_node();
let root = find_node_by_zipper(node.clone(), &[0]);
dbg!(&root);
assert_eq!(Some(node), root);
}
#[test]
fn should_find_node1() {
let node = sample_node();
let found = find_node_by_zipper(node, &[0, 0]);
dbg!(&found);
let expected = element(
"div",
vec![attr("class", "[0,0]"), attr("id", "1")],
vec![
element(
"div",
vec![attr("class", "[0,0,0]"), attr("id", "2")],
vec![],
),
element(
"div",
vec![attr("class", "[0,0,1]"), attr("id", "3")],
vec![],
),
],
);
assert_eq!(Some(expected), found);
}
#[test]
fn should_find_node2() {
let node = sample_node();
let found = find_node_by_zipper(node, &[0, 0, 0]);
dbg!(&found);
let expected = element(
"div",
vec![attr("class", "[0,0,0]"), attr("id", "2")],
vec![],
);
assert_eq!(Some(expected), found);
}
#[test]
fn should_find_node3() {
let node = sample_node();
let found = find_node_by_zipper(node, &[0, 0, 1]);
dbg!(&found);
let expected = element(
"div",
vec![attr("class", "[0,0,1]"), attr("id", "3")],
vec![],
);
assert_eq!(Some(expected), found);
}
#[test]
fn should_find_node4() {
let node = sample_node();
let node4 = find_node_by_zipper(node, &[0, 1]);
dbg!(&node4);
let expected = element(
"div",
vec![attr("class", "[0,1]"), attr("id", "4")],
vec![
element(
"div",
vec![attr("class", "[0,1,0]"), attr("id", "5")],
vec![],
),
element(
"div",
vec![attr("class", "[0,1,1]"), attr("id", "6")],
vec![],
),
element(
"div",
vec![attr("class", "[0,1,2]"), attr("id", "7")],
vec![],
),
],
);
assert_eq!(Some(expected), node4);
}
#[test]
fn should_find_node5() {
let node = sample_node();
let node5 = find_node_by_zipper(node, &[0, 1, 0]);
dbg!(&node5);
let expected = element(
"div",
vec![attr("class", "[0,1,0]"), attr("id", "5")],
vec![],
);
assert_eq!(Some(expected), node5);
}
#[test]
fn should_find_node6() {
let node = sample_node();
let node6 = find_node_by_zipper(node, &[0, 1, 1]);
dbg!(&node6);
let expected = element(
"div",
vec![attr("class", "[0,1,1]"), attr("id", "6")],
vec![],
);
assert_eq!(Some(expected), node6);
}
#[test]
fn should_find_node7() {
let node = sample_node();
let node7 = find_node_by_zipper(node, &[0, 1, 2]);
dbg!(&node7);
let expected = element(
"div",
vec![attr("class", "[0,1,2]"), attr("id", "7")],
vec![],
);
assert_eq!(Some(expected), node7);
}
#[test]
fn should_find_none_in_013() {
let node = sample_node();
let found = find_node_by_zipper(node, &[0, 1, 3]);
dbg!(&found);
assert_eq!(None, found);
}
#[test]
fn should_find_none_in_00000() {
let node = sample_node();
let found = find_node_by_zipper(node, &[0, 0, 0, 0]);
dbg!(&found);
assert_eq!(None, found);
}
#[test]
fn should_find_none_007() {
let node = sample_node();
assert_eq!(None, find_node_by_zipper(node, &[0, 0, 7]));
}
}