use std::ops::Deref;
use std::sync::Arc;
use incrementalmerkletree::{Address, Level, Position};
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Node<C, A, V> {
Parent { ann: A, left: C, right: C },
Leaf { value: V },
Nil,
}
impl<C, A, V> Node<C, A, V> {
pub fn is_nil(&self) -> bool {
matches!(self, Node::Nil)
}
pub fn leaf_value(&self) -> Option<&V> {
match self {
Node::Parent { .. } => None,
Node::Leaf { value } => Some(value),
Node::Nil => None,
}
}
pub fn annotation(&self) -> Option<&A> {
match self {
Node::Parent { ann, .. } => Some(ann),
Node::Leaf { .. } => None,
Node::Nil => None,
}
}
pub fn reannotate(self, ann: A) -> Self {
match self {
Node::Parent { left, right, .. } => Node::Parent { ann, left, right },
other => other,
}
}
}
impl<'a, C, A, V> Node<C, &'a A, &'a V>
where
C: Clone,
A: Clone,
V: Clone,
{
pub fn cloned(&self) -> Node<C, A, V> {
match self {
Node::Parent { ann, left, right } => Node::Parent {
ann: (*ann).clone(),
left: left.clone(),
right: right.clone(),
},
Node::Leaf { value } => Node::Leaf {
value: (*value).clone(),
},
Node::Nil => Node::Nil,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Tree<A, V>(pub(crate) Node<Arc<Tree<A, V>>, A, V>);
impl<A, V> Deref for Tree<A, V> {
type Target = Node<Arc<Tree<A, V>>, A, V>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<A, V> Tree<A, V> {
pub const fn empty() -> Self {
Tree(Node::Nil)
}
pub fn leaf(value: V) -> Self {
Tree(Node::Leaf { value })
}
pub fn parent(ann: A, left: Self, right: Self) -> Self {
Tree(Node::Parent {
ann,
left: Arc::new(left),
right: Arc::new(right),
})
}
pub fn is_empty(&self) -> bool {
self.0.is_nil()
}
pub fn reannotate_root(self, ann: A) -> Self {
Tree(self.0.reannotate(ann))
}
pub fn is_leaf(&self) -> bool {
matches!(&self.0, Node::Leaf { .. })
}
pub fn incomplete_nodes(&self, root_addr: Address) -> Vec<Address> {
match &self.0 {
Node::Parent { left, right, .. } => {
assert!(!(left.0.is_nil() && right.0.is_nil()));
let (left_root, right_root) = root_addr
.children()
.expect("A parent node cannot appear at level 0");
let mut left_incomplete = left.incomplete_nodes(left_root);
let mut right_incomplete = right.incomplete_nodes(right_root);
left_incomplete.append(&mut right_incomplete);
left_incomplete
}
Node::Leaf { .. } => vec![],
Node::Nil => vec![root_addr],
}
}
pub fn map<B, F>(&self, f: &F) -> Tree<A, B>
where
F: Fn(&V) -> B,
A: Clone,
{
Tree(match &self.0 {
Node::Parent { ann, left, right } => Node::Parent {
ann: ann.clone(),
left: Arc::new(left.map(f)),
right: Arc::new(right.map(f)),
},
Node::Leaf { value } => Node::Leaf { value: f(value) },
Node::Nil => Node::Nil,
})
}
pub fn try_map<B, E, F>(&self, f: &F) -> Result<Tree<A, B>, E>
where
F: Fn(&V) -> Result<B, E>,
A: Clone,
{
Ok(Tree(match &self.0 {
Node::Parent { ann, left, right } => Node::Parent {
ann: ann.clone(),
left: Arc::new(left.try_map(f)?),
right: Arc::new(right.try_map(f)?),
},
Node::Leaf { value } => Node::Leaf { value: f(value)? },
Node::Nil => Node::Nil,
}))
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct LocatedTree<A, V> {
pub(crate) root_addr: Address,
pub(crate) root: Tree<A, V>,
}
impl<A, V> LocatedTree<A, V> {
pub fn from_parts(root_addr: Address, root: Tree<A, V>) -> Result<Self, Address> {
fn check<A, V>(addr: Address, root: &Tree<A, V>) -> Result<(), Address> {
match (&root.0, addr.children()) {
(Node::Parent { .. }, None) => Err(addr),
(Node::Parent { left, right, .. }, Some((l_addr, r_addr))) => {
check(l_addr, left)?;
check(r_addr, right)?;
Ok(())
}
(Node::Leaf { .. }, _) => Ok(()),
(Node::Nil, _) => Ok(()),
}
}
check(root_addr, &root).map(|_| LocatedTree { root_addr, root })
}
pub fn root_addr(&self) -> Address {
self.root_addr
}
pub fn root(&self) -> &Tree<A, V> {
&self.root
}
pub fn take_root(self) -> Tree<A, V> {
self.root
}
pub fn reannotate_root(self, value: A) -> Self {
LocatedTree {
root_addr: self.root_addr,
root: self.root.reannotate_root(value),
}
}
pub fn incomplete_nodes(&self) -> Vec<Address> {
self.root.incomplete_nodes(self.root_addr)
}
pub fn pretty_print_indented_with<FA, FV>(&self, fmt_ann: FA, fmt_val: FV) -> String
where
FA: Fn(&A) -> String,
FV: Fn(&V) -> String,
{
fn go<A, V, FA, FV>(
out: &mut String,
addr: Address,
tree: &Tree<A, V>,
self_prefix: &str,
child_prefix: &str,
fmt_ann: &FA,
fmt_val: &FV,
) where
FA: Fn(&A) -> String,
FV: Fn(&V) -> String,
{
if !out.is_empty() {
out.push('\n');
}
let loc = format!("[{},{}]", u8::from(addr.level()), addr.index());
match &tree.0 {
Node::Parent { ann, left, right } => {
out.push_str(&format!(
"{self_prefix}{loc} Parent (ann: {})",
fmt_ann(ann)
));
let (l_addr, r_addr) = addr
.children()
.expect("a parent node always has child addresses");
let l_self = format!("{child_prefix}|-- ");
let l_child = format!("{child_prefix}| ");
let r_self = format!("{child_prefix}`-- ");
let r_child = format!("{child_prefix} ");
go(out, l_addr, left, &l_self, &l_child, fmt_ann, fmt_val);
go(out, r_addr, right, &r_self, &r_child, fmt_ann, fmt_val);
}
Node::Leaf { value } => {
out.push_str(&format!("{self_prefix}{loc} Leaf {}", fmt_val(value)));
}
Node::Nil => {
out.push_str(&format!("{self_prefix}{loc} Nil"));
}
}
}
let mut out = String::new();
go(
&mut out,
self.root_addr,
&self.root,
"",
"",
&fmt_ann,
&fmt_val,
);
out
}
pub fn pretty_print_bottom_top_with<FA, FV>(&self, fmt_ann: FA, fmt_val: FV) -> String
where
FA: Fn(&A) -> String,
FV: Fn(&V) -> String,
{
fn render<A, V, FA, FV>(
addr: Address,
tree: &Tree<A, V>,
fmt_ann: &FA,
fmt_val: &FV,
) -> (Vec<String>, usize)
where
FA: Fn(&A) -> String,
FV: Fn(&V) -> String,
{
let level = u8::from(addr.level());
let index = addr.index();
match &tree.0 {
Node::Parent { ann, left, right } => {
let (l_addr, r_addr) = addr
.children()
.expect("a parent node always has child addresses");
let (l_block, l_col) = render(l_addr, left, fmt_ann, fmt_val);
let (r_block, r_col) = render(r_addr, right, fmt_ann, fmt_val);
let l_w = l_block.iter().map(|s| s.len()).max().unwrap_or(0);
let r_w = r_block.iter().map(|s| s.len()).max().unwrap_or(0);
let h = l_block.len().max(r_block.len());
let l_pad = h - l_block.len();
let r_pad = h - r_block.len();
let row_chars =
|block: &[String], pad: usize, w: usize, i: usize| -> Vec<char> {
if i < pad {
vec![' '; w]
} else {
let mut v: Vec<char> = block[i - pad].chars().collect();
v.resize(w, ' ');
v
}
};
let lc = l_col;
let mut gap = 1usize;
let mut rc = l_w + gap + r_col;
while (rc - lc) % 2 != 0 {
gap += 1;
rc = l_w + gap + r_col;
}
let top_w = l_w + gap + r_w;
let hdiag = (rc - lc) / 2 - 1;
let parent_col = lc + hdiag + 1;
let ann_str = fmt_ann(ann);
let token: Vec<char> = if ann_str.is_empty() {
format!("[{level},{index}]").chars().collect()
} else {
format!("[{level},{index}]:{ann_str}").chars().collect()
};
let tw = token.len();
let token_start = parent_col as isize - (tw as isize) / 2;
let left_pad = if token_start < 0 {
(-token_start) as usize
} else {
0
};
let token_start = (token_start + left_pad as isize) as usize;
let width = (top_w + left_pad).max(token_start + tw);
let total_h = h + hdiag + 1;
let mut grid = vec![vec![' '; width]; total_h];
for (i, row) in grid[..h].iter_mut().enumerate() {
for (j, ch) in row_chars(&l_block, l_pad, l_w, i).into_iter().enumerate() {
if ch != ' ' {
row[left_pad + j] = ch;
}
}
for (j, ch) in row_chars(&r_block, r_pad, r_w, i).into_iter().enumerate() {
if ch != ' ' {
row[left_pad + l_w + gap + j] = ch;
}
}
}
for (di, row) in grid[h..h + hdiag].iter_mut().enumerate() {
let i = di + 1;
row[left_pad + lc + i] = '\\';
row[left_pad + rc - i] = '/';
}
for (j, ch) in token.iter().enumerate() {
grid[total_h - 1][token_start + j] = *ch;
}
let lines = grid
.into_iter()
.map(|r| r.into_iter().collect::<String>())
.collect();
(lines, parent_col + left_pad)
}
terminal => {
let token = match terminal {
Node::Leaf { value } => format!("[{level},{index}]:{}", fmt_val(value)),
_ => format!("[{level},{index}]:Nil"),
};
let center = token.chars().count() / 2;
(vec![token], center)
}
}
}
let (lines, _) = render(self.root_addr, &self.root, &fmt_ann, &fmt_val);
lines
.into_iter()
.map(|l| l.trim_end().to_string())
.collect::<Vec<_>>()
.join("\n")
}
pub fn value_at_position(&self, position: Position) -> Option<&V> {
fn go<A, V>(pos: Position, addr: Address, root: &Tree<A, V>) -> Option<&V> {
match &root.0 {
Node::Parent { left, right, .. } => {
let (l_addr, r_addr) = addr
.children()
.expect("has children because we checked `root` is a parent");
if l_addr.position_range().contains(&pos) {
go(pos, l_addr, left)
} else {
go(pos, r_addr, right)
}
}
Node::Leaf { value } if addr.level() == Level::from(0) => Some(value),
_ => None,
}
}
if self.root_addr.position_range().contains(&position) {
go(position, self.root_addr, &self.root)
} else {
None
}
}
pub fn map<B, F>(&self, f: &F) -> LocatedTree<A, B>
where
F: Fn(&V) -> B,
A: Clone,
{
LocatedTree {
root_addr: self.root_addr,
root: self.root.map(f),
}
}
pub fn try_map<B, E, F>(&self, f: &F) -> Result<LocatedTree<A, B>, E>
where
F: Fn(&V) -> Result<B, E>,
A: Clone,
{
Ok(LocatedTree {
root_addr: self.root_addr,
root: self.root.try_map(f)?,
})
}
}
impl<A, V> LocatedTree<A, V>
where
A: Default + Clone,
V: Clone,
{
pub fn empty(root_addr: Address) -> Self {
Self {
root_addr,
root: Tree::empty(),
}
}
pub fn with_root_value(root_addr: Address, value: V) -> Self {
Self {
root_addr,
root: Tree::leaf(value),
}
}
pub fn subtree(&self, addr: Address) -> Option<Self> {
fn go<A, V>(
root_addr: Address,
root: &Tree<A, V>,
addr: Address,
) -> Option<LocatedTree<A, V>>
where
A: Clone,
V: Clone,
{
if root_addr == addr {
Some(LocatedTree {
root_addr,
root: root.clone(),
})
} else {
match &root.0 {
Node::Parent { left, right, .. } => {
let (l_addr, r_addr) = root_addr
.children()
.expect("has children because we checked `root` is a parent");
if l_addr.contains(&addr) {
go(l_addr, left.as_ref(), addr)
} else {
go(r_addr, right.as_ref(), addr)
}
}
_ => None,
}
}
}
if self.root_addr.contains(&addr) {
go(self.root_addr, &self.root, addr)
} else {
None
}
}
pub fn decompose_to_level(self, level: Level) -> Vec<Self> {
fn go<A, V>(level: Level, root_addr: Address, root: Tree<A, V>) -> Vec<LocatedTree<A, V>>
where
A: Clone,
V: Clone,
{
if root_addr.level() == level {
vec![LocatedTree { root_addr, root }]
} else {
match root.0 {
Node::Parent { left, right, .. } => {
let (l_addr, r_addr) = root_addr
.children()
.expect("has children because we checked `root` is a parent");
let mut l_decomposed = go(
level,
l_addr,
Arc::try_unwrap(left).unwrap_or_else(|rc| (*rc).clone()),
);
let mut r_decomposed = go(
level,
r_addr,
Arc::try_unwrap(right).unwrap_or_else(|rc| (*rc).clone()),
);
l_decomposed.append(&mut r_decomposed);
l_decomposed
}
_ => vec![],
}
}
}
if level >= self.root_addr.level() {
vec![self]
} else {
go(level, self.root_addr, self.root)
}
}
}
#[cfg(test)]
pub(crate) mod tests {
use incrementalmerkletree::{Address, Level};
use super::{LocatedTree, Tree};
pub(crate) fn str_leaf<A>(c: &str) -> Tree<A, String> {
Tree::leaf(c.to_string())
}
pub(crate) fn nil<A, B>() -> Tree<A, B> {
Tree::empty()
}
pub(crate) fn leaf<A, B>(value: B) -> Tree<A, B> {
Tree::leaf(value)
}
pub(crate) fn parent<A, B>(left: Tree<A, B>, right: Tree<A, B>) -> Tree<A, B>
where
A: Default,
{
Tree::parent(A::default(), left, right)
}
#[test]
fn incomplete_nodes() {
let t: Tree<(), String> = parent(nil(), str_leaf("a"));
assert_eq!(
t.incomplete_nodes(Address::from_parts(Level::from(1), 0)),
vec![Address::from_parts(Level::from(0), 0)]
);
let t0 = parent(str_leaf("b"), t.clone());
assert_eq!(
t0.incomplete_nodes(Address::from_parts(Level::from(2), 1)),
vec![Address::from_parts(Level::from(0), 6)]
);
let t1 = parent(nil(), t);
assert_eq!(
t1.incomplete_nodes(Address::from_parts(Level::from(2), 1)),
vec![
Address::from_parts(Level::from(1), 2),
Address::from_parts(Level::from(0), 6)
]
);
}
#[test]
fn located() {
let l = parent(str_leaf("a"), str_leaf("b"));
let r = parent(str_leaf("c"), str_leaf("d"));
let t: LocatedTree<(), String> = LocatedTree {
root_addr: Address::from_parts(2.into(), 1),
root: parent(l.clone(), r.clone()),
};
assert_eq!(t.value_at_position(5.into()), Some(&"b".to_string()));
assert_eq!(t.value_at_position(8.into()), None);
assert_eq!(t.subtree(Address::from_parts(0.into(), 1)), None);
assert_eq!(t.subtree(Address::from_parts(3.into(), 0)), None);
let subtree_addr = Address::from_parts(1.into(), 3);
assert_eq!(
t.subtree(subtree_addr),
Some(LocatedTree {
root_addr: subtree_addr,
root: r.clone()
})
);
assert_eq!(
t.decompose_to_level(1.into()),
vec![
LocatedTree {
root_addr: Address::from_parts(1.into(), 2),
root: l,
},
LocatedTree {
root_addr: Address::from_parts(1.into(), 3),
root: r,
}
]
);
}
}