#![allow(dead_code)]
use std::collections::VecDeque;
use std::io::prelude::*;
use sha2::{Digest, Sha256};
#[derive(Debug, Clone)]
struct Node {
pub hash: Vec<u8>,
pub index: usize,
pub left: Option<usize>,
pub right: Option<usize>,
}
#[derive(Debug, Clone)]
pub struct HashTree {
nodes: VecDeque<Node>,
num_blocks: usize,
block_size: usize,
}
impl HashTree {
pub fn new(block_size: usize) -> Self {
Self {
nodes: VecDeque::new(),
num_blocks: 0,
block_size,
}
}
pub fn from_data<R: Read>(mut self, data: &mut R) -> Result<Self, std::io::Error> {
let mut buf = Vec::<u8>::with_capacity(self.block_size);
let mut index = 0;
loop {
let mut chunk = data.take(self.block_size as u64);
if chunk.read_to_end(&mut buf)? == 0 { break; }
let hash = Sha256::digest(&buf).to_vec();
let node = Node { hash, index, left: None, right: None };
self.nodes.push_back(node);
index += 1;
buf.clear();
}
self.num_blocks = self.nodes.len();
if self.nodes.len() % 2 == 1 {
self.nodes.push_back(self.nodes.back().unwrap().clone());
}
self.build(self.nodes.clone())?;
Ok(self)
}
fn build(&mut self, mut unprocessed_nodes: VecDeque<Node>) -> Result<(), std::io::Error> {
let mut parents = VecDeque::<Node>::new();
while !unprocessed_nodes.is_empty() {
let mut n1 = unprocessed_nodes.pop_front().unwrap();
let mut n2 = unprocessed_nodes.pop_front().unwrap();
n1.hash.append(&mut n2.hash);
let merged_hash = n1.hash;
let hash = Sha256::digest(&merged_hash).to_vec();
let index = self.nodes.len();
let parent = Node { hash, index, left: Some(n1.index), right: Some(n2.index) };
parents.push_back(parent.clone());
self.nodes.push_back(parent);
}
if parents.len() == 1 {
return Ok(());
}
self.build(parents)
}
pub fn insert<R: Read>(&mut self, data: &mut R) {
unimplemented!();
}
pub fn update(&mut self) {
unimplemented!();
}
pub fn is_empty(&self) -> bool {
if self.nodes.len() == 0 {
return true
}
false
}
pub fn root_hash(&self) -> Option<String> {
if let Some(root) = self.nodes.back() {
return Some(hex::encode(&root.hash))
};
None
}
pub fn num_nodes(&self) -> usize {
self.nodes.len()
}
pub fn num_blocks(&self) -> usize {
self.num_blocks
}
}
impl PartialEq for HashTree {
fn eq(&self, other: &Self) -> bool {
let my_root = match self.root_hash() {
Some(v) => v,
None => {
match other.root_hash() {
Some(_) => { return false },
None => { return true }
};
}
};
let other_root = match other.root_hash() {
Some(v) => v,
None => { return false; }
};
my_root == other_root
}
}