use core::num::NonZeroUsize;
use crate::utils::{ByteReader, ByteWriter, Deserializable, Serializable};
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct InOrderIndex {
idx: usize,
}
impl InOrderIndex {
pub fn new(idx: NonZeroUsize) -> InOrderIndex {
InOrderIndex { idx: idx.get() }
}
pub fn from_leaf_pos(leaf: usize) -> InOrderIndex {
let pos = leaf + 1;
InOrderIndex { idx: pos * 2 - 1 }
}
pub fn is_leaf(&self) -> bool {
self.idx & 1 == 1
}
pub fn is_left_child(&self) -> bool {
self.parent().left_child() == *self
}
pub fn level(&self) -> u32 {
self.idx.trailing_zeros()
}
pub fn left_child(&self) -> InOrderIndex {
let els = 1 << (self.level() - 1);
InOrderIndex { idx: self.idx - els }
}
pub fn right_child(&self) -> InOrderIndex {
let els = 1 << (self.level() - 1);
InOrderIndex { idx: self.idx + els }
}
pub fn parent(&self) -> InOrderIndex {
let target = self.level() + 1;
let bit = 1 << target;
let mask = bit - 1;
let idx = self.idx ^ (self.idx & mask);
InOrderIndex { idx: idx | bit }
}
pub fn sibling(&self) -> InOrderIndex {
let parent = self.parent();
if *self > parent {
parent.left_child()
} else {
parent.right_child()
}
}
pub fn inner(&self) -> usize {
self.idx
}
pub fn to_leaf_pos(&self) -> Option<usize> {
if self.is_leaf() { Some((self.idx - 1) / 2) } else { None }
}
}
impl Serializable for InOrderIndex {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
target.write_usize(self.idx);
}
}
impl Deserializable for InOrderIndex {
fn read_from<R: ByteReader>(
source: &mut R,
) -> Result<Self, crate::utils::DeserializationError> {
let idx = source.read_usize()?;
Ok(InOrderIndex { idx })
}
}
impl From<InOrderIndex> for usize {
fn from(index: InOrderIndex) -> Self {
index.idx
}
}
#[cfg(test)]
mod test {
use proptest::prelude::*;
use super::InOrderIndex;
use crate::utils::{Deserializable, Serializable};
proptest! {
#[test]
fn proptest_inorder_index_random(count in 1..1000usize) {
let left_pos = count * 2;
let right_pos = count * 2 + 1;
let left = InOrderIndex::from_leaf_pos(left_pos);
let right = InOrderIndex::from_leaf_pos(right_pos);
assert!(left.is_leaf());
assert!(right.is_leaf());
assert_eq!(left.parent(), right.parent());
assert_eq!(left.parent().right_child(), right);
assert_eq!(left, right.parent().left_child());
assert_eq!(left.sibling(), right);
assert_eq!(left, right.sibling());
}
}
#[test]
fn test_inorder_index_basic() {
let left = InOrderIndex::from_leaf_pos(0);
let right = InOrderIndex::from_leaf_pos(1);
assert!(left.is_leaf());
assert!(right.is_leaf());
assert_eq!(left.parent(), right.parent());
assert_eq!(left.parent().right_child(), right);
assert_eq!(left, right.parent().left_child());
assert_eq!(left.sibling(), right);
assert_eq!(left, right.sibling());
}
#[test]
fn test_inorder_index_serialization() {
let index = InOrderIndex::from_leaf_pos(5);
let bytes = index.to_bytes();
let index2 = InOrderIndex::read_from_bytes(&bytes).unwrap();
assert_eq!(index, index2);
}
}