use crate::node::{is_null_node_ref, is_wrapper_node, Node};
use crate::{NodeRef, VoteReference};
use std::collections::VecDeque;
use std::sync::Arc;
pub type VoteReferencePair = (Option<VoteReference>, Option<VoteReference>);
pub fn find_down_right_most_branch(node: &NodeRef) -> Option<Vec<NodeRef>> {
if node.is_none() {
return None;
}
if is_null_node_ref(node) {
return None;
}
let node_ref = node.as_ref().unwrap();
let node_vec = vec![node.clone()];
if is_wrapper_node(&node_ref.left) {
return Some(node_vec);
}
if is_null_node_ref(&node_ref.right) {
return match find_down_right_most_branch(&node_ref.left) {
Some(path) => Some([node_vec, path].concat()),
None => Some(node_vec),
};
}
match find_down_right_most_branch(&node_ref.right) {
Some(path) => Some([node_vec, path].concat()),
None => Some(node_vec),
}
}
pub fn find_node_by_vote_reference(
node: &NodeRef,
reference: &VoteReference,
) -> Option<Vec<NodeRef>> {
if node.is_none() {
return None;
}
if let Some((r, _)) = node.as_ref().unwrap().vote {
return if &r == reference {
Some(vec![node.clone()])
} else {
None
};
}
let node_vec = vec![node.clone()];
let node = node.as_ref().unwrap();
if let Some(path) = find_node_by_vote_reference(&node.left, reference) {
return Some([node_vec, path].concat());
}
if let Some(path) = find_node_by_vote_reference(&node.right, reference) {
return Some([node_vec, path].concat());
}
None
}
pub fn find_closest_siblings(
root: &NodeRef,
reference: &VoteReference,
) -> Result<(VoteReferencePair, bool), String> {
let root: &Arc<Node> = root
.as_ref()
.ok_or_else(|| "Invalid root node".to_string())?;
let mut queue = VecDeque::from([root]);
let mut left_sibling: Option<VoteReference> = None;
let mut right_sibling: Option<VoteReference> = None;
let mut reference_exists = false;
while let Some(node) = queue.pop_front() {
if let Some(n) = &node.left {
queue.push_back(n);
}
if let Some(n) = &node.right {
queue.push_back(n);
}
if let Some((r, _)) = &node.vote {
if r == reference {
reference_exists = true;
}
if r < reference {
if let Some(l) = left_sibling {
if r > &l {
left_sibling = Some(*r);
}
} else {
left_sibling = Some(*r);
}
}
if r > reference {
if let Some(l) = right_sibling {
if r < &l {
right_sibling = Some(*r);
}
} else {
right_sibling = Some(*r);
}
}
}
}
Ok(((left_sibling, right_sibling), reference_exists))
}
pub fn tree_depth(node: &NodeRef) -> usize {
match node {
Some(n) => 1 + tree_depth(&n.left),
None => 0,
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::generate::generate_tree;
use crate::hash::hash_node_ref;
use crate::Validation;
#[test]
fn test_find_down_right_most_branch() {
let root = generate_tree(vec![([0xaa; 32], vec![1, 0])], true).unwrap();
let path = find_down_right_most_branch(&root).unwrap();
assert_eq!(path.len(), 1);
assert_eq!(
hash_node_ref(&path[0], &Validation::Strict),
hash_node_ref(&root, &Validation::Strict)
);
let root = generate_tree(
vec![
([0xaa; 32], vec![1, 0]),
([0xbb; 32], vec![1, 0]),
([0xcc; 32], vec![0, 1]),
],
true,
)
.unwrap();
let path = find_down_right_most_branch(&root).unwrap();
assert_eq!(path.len(), 2);
assert_eq!(
hash_node_ref(&path[1], &Validation::Strict),
hash_node_ref(&root.unwrap().right, &Validation::Strict)
);
}
#[test]
fn test_find_node_by_vote_reference() {
let root = generate_tree(
vec![
([0xaa; 32], vec![1, 0]),
([0xbb; 32], vec![1, 0]),
([0xcc; 32], vec![0, 1]),
],
true,
)
.unwrap();
let path = find_node_by_vote_reference(&root, &[0xbb; 32]).unwrap();
assert_eq!(path.len(), 4);
assert_eq!(
hash_node_ref(&path[0], &Validation::Strict),
hash_node_ref(&root, &Validation::Strict)
);
assert_eq!(
hash_node_ref(&path[1], &Validation::Strict),
hash_node_ref(&root.as_ref().unwrap().left, &Validation::Strict)
);
assert_eq!(
hash_node_ref(&path[2], &Validation::Strict),
hash_node_ref(
&root.as_ref().unwrap().left.as_ref().unwrap().right,
&Validation::Strict
)
);
assert_eq!(
hash_node_ref(&path[3], &Validation::Strict),
hash_node_ref(
&root
.as_ref()
.unwrap()
.left
.as_ref()
.unwrap()
.right
.as_ref()
.unwrap()
.left,
&Validation::Strict
)
);
}
#[test]
fn test_find_closest_siblings() {
let root = generate_tree(
vec![
([0xaa; 32], vec![1, 0]),
([0xbb; 32], vec![1, 0]),
([0xdd; 32], vec![0, 1]),
],
false,
)
.unwrap();
let ((left, right), exists) = find_closest_siblings(&root, &[0xaa; 32]).unwrap();
assert!(exists);
assert!(left.is_none());
assert_eq!(right, Some([0xbb; 32]));
let ((left, right), exists) = find_closest_siblings(&root, &[0xbb; 32]).unwrap();
assert!(exists);
assert_eq!(left, Some([0xaa; 32]));
assert_eq!(right, Some([0xdd; 32]));
let ((left, right), exists) = find_closest_siblings(&root, &[0xdd; 32]).unwrap();
assert!(exists);
assert_eq!(left, Some([0xbb; 32]));
assert!(right.is_none());
let ((left, right), exists) = find_closest_siblings(&root, &[0xcc; 32]).unwrap();
assert!(!exists);
assert_eq!(left, Some([0xbb; 32]));
assert_eq!(right, Some([0xdd; 32]));
}
#[test]
fn test_tree_depth() {
let root = generate_tree(vec![([0xaa; 32], vec![1, 0])], false).unwrap();
assert_eq!(3, tree_depth(&root));
let root = generate_tree(
vec![
([0xaa; 32], vec![1, 0]),
([0xbb; 32], vec![1, 0]),
([0xdd; 32], vec![0, 1]),
],
false,
)
.unwrap();
assert_eq!(4, tree_depth(&root));
}
}