#![deny(missing_docs)]
use std::{
fmt::{self, Debug},
ops::Range,
};
use range_collections::RangeSetRef;
pub mod iter;
mod rec;
mod tree;
use iter::*;
pub use tree::{BlockSize, ChunkNum};
pub mod io;
pub use blake3;
#[cfg(all(test, feature = "tokio_fsm"))]
mod tests;
#[cfg(all(test, feature = "tokio_fsm"))]
mod tests2;
pub type ChunkRanges = range_collections::RangeSet2<ChunkNum>;
pub type ByteRanges = range_collections::RangeSet2<u64>;
pub type ChunkRangesRef = range_collections::RangeSetRef<ChunkNum>;
fn hash_subtree(start_chunk: u64, data: &[u8], is_root: bool) -> blake3::Hash {
use blake3::hazmat::{ChainingValue, HasherExt};
if is_root {
debug_assert!(start_chunk == 0);
blake3::hash(data)
} else {
let mut hasher = blake3::Hasher::new();
hasher.set_input_offset(start_chunk * 1024);
hasher.update(data);
let non_root_hash: ChainingValue = hasher.finalize_non_root();
blake3::Hash::from(non_root_hash)
}
}
fn parent_cv(left_child: &blake3::Hash, right_child: &blake3::Hash, is_root: bool) -> blake3::Hash {
use blake3::hazmat::{merge_subtrees_non_root, merge_subtrees_root, ChainingValue, Mode};
let left_child: ChainingValue = *left_child.as_bytes();
let right_child: ChainingValue = *right_child.as_bytes();
if is_root {
merge_subtrees_root(&left_child, &right_child, Mode::Hash)
} else {
blake3::Hash::from(merge_subtrees_non_root(
&left_child,
&right_child,
Mode::Hash,
))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct BaoTree {
size: u64,
block_size: BlockSize,
}
#[derive(Debug, Clone, Copy)]
pub enum PostOrderOffset {
Stable(u64),
Unstable(u64),
}
impl PostOrderOffset {
pub fn value(self) -> u64 {
match self {
Self::Stable(n) => n,
Self::Unstable(n) => n,
}
}
}
impl BaoTree {
pub fn new(size: u64, block_size: BlockSize) -> Self {
Self { size, block_size }
}
pub fn size(&self) -> u64 {
self.size
}
pub fn block_size(&self) -> BlockSize {
self.block_size
}
pub(crate) fn shifted(&self) -> (TreeNode, TreeNode) {
let level = self.block_size.0;
let size = self.size;
let shift = 10 + level;
let mask = (1 << shift) - 1;
let full_blocks = size >> shift;
let open_block = ((size & mask) != 0) as u64;
let blocks = (full_blocks + open_block).max(1);
let n = blocks.div_ceil(2);
let root = n.next_power_of_two() - 1;
let filled_size = n + n.saturating_sub(1);
(TreeNode(root), TreeNode(filled_size))
}
fn byte_range(&self, node: TreeNode) -> Range<u64> {
let start = node.chunk_range().start.to_bytes();
let end = node.chunk_range().end.to_bytes();
start..end.min(self.size)
}
fn leaf_byte_ranges3(&self, leaf: TreeNode) -> (u64, u64, u64) {
let Range { start, end } = leaf.byte_range();
let mid = leaf.mid().to_bytes();
if !(start < self.size || (start == 0 && self.size == 0)) {
debug_assert!(start < self.size || (start == 0 && self.size == 0));
}
(start, mid.min(self.size), end.min(self.size))
}
pub fn post_order_chunks_iter(&self) -> PostOrderChunkIter {
PostOrderChunkIter::new(*self)
}
pub fn ranges_pre_order_chunks_iter_ref<'a>(
&self,
ranges: &'a RangeSetRef<ChunkNum>,
min_level: u8,
) -> PreOrderPartialChunkIterRef<'a> {
PreOrderPartialChunkIterRef::new(*self, ranges, min_level)
}
pub fn post_order_nodes_iter(&self) -> impl Iterator<Item = TreeNode> {
let (root, len) = self.shifted();
let shift = self.block_size.0;
PostOrderNodeIter::new(root, len).map(move |x| x.subtract_block_size(shift))
}
pub fn pre_order_nodes_iter(&self) -> impl Iterator<Item = TreeNode> {
let (root, len) = self.shifted();
let shift = self.block_size.0;
PreOrderNodeIter::new(root, len).map(move |x| x.subtract_block_size(shift))
}
#[cfg(test)]
pub fn ranges_pre_order_nodes_iter<'a>(
&self,
ranges: &'a RangeSetRef<ChunkNum>,
min_level: u8,
) -> PreOrderPartialIterRef<'a> {
PreOrderPartialIterRef::new(*self, ranges, min_level)
}
pub fn root(&self) -> TreeNode {
let shift = 10;
let mask = (1 << shift) - 1;
let full_blocks = self.size >> shift;
let open_block = ((self.size & mask) != 0) as u64;
let blocks = (full_blocks + open_block).max(1);
let chunks = ChunkNum(blocks);
TreeNode::root(chunks)
}
pub fn blocks(&self) -> u64 {
blocks(self.size, self.block_size).max(1)
}
pub fn chunks(&self) -> ChunkNum {
ChunkNum::chunks(self.size)
}
fn outboard_hash_pairs(&self) -> u64 {
self.blocks() - 1
}
pub fn outboard_size(&self) -> u64 {
self.outboard_hash_pairs() * 64
}
#[allow(dead_code)]
fn filled_size(&self) -> TreeNode {
let blocks = self.chunks();
let n = blocks.0.div_ceil(2);
TreeNode(n + n.saturating_sub(1))
}
#[cfg(test)]
const fn is_leaf(&self, node: TreeNode) -> bool {
node.level() == self.block_size.to_u32()
}
#[inline]
#[cfg(test)]
const fn is_persisted(&self, node: TreeNode) -> bool {
!self.is_leaf(node) || node.mid().to_bytes() < self.size
}
#[inline]
const fn is_relevant_for_outboard(&self, node: TreeNode) -> bool {
let level = node.level();
if level < self.block_size.to_u32() {
false
} else if level > self.block_size.to_u32() {
true
} else {
node.mid().to_bytes() < self.size
}
}
pub fn pre_order_offset(&self, node: TreeNode) -> Option<u64> {
let shifted = node.add_block_size(self.block_size.0)?;
let is_half_leaf = shifted.is_leaf() && node.mid().to_bytes() >= self.size;
if !is_half_leaf {
let (_, tree_filled_size) = self.shifted();
Some(pre_order_offset_loop(shifted.0, tree_filled_size.0))
} else {
None
}
}
pub fn post_order_offset(&self, node: TreeNode) -> Option<PostOrderOffset> {
let shifted = node.add_block_size(self.block_size.0)?;
if node.byte_range().end <= self.size {
Some(PostOrderOffset::Stable(shifted.post_order_offset()))
} else {
if shifted.is_leaf() && node.mid().to_bytes() >= self.size {
None
} else {
self.outboard_hash_pairs()
.checked_sub(u64::from(node.right_count()) + 1)
.map(PostOrderOffset::Unstable)
}
}
}
const fn chunk_group_chunks(&self) -> ChunkNum {
ChunkNum(1 << self.block_size.0)
}
fn chunk_group_bytes(&self) -> usize {
self.chunk_group_chunks().to_bytes().try_into().unwrap()
}
}
pub(crate) const fn blocks(size: u64, block_size: BlockSize) -> u64 {
let chunk_group_log = block_size.0;
let block_bits = chunk_group_log + 10;
let block_mask = (1 << block_bits) - 1;
let full_blocks = size >> block_bits;
let open_block = ((size & block_mask) != 0) as u64;
full_blocks + open_block
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TreeNode(u64);
impl fmt::Display for TreeNode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl fmt::Debug for TreeNode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if !f.alternate() {
write!(f, "TreeNode({})", self.0)
} else if self.is_leaf() {
write!(f, "TreeNode::Leaf({})", self.0)
} else {
write!(f, "TreeNode::Branch({}, level={})", self.0, self.level())
}
}
}
impl TreeNode {
#[cfg(all(test, feature = "tokio_fsm"))]
fn from_start_chunk_and_level(start_chunk: ChunkNum, level: BlockSize) -> Self {
let start_chunk = start_chunk.0;
let level = level.0;
let check_mask = (1 << (level + 1)) - 1;
debug_assert_eq!(start_chunk & check_mask, 0);
let level_mask = (1 << level) - 1;
Self(start_chunk | level_mask)
}
fn root(chunks: ChunkNum) -> TreeNode {
Self(chunks.0.div_ceil(2).next_power_of_two() - 1)
}
pub const fn mid(&self) -> ChunkNum {
ChunkNum(self.0 + 1)
}
#[inline]
const fn half_span(&self) -> u64 {
1 << self.level()
}
#[inline]
pub const fn level(&self) -> u32 {
self.0.trailing_ones()
}
#[inline]
pub const fn is_leaf(&self) -> bool {
(self.0 & 1) == 0
}
#[inline]
pub const fn subtract_block_size(&self, n: u8) -> Self {
let shifted = !(!self.0 << n);
Self(shifted)
}
#[inline]
pub const fn add_block_size(&self, n: u8) -> Option<Self> {
let mask = (1 << n) - 1;
if self.0 & mask == mask {
Some(Self(self.0 >> n))
} else {
None
}
}
fn byte_range(&self) -> Range<u64> {
let range = self.chunk_range();
range.start.to_bytes()..range.end.to_bytes()
}
#[inline]
pub const fn count_below(&self) -> u64 {
let x = self.0 + 1;
let lowest_bit = x & (-(x as i64) as u64);
lowest_bit * 2 - 2
}
pub fn next_left_ancestor(&self) -> Option<Self> {
self.next_left_ancestor0().map(Self)
}
pub fn left_child(&self) -> Option<Self> {
let offset = 1 << self.level().checked_sub(1)?;
Some(Self(self.0 - offset))
}
pub fn right_child(&self) -> Option<Self> {
let offset = 1 << self.level().checked_sub(1)?;
Some(Self(self.0 + offset))
}
pub fn parent(&self) -> Option<Self> {
let level = self.level();
if level == 63 {
return None;
}
let span = 1u64 << level;
let offset = self.0;
Some(Self(if (offset & (span * 2)) == 0 {
offset + span
} else {
offset - span
}))
}
pub fn restricted_parent(&self, len: Self) -> Option<Self> {
let mut curr = *self;
while let Some(parent) = curr.parent() {
if parent.0 < len.0 {
return Some(parent);
}
curr = parent;
}
None
}
pub(crate) fn right_descendant(&self, len: Self) -> Option<Self> {
let mut node = self.right_child()?;
while node >= len {
node = node.left_child()?;
}
Some(node)
}
pub const fn node_range(&self) -> Range<Self> {
let half_span = self.half_span();
let nn = self.0;
let r = nn + half_span;
let l = nn + 1 - half_span;
Self(l)..Self(r)
}
pub fn chunk_range(&self) -> Range<ChunkNum> {
let level = self.level();
let span = 1 << level;
let mid = self.0 + 1;
ChunkNum(mid - span)..ChunkNum(mid + span)
}
pub fn right_count(&self) -> u32 {
(self.0 + 1).count_ones() - 1
}
#[inline]
pub const fn post_order_offset(&self) -> u64 {
let below_me = self.count_below();
let next_left_ancestor = self.next_left_ancestor0();
match next_left_ancestor {
Some(nla) => below_me + nla + 1 - ((nla + 1).count_ones() as u64),
None => below_me,
}
}
pub const fn post_order_range(&self) -> Range<u64> {
let offset = self.post_order_offset();
let end = offset + 1;
let start = offset - self.count_below();
start..end
}
#[inline]
const fn next_left_ancestor0(&self) -> Option<u64> {
let x = self.0 + 1;
let without_lowest_bit = x & (x - 1);
without_lowest_bit.checked_sub(1)
}
}
fn pre_order_offset_loop(node: u64, len: u64) -> u64 {
let level = (!node).trailing_zeros();
let span = 1u64 << level;
let left = node + 1 - span;
let mut parent_count = 0;
let mut offset = node;
let mut span = span;
loop {
let pspan = span * 2;
offset = if (offset & pspan) == 0 {
offset + span
} else {
offset - span
};
if offset < len {
parent_count += 1;
}
if pspan >= len {
break;
}
span = pspan;
}
left - (left.count_ones() as u64) + parent_count
}
pub(crate) fn split(
ranges: &RangeSetRef<ChunkNum>,
node: TreeNode,
) -> (&RangeSetRef<ChunkNum>, &RangeSetRef<ChunkNum>) {
let mid = node.mid();
let start = node.chunk_range().start;
split_inner(ranges, start, mid)
}
pub(crate) fn split_inner(
ranges: &RangeSetRef<ChunkNum>,
start: ChunkNum,
mid: ChunkNum,
) -> (&RangeSetRef<ChunkNum>, &RangeSetRef<ChunkNum>) {
let (mut a, mut b) = ranges.split(mid);
debug_assert!(a.boundaries().last() < Some(&mid));
if a.boundaries().len() == 1 && a.boundaries()[0] <= start {
a = RangeSetRef::new(&[ChunkNum(0)]).unwrap();
}
if b.boundaries().len() == 1 && b.boundaries()[0] <= mid {
b = RangeSetRef::new(&[ChunkNum(0)]).unwrap();
}
(a, b)
}
#[cfg(feature = "serde")]
mod io_error_serde {
use std::{fmt, io};
use serde::{
de::{self, Visitor},
Deserializer, Serializer,
};
pub fn serialize<S>(error: &io::Error, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&format!("{:?}:{}", error.kind(), error))
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<io::Error, D::Error>
where
D: Deserializer<'de>,
{
struct IoErrorVisitor;
impl Visitor<'_> for IoErrorVisitor {
type Value = io::Error;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("an io::Error string representation")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(io::Error::other(value))
}
}
deserializer.deserialize_str(IoErrorVisitor)
}
}