use std::hash::Hash;
use super::{diff::DiffTree, NodeIDX, Tree};
use crate::path::Path;
impl<N, B> Tree<N, B>
where
N: Clone + Eq,
B: Clone + Eq + Hash,
{
fn diff_rec(
&self,
diff: &mut DiffTree<N, B>,
other: &Tree<N, B>,
idx_d: NodeIDX,
idx_s: NodeIDX,
idx_o: NodeIDX,
) {
let mut branches_o = other.nodes[idx_o].children.clone();
for (branch, &c_idx_s) in &self.nodes[idx_s].children {
if let Some(c_idx_o) = branches_o.remove(branch) {
let value_s = &self.nodes[c_idx_s].value;
let value_o = &other.nodes[c_idx_o].value;
let c_idx_d = diff
.insert_at(
idx_d,
branch.clone(),
if value_s != value_o {
(Some(value_s.clone()), Some(value_o.clone()))
} else {
Default::default()
},
)
.1;
self.diff_rec(diff, other, c_idx_d, c_idx_s, c_idx_o);
} else {
let c_idx_d = diff.insert_at(idx_d, branch.clone(), Default::default()).1;
diff.mirror_subtree_at(self, c_idx_d, c_idx_s, false);
}
}
for (branch, c_idx_o) in branches_o {
let c_idx_d = diff.insert_at(idx_d, branch.clone(), Default::default()).1;
diff.mirror_subtree_at(other, c_idx_d, c_idx_o, true);
}
}
}
impl<N, B> Tree<N, B>
where
N: Clone + Default + Eq,
B: Clone + Default + Eq + Hash,
{
pub fn diff(&mut self, other: &Tree<N, B>) -> DiffTree<N, B> {
let mut diff = DiffTree::new();
if other.nodes.is_empty() {
diff.mirror_subtree(self, &Path::new(), false);
return diff;
}
if self.nodes.is_empty() {
diff.mirror_subtree(other, &Path::new(), true);
return diff;
}
if self.nodes[0].value == other.nodes[0].value {
diff.insert_root((None, None));
} else {
diff.insert_root((
Some(self.nodes[0].value.clone()),
Some(other.nodes[0].value.clone()),
));
}
self.diff_rec(&mut diff, other, 0, 0, 0);
diff
}
pub fn zip(&mut self, other: &Tree<N, B>) -> DiffTree<N, B> {
let mut diff = DiffTree::new();
diff.mirror_subtree(self, &Path::new(), false);
diff.mirror_subtree(other, &Path::new(), true);
diff
}
}