use std::cmp::Ordering;
use rand::Rng;
use crate::{
error::DecodingError,
tree::ChildDir,
utils::{bytes_to_usize, tree_index_from_u64, usize_to_bytes},
};
const BYTE_SIZE: usize = 8;
const BYTE_NUM: usize = 32;
pub const MAX_HEIGHT: usize = BYTE_SIZE * BYTE_NUM;
const HEIGHT_BYTE_NUM: usize = 2;
#[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq)]
pub struct TreeIndex {
height: usize,
path: [u8; BYTE_NUM],
}
impl Ord for TreeIndex {
fn cmp(&self, other: &Self) -> Ordering {
match self.height.cmp(&other.get_height()) {
Ordering::Greater => Ordering::Less,
Ordering::Less => Ordering::Greater,
Ordering::Equal => {
for i in 0..self.height {
match self.get_bit(i).cmp(&other.get_bit(i)) {
Ordering::Greater => {
return Ordering::Greater;
}
Ordering::Less => {
return Ordering::Less;
}
Ordering::Equal => {
continue;
}
}
}
Ordering::Equal
}
}
}
}
impl PartialOrd for TreeIndex {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl TreeIndex {
pub fn new(height: usize, pos: [u8; BYTE_NUM]) -> TreeIndex {
if height > MAX_HEIGHT {
panic!("{}", DecodingError::ExceedMaxHeight);
}
TreeIndex { height, path: pos }
}
pub fn from_u32(height: usize, pos: u32) -> TreeIndex {
if height > MAX_HEIGHT {
panic!("{}", DecodingError::ExceedMaxHeight);
}
if 32 - pos.leading_zeros() > height as u32 {
panic!("{}", DecodingError::IndexOverflow);
}
tree_index_from_u64(height, pos as u64)
}
pub fn from_u64(height: usize, pos: u64) -> TreeIndex {
if height > MAX_HEIGHT {
panic!("{}", DecodingError::ExceedMaxHeight);
}
if 64 - pos.leading_zeros() > height as u32 {
panic!("{}", DecodingError::IndexOverflow);
}
tree_index_from_u64(height, pos)
}
pub fn zero(height: usize) -> TreeIndex {
TreeIndex::new(height, [0u8; BYTE_NUM])
}
pub fn get_height(&self) -> usize {
self.height
}
pub fn set_height(&mut self, height: usize) {
if height > MAX_HEIGHT {
panic!("{}", DecodingError::ExceedMaxHeight);
}
self.height = height;
}
pub fn get_path(&self) -> [u8; BYTE_NUM] {
self.path
}
pub fn get_bit(&self, i: usize) -> u8 {
if i >= self.height {
panic!("The input index is out of range, thus the queried bit doesn't exist.");
}
(self.path[i / BYTE_SIZE] >> (i % BYTE_SIZE)) & 1
}
pub fn get_last_bit(self) -> u8 {
if self.height == 0 {
panic!("The height is 0, thus the queried bit doesn't exist.");
}
self.get_bit(self.height - 1)
}
pub fn get_prefix(&self, height: usize) -> TreeIndex {
if height > self.height {
panic!("The input height exceeds the height of the tree index.");
}
let mut index = TreeIndex::new(height, self.path);
let mut len = height;
let mut flag: u32 = (1 << 8) - 1;
for i in 0..BYTE_NUM {
if len < BYTE_SIZE {
flag = (1 << len) - 1;
len = 0;
} else {
len -= 8;
}
index.path[i] &= flag as u8;
}
index
}
pub fn randomize(&mut self) {
let mut rng = rand::thread_rng();
for i in 0..BYTE_NUM {
self.path[i] = rng.gen();
}
*self = self.get_prefix(self.height);
}
pub fn get_lch_index(&self) -> TreeIndex {
if self.height == MAX_HEIGHT {
panic!("The index already has the maximum height.");
}
let mut pos = self.path;
pos[self.height / BYTE_SIZE] &= u8::MAX - (1 << (self.height % BYTE_SIZE));
TreeIndex::new(self.height + 1, self.path)
}
pub fn get_rch_index(&self) -> TreeIndex {
if self.height == MAX_HEIGHT {
panic!("The index already has the maximum height.");
}
let mut pos = self.path;
pos[self.height / BYTE_SIZE] |= 1 << (self.height % BYTE_SIZE);
TreeIndex::new(self.height + 1, pos)
}
pub fn get_child_index_by_dir(&self, dir: ChildDir) -> TreeIndex {
if dir == ChildDir::Left {
self.get_lch_index()
} else {
self.get_rch_index()
}
}
pub fn get_sibling_index(&self) -> TreeIndex {
if self.height == 0 {
panic!("The root doesn't have a sibling.");
}
let mut pos = self.path;
pos[(self.height - 1) / BYTE_SIZE] ^= 1 << ((self.height - 1) % BYTE_SIZE);
TreeIndex::new(self.height, pos)
}
pub fn get_parent_index(&self) -> TreeIndex {
if self.height == 0 {
panic!("The root doesn't have a parent.");
}
self.get_prefix(self.height - 1)
}
fn get_byte_num_by_bit(bit_num: usize) -> usize {
let mut byte_num = bit_num / BYTE_SIZE;
if bit_num % BYTE_SIZE > 0 {
byte_num += 1;
}
byte_num
}
fn get_dir_index(&self, dir: ChildDir) -> Option<TreeIndex> {
let mut opp_dir = ChildDir::Left;
let mut dir_bit = 1;
if dir == ChildDir::Left {
opp_dir = ChildDir::Right;
dir_bit = 0;
}
let mut index = *self;
for i in (0..self.height).rev() {
if self.get_bit(i) == 1 - dir_bit {
index = index.get_prefix(i).get_child_index_by_dir(dir);
break;
}
}
while index.get_height() < self.height {
index = index.get_child_index_by_dir(opp_dir);
}
if index == *self {
None
} else {
Some(index)
}
}
pub fn get_left_index(&self) -> Option<TreeIndex> {
self.get_dir_index(ChildDir::Left)
}
pub fn get_right_index(&self) -> Option<TreeIndex> {
self.get_dir_index(ChildDir::Right)
}
pub fn serialize(list: &[TreeIndex]) -> Vec<u8> {
let mut vec: Vec<u8> = Vec::new();
if list.is_empty() {
return vec;
}
let height = list[0].get_height();
let mut height_bytes = usize_to_bytes(height, HEIGHT_BYTE_NUM);
vec.append(&mut height_bytes);
let byte_num = Self::get_byte_num_by_bit(height);
for item in list {
vec.extend_from_slice(&item.get_path()[0..byte_num]);
}
vec
}
pub fn deserialize_as_a_unit(
bytes: &[u8],
num: usize,
begin: &mut usize,
) -> Result<Vec<TreeIndex>, DecodingError> {
if bytes.len() - *begin == 0 && num == 0 {
return Ok(Vec::new());
}
let height = bytes_to_usize(bytes, HEIGHT_BYTE_NUM, begin);
if let Err(e) = height {
return Err(e);
}
let height = height.unwrap();
if height > MAX_HEIGHT {
return Err(DecodingError::ExceedMaxHeight);
}
let index_byte_num = Self::get_byte_num_by_bit(height);
if (bytes.len() - *begin) < index_byte_num * num {
return Err(DecodingError::BytesNotEnough);
}
let mut vec: Vec<TreeIndex> = Vec::new();
for _i in 0..num {
let mut path = [0u8; BYTE_NUM];
for item in path.iter_mut().take(index_byte_num) {
*item = bytes[*begin];
*begin += 1;
}
vec.push(TreeIndex::new(height, path));
}
Ok(vec)
}
}