use std::{
fmt,
ops::{Add, Div, Mul, Sub},
};
use range_collections::range_set::RangeSetEntry;
#[repr(transparent)]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ChunkNum(pub u64);
impl std::fmt::Debug for ChunkNum {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if f.alternate() {
write!(f, "ChunkNum({:#x})", self.0)
} else {
write!(f, "{}", self.0)
}
}
}
impl std::fmt::Display for ChunkNum {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Debug::fmt(self, f)
}
}
impl RangeSetEntry for ChunkNum {
fn min_value() -> Self {
ChunkNum(0)
}
fn is_min_value(&self) -> bool {
self.0 == 0
}
}
impl Mul<u64> for ChunkNum {
type Output = ChunkNum;
fn mul(self, rhs: u64) -> Self::Output {
ChunkNum(self.0 * rhs)
}
}
impl Div<u64> for ChunkNum {
type Output = ChunkNum;
fn div(self, rhs: u64) -> Self::Output {
ChunkNum(self.0 / rhs)
}
}
impl Sub<u64> for ChunkNum {
type Output = ChunkNum;
fn sub(self, rhs: u64) -> Self::Output {
ChunkNum(self.0 - rhs)
}
}
impl Sub<ChunkNum> for ChunkNum {
type Output = ChunkNum;
fn sub(self, rhs: ChunkNum) -> Self::Output {
ChunkNum(self.0 - rhs.0)
}
}
impl Add<u64> for ChunkNum {
type Output = ChunkNum;
fn add(self, rhs: u64) -> Self::Output {
ChunkNum(self.0 + rhs)
}
}
impl Add<ChunkNum> for ChunkNum {
type Output = ChunkNum;
fn add(self, rhs: ChunkNum) -> Self::Output {
ChunkNum(self.0 + rhs.0)
}
}
impl PartialEq<u64> for ChunkNum {
fn eq(&self, other: &u64) -> bool {
self.0 == *other
}
}
impl PartialEq<ChunkNum> for u64 {
fn eq(&self, other: &ChunkNum) -> bool {
*self == other.0
}
}
impl PartialOrd<u64> for ChunkNum {
fn partial_cmp(&self, other: &u64) -> Option<std::cmp::Ordering> {
self.0.partial_cmp(other)
}
}
impl ChunkNum {
pub fn to_usize(self) -> usize {
usize::try_from(self.0).expect("usize overflow")
}
}
pub(crate) const BLAKE3_CHUNK_SIZE: usize = 1024;
#[repr(transparent)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct BlockSize(pub(crate) u8);
impl fmt::Display for BlockSize {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self, f)
}
}
impl BlockSize {
pub const fn from_chunk_log(chunk_log: u8) -> Self {
Self(chunk_log)
}
pub const fn chunk_log(self) -> u8 {
self.0
}
pub const ZERO: BlockSize = BlockSize(0);
pub const fn bytes(self) -> usize {
BLAKE3_CHUNK_SIZE << self.0
}
pub const fn from_bytes(bytes: u64) -> Option<Self> {
if bytes.count_ones() != 1 {
return None;
}
if bytes < 1024 {
return None;
}
Some(Self((bytes.trailing_zeros() - 10) as u8))
}
pub(crate) const fn to_u32(self) -> u32 {
self.0 as u32
}
}
impl ChunkNum {
pub const fn chunk_group_start(start: ChunkNum, block_size: BlockSize) -> ChunkNum {
ChunkNum((start.0 >> block_size.0) << block_size.0)
}
pub const fn chunk_group_end(end: ChunkNum, block_size: BlockSize) -> ChunkNum {
let mask = (1 << block_size.0) - 1;
let part = ((end.0 & mask) != 0) as u64;
let whole = end.0 >> block_size.0;
ChunkNum((whole + part) << block_size.0)
}
pub const fn chunks(size: u64) -> ChunkNum {
let mask = (1 << 10) - 1;
let part = ((size & mask) != 0) as u64;
let whole = size >> 10;
ChunkNum(whole + part)
}
pub const fn full_chunks(size: u64) -> ChunkNum {
ChunkNum(size >> 10)
}
pub const fn to_bytes(&self) -> u64 {
self.0 << 10
}
}