1use std::{
5 fmt,
6 ops::{Add, Div, Mul, Sub},
7};
8
9use range_collections::range_set::RangeSetEntry;
10
11#[repr(transparent)]
16#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
17#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
18pub struct ChunkNum(pub u64);
19
20impl std::fmt::Debug for ChunkNum {
21 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22 if f.alternate() {
23 write!(f, "ChunkNum({:#x})", self.0)
24 } else {
25 write!(f, "{}", self.0)
26 }
27 }
28}
29
30impl std::fmt::Display for ChunkNum {
31 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32 std::fmt::Debug::fmt(self, f)
33 }
34}
35
36impl RangeSetEntry for ChunkNum {
37 fn min_value() -> Self {
38 ChunkNum(0)
39 }
40
41 fn is_min_value(&self) -> bool {
42 self.0 == 0
43 }
44}
45
46impl Mul<u64> for ChunkNum {
47 type Output = ChunkNum;
48
49 fn mul(self, rhs: u64) -> Self::Output {
50 ChunkNum(self.0 * rhs)
51 }
52}
53
54impl Div<u64> for ChunkNum {
55 type Output = ChunkNum;
56
57 fn div(self, rhs: u64) -> Self::Output {
58 ChunkNum(self.0 / rhs)
59 }
60}
61
62impl Sub<u64> for ChunkNum {
63 type Output = ChunkNum;
64
65 fn sub(self, rhs: u64) -> Self::Output {
66 ChunkNum(self.0 - rhs)
67 }
68}
69
70impl Sub<ChunkNum> for ChunkNum {
71 type Output = ChunkNum;
72
73 fn sub(self, rhs: ChunkNum) -> Self::Output {
74 ChunkNum(self.0 - rhs.0)
75 }
76}
77
78impl Add<u64> for ChunkNum {
79 type Output = ChunkNum;
80
81 fn add(self, rhs: u64) -> Self::Output {
82 ChunkNum(self.0 + rhs)
83 }
84}
85
86impl Add<ChunkNum> for ChunkNum {
87 type Output = ChunkNum;
88
89 fn add(self, rhs: ChunkNum) -> Self::Output {
90 ChunkNum(self.0 + rhs.0)
91 }
92}
93
94impl PartialEq<u64> for ChunkNum {
95 fn eq(&self, other: &u64) -> bool {
96 self.0 == *other
97 }
98}
99
100impl PartialEq<ChunkNum> for u64 {
101 fn eq(&self, other: &ChunkNum) -> bool {
102 *self == other.0
103 }
104}
105
106impl PartialOrd<u64> for ChunkNum {
107 fn partial_cmp(&self, other: &u64) -> Option<std::cmp::Ordering> {
108 self.0.partial_cmp(other)
109 }
110}
111
112impl ChunkNum {
113 pub fn to_usize(self) -> usize {
115 usize::try_from(self.0).expect("usize overflow")
116 }
117}
118
119pub(crate) const BLAKE3_CHUNK_SIZE: usize = 1024;
120
121#[repr(transparent)]
131#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
132pub struct BlockSize(pub(crate) u8);
133
134impl fmt::Display for BlockSize {
135 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136 fmt::Debug::fmt(&self, f)
137 }
138}
139
140impl BlockSize {
141 pub const fn from_chunk_log(chunk_log: u8) -> Self {
145 Self(chunk_log)
146 }
147
148 pub const fn chunk_log(self) -> u8 {
150 self.0
151 }
152
153 pub const ZERO: BlockSize = BlockSize(0);
157
158 pub const fn bytes(self) -> usize {
160 BLAKE3_CHUNK_SIZE << self.0
161 }
162
163 pub const fn from_bytes(bytes: u64) -> Option<Self> {
165 if bytes.count_ones() != 1 {
166 return None;
168 }
169 if bytes < 1024 {
170 return None;
172 }
173 Some(Self((bytes.trailing_zeros() - 10) as u8))
174 }
175
176 pub(crate) const fn to_u32(self) -> u32 {
178 self.0 as u32
179 }
180}
181
182impl ChunkNum {
183 pub const fn chunk_group_start(start: ChunkNum, block_size: BlockSize) -> ChunkNum {
185 ChunkNum((start.0 >> block_size.0) << block_size.0)
186 }
187
188 pub const fn chunk_group_end(end: ChunkNum, block_size: BlockSize) -> ChunkNum {
190 let mask = (1 << block_size.0) - 1;
191 let part = ((end.0 & mask) != 0) as u64;
192 let whole = end.0 >> block_size.0;
193 ChunkNum((whole + part) << block_size.0)
194 }
195
196 pub const fn chunks(size: u64) -> ChunkNum {
200 let mask = (1 << 10) - 1;
201 let part = ((size & mask) != 0) as u64;
202 let whole = size >> 10;
203 ChunkNum(whole + part)
204 }
205
206 pub const fn full_chunks(size: u64) -> ChunkNum {
210 ChunkNum(size >> 10)
211 }
212
213 pub const fn to_bytes(&self) -> u64 {
215 self.0 << 10
216 }
217}