1use std::fmt;
2use std::num::NonZeroU16;
3use std::ops::Range;
4
5use serde::Deserialize;
6use serde::Serialize;
7
8use crate::error::Error;
9
10#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
12#[repr(transparent)]
13pub struct ByteOffset(pub u64);
14
15impl ByteOffset {
16 pub const ZERO: Self = Self(0);
17
18 pub fn new(offset: u64) -> Self {
19 Self(offset)
20 }
21
22 pub fn get(self) -> u64 {
23 self.0
24 }
25
26 pub fn checked_add_len(self, len: ByteLen) -> Option<Self> {
27 self.0.checked_add(len.0).map(Self)
28 }
29
30 pub fn saturating_add_len(self, len: ByteLen) -> Self {
31 Self(self.0.saturating_add(len.0))
32 }
33}
34
35impl fmt::Display for ByteOffset {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 write!(f, "0x{:X}", self.0)
38 }
39}
40
41impl From<u64> for ByteOffset {
42 fn from(value: u64) -> Self {
43 Self(value)
44 }
45}
46
47#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
50#[repr(transparent)]
51pub struct ByteLen(pub u64);
52
53impl ByteLen {
54 pub const ZERO: Self = Self(0);
55
56 pub fn new(len: u64) -> Self {
57 Self(len)
58 }
59
60 pub fn get(self) -> u64 {
61 self.0
62 }
63
64 pub fn is_zero(self) -> bool {
65 self.0 == 0
66 }
67}
68
69impl fmt::Display for ByteLen {
70 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71 write!(f, "{} bytes", self.0)
72 }
73}
74
75impl From<u64> for ByteLen {
76 fn from(value: u64) -> Self {
77 Self(value)
78 }
79}
80
81#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
85pub struct ByteRange {
86 start: ByteOffset,
87 end: ByteOffset,
88}
89
90impl ByteRange {
91 pub fn new(start: ByteOffset, end: ByteOffset) -> Result<Self, Error> {
92 if start > end {
93 return Err(Error::InvalidRange { start, end });
94 }
95 Ok(Self { start, end })
96 }
97
98 pub fn from_offset_and_len(start: ByteOffset, len: ByteLen) -> Result<Self, Error> {
99 let end = start.checked_add_len(len).ok_or(Error::InvalidRange { start, end: ByteOffset(u64::MAX) })?;
100 Ok(Self { start, end })
101 }
102
103 pub fn start(self) -> ByteOffset {
104 self.start
105 }
106
107 pub fn end(self) -> ByteOffset {
108 self.end
109 }
110
111 pub fn len(self) -> ByteLen {
112 ByteLen(self.end.0 - self.start.0)
113 }
114
115 pub fn is_empty(self) -> bool {
116 self.start == self.end
117 }
118
119 pub fn contains(self, offset: ByteOffset) -> bool {
120 self.start <= offset && offset < self.end
121 }
122
123 pub fn as_u64_range(self) -> Range<u64> {
124 self.start.0..self.end.0
125 }
126}
127
128impl fmt::Display for ByteRange {
129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130 write!(f, "{}..{}", self.start, self.end)
131 }
132}
133
134#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
139#[repr(transparent)]
140pub struct ColumnCount(NonZeroU16);
141
142impl ColumnCount {
143 pub const DEFAULT: Self = match NonZeroU16::new(16) {
144 Some(n) => Self(n),
145 None => unreachable!(),
146 };
147
148 pub fn new(cols: u16) -> Result<Self, Error> {
149 NonZeroU16::new(cols).map(Self).ok_or(Error::ZeroColumns)
150 }
151
152 pub fn get(self) -> u16 {
153 self.0.get()
154 }
155
156 pub fn as_u64(self) -> u64 {
157 u64::from(self.0.get())
158 }
159}
160
161impl Default for ColumnCount {
162 fn default() -> Self {
163 Self::DEFAULT
164 }
165}
166
167#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
169#[repr(transparent)]
170pub struct RowIndex(pub u64);
171
172impl RowIndex {
173 pub fn new(row: u64) -> Self {
174 Self(row)
175 }
176
177 pub fn get(self) -> u64 {
178 self.0
179 }
180
181 pub fn start_offset(self, columns: ColumnCount) -> ByteOffset {
183 ByteOffset(self.0.saturating_mul(columns.as_u64()))
184 }
185}
186
187impl fmt::Display for RowIndex {
188 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
189 write!(f, "{}", self.0)
190 }
191}
192
193#[cfg(test)]
194mod tests {
195 use super::*;
196
197 #[test]
198 fn range_invariant() {
199 assert!(ByteRange::new(ByteOffset(5), ByteOffset(3)).is_err());
200 let r = ByteRange::new(ByteOffset(0), ByteOffset(10)).unwrap();
201 assert_eq!(r.len().get(), 10);
202 assert!(!r.is_empty());
203 assert!(r.contains(ByteOffset(0)));
204 assert!(r.contains(ByteOffset(9)));
205 assert!(!r.contains(ByteOffset(10)));
206 }
207
208 #[test]
209 fn row_start_offset_with_default_columns() {
210 let row = RowIndex::new(3);
211 assert_eq!(row.start_offset(ColumnCount::DEFAULT), ByteOffset(48));
212 }
213
214 #[test]
215 fn column_count_rejects_zero() {
216 assert!(ColumnCount::new(0).is_err());
217 assert_eq!(ColumnCount::new(32).unwrap().get(), 32);
218 }
219}