use serde::{Deserialize, Serialize};
use std::{
convert::{TryFrom, TryInto},
fmt::Debug,
};
use thiserror::Error;
use super::diff::{AbDiff, StagedAbDiff};
use crate::{
binary_tree::{LeafIndex, TreeSize},
error::LibraryError,
};
pub(in crate::binary_tree) type NodeIndex = u32;
pub(super) fn to_node_index(leaf_index: LeafIndex) -> NodeIndex {
leaf_index * 2
}
#[cfg_attr(test, derive(PartialEq))]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub(crate) struct ABinaryTree<T: Clone + Debug> {
nodes: Vec<T>,
}
impl<T: Clone + Debug> TryFrom<Vec<T>> for ABinaryTree<T> {
type Error = ABinaryTreeError;
fn try_from(nodes: Vec<T>) -> Result<Self, Self::Error> {
Self::new(nodes)
}
}
impl<T: Clone + Debug> ABinaryTree<T> {
pub(crate) fn new(nodes: Vec<T>) -> Result<Self, ABinaryTreeError> {
let max_nodes = usize::try_from(NodeIndex::MAX)
.map_err(|_| LibraryError::custom("Architecture not supported"))?;
if nodes.len() > max_nodes {
return Err(ABinaryTreeError::OutOfRange);
}
if nodes.len() % 2 != 1 {
return Err(ABinaryTreeError::InvalidNumberOfNodes);
}
Ok(ABinaryTree { nodes })
}
pub(in crate::binary_tree) fn node_by_index(
&self,
node_index: NodeIndex,
) -> Result<&T, ABinaryTreeError> {
self.nodes
.get(
usize::try_from(node_index)
.map_err(|_| LibraryError::custom("Architecture not supported"))?,
)
.ok_or(ABinaryTreeError::OutOfBounds)
}
pub(in crate::binary_tree) fn size(&self) -> Result<NodeIndex, LibraryError> {
let tree_size =
u32::try_from(self.nodes.len()).map_err(|_| LibraryError::custom("Tree is too big"))?;
Ok(tree_size)
}
pub(crate) fn leaf_count(&self) -> Result<TreeSize, LibraryError> {
Ok(((self.size()? - 1) / 2) + 1)
}
pub(crate) fn leaves(&self) -> Result<Vec<&T>, LibraryError> {
let mut leaf_references = Vec::new();
for leaf_index in 0..self.leaf_count()? {
let node_index = usize::try_from(to_node_index(leaf_index))
.map_err(|_| LibraryError::custom("Tree is too big"))?;
let node_ref = self
.nodes
.get(node_index)
.ok_or_else(|| LibraryError::custom("Node not found"))?;
leaf_references.push(node_ref);
}
Ok(leaf_references)
}
pub(crate) fn empty_diff(&self) -> Result<AbDiff<'_, T>, ABinaryTreeError> {
self.try_into()
.map_err(|_| ABinaryTreeError::ABinaryTreeDiffError)
}
pub(crate) fn merge_diff(&mut self, diff: StagedAbDiff<T>) -> Result<(), LibraryError> {
let diff_size = usize::try_from(diff.tree_size())
.map_err(|_| LibraryError::custom("Architecture not supported"))?;
self.nodes.truncate(diff_size);
for (node_index, diff_node) in diff.diff().into_iter() {
match node_index {
node_index if node_index == self.size()? => self.nodes.push(diff_node),
node_index if node_index > self.size()? => {
return Err(LibraryError::custom("Node is outside the tree"))
}
node_index => {
let node_index = usize::try_from(node_index)
.map_err(|_| LibraryError::custom("Architecture not supported"))?;
self.nodes[node_index] = diff_node;
}
}
}
Ok(())
}
pub(crate) fn nodes(&self) -> &[T] {
&self.nodes
}
pub(crate) fn leaf(&self, leaf_index: LeafIndex) -> Result<&T, ABinaryTreeError> {
let node_index = usize::try_from(to_node_index(leaf_index))
.map_err(|_| LibraryError::custom("Architecture not supported"))?;
self.nodes
.get(node_index)
.ok_or(ABinaryTreeError::OutOfBounds)
}
}
#[derive(Error, Debug, PartialEq, Clone)]
pub(crate) enum ABinaryTreeError {
#[error(transparent)]
LibraryError(#[from] LibraryError),
#[error("Adding nodes exceeds the maximum possible size of the tree.")]
OutOfRange,
#[error("Not enough nodes to remove.")]
InvalidNumberOfNodes,
#[error("The given index is outside of the tree.")]
OutOfBounds,
#[error("An error occurred while handling a diff.")]
ABinaryTreeDiffError,
}