bit_buf/read.rs
1use crate::{BitBuf, Error, Result, Storage};
2
3impl<S: Storage> BitBuf<S> {
4 /// Read a BE-bit-order [`u8`] from `byte_offset` without performing bound checks
5 ///
6 /// # Safety
7 ///
8 /// * This is UB if [`byte_offset >= self.bytes().len()`][Self::bytes]
9 ///
10 /// # Panics
11 ///
12 /// * Panics in debug mode if [`byte_offset >= self.bytes().len()`][Self::bytes]
13 #[inline(always)]
14 #[must_use]
15 pub unsafe fn read_u8_be_aligned_full_at_unchecked(&self, byte_offset: usize) -> u8 {
16 let bytes = self.bytes();
17
18 debug_assert!(
19 byte_offset < bytes.len(),
20 "BitBuf::read_u8_be_aligned_full_at_unchecked: index out of bounds! len is {}, offset is {}",
21 bytes.len(),
22 byte_offset,
23 );
24
25 unsafe { *bytes.get_unchecked(byte_offset) }
26 }
27
28 /// Read the next BE-bit-order [`u8`] without performing bound checks, advancing the internal cursor
29 ///
30 /// # Safety
31 ///
32 /// * The internal cursor must be byte-aligned ([`self.is_aligned()`][Self::is_aligned])
33 /// * This is UB if the internal cursor points past the end of storage (<code>[self.byte_pos()][Self::byte_pos] >= [self.bytes().len()][Self::bytes]</code>)
34 ///
35 /// # Panics
36 ///
37 /// * Panics in debug mode if the internal cursor is not byte-aligned ([`!self.is_aligned()`][Self::is_aligned])
38 /// * Panics in debug mode if the internal cursor points past the end of storage (<code>[self.byte_pos()][Self::byte_pos] >= [self.bytes().len()][Self::bytes]</code>)
39 #[inline(always)]
40 #[must_use]
41 pub unsafe fn read_u8_be_aligned_full_unchecked(&mut self) -> u8 {
42 debug_assert!(
43 self.is_aligned(),
44 "BitBuf::read_u8_be_aligned_full_unchecked called at unaligned bit position: {}",
45 self.pos(),
46 );
47
48 let b = unsafe { self.read_u8_be_aligned_full_at_unchecked(self.byte_pos()) };
49 self.advance_bytes(1);
50 b
51 }
52
53 /// Read a BE-bit-order [`u8`] from `offset` without performing bound checks
54 ///
55 /// # Safety
56 ///
57 /// * This is UB if <code>(offset / 8) >= [`self.bytes().len()`][Self::bytes]</code>
58 /// * This is UB if <code>(offset % 8 != 0) && (offset / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
59 ///
60 /// # Panics
61 ///
62 /// * Panics in debug mode if <code>(offset / 8) >= [`self.bytes().len()`][Self::bytes]</code>
63 /// * Panics in debug mode if <code>(offset % 8 != 0) && (offset / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
64 #[inline(always)]
65 #[must_use]
66 pub unsafe fn read_u8_be_full_at_unchecked(&self, offset: usize) -> u8 {
67 let byte_idx = offset / 8;
68 let shift = offset % 8;
69
70 let bytes = self.bytes();
71
72 debug_assert!(
73 byte_idx < bytes.len(),
74 "BitBuf::read_u8_be_full_at_unchecked: index out of bounds! len is {}, byte_idx is {}",
75 bytes.len(),
76 byte_idx,
77 );
78
79 if shift == 0 {
80 unsafe { self.read_u8_be_aligned_full_at_unchecked(byte_idx) }
81 } else {
82 let next_idx = byte_idx + 1;
83
84 debug_assert!(
85 next_idx < bytes.len(),
86 "BitBuf::read_u8_be_full_at_unchecked: lookahead index out of bounds! len is {}, lookahead byte_idx is {}",
87 bytes.len(),
88 next_idx,
89 );
90
91 let (high, low) = unsafe {
92 (
93 *bytes.get_unchecked(byte_idx),
94 *bytes.get_unchecked(next_idx),
95 )
96 };
97
98 (high << shift) | (low >> (8 - shift))
99 }
100 }
101
102 /// Read the next BE-bit-order [`u8`] without performing bound checks, advancing the internal cursor
103 ///
104 /// # Safety
105 ///
106 /// * This is UB if <code>(self.pos() / 8) >= [`self.bytes().len()`][Self::bytes]</code>
107 /// * This is UB if <code>(self.pos() % 8 != 0) && (self.pos() / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
108 ///
109 /// # Panics
110 ///
111 /// * Panics in debug mode if <code>(self.pos() / 8) >= [`self.bytes().len()`][Self::bytes]</code>
112 /// * Panics in debug mode if <code>(self.pos() % 8 != 0) && (self.pos() / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
113 #[inline(always)]
114 #[must_use]
115 pub unsafe fn read_u8_be_full_unchecked(&mut self) -> u8 {
116 let b = unsafe { self.read_u8_be_full_at_unchecked(self.pos()) };
117 self.advance_bytes(1);
118 b
119 }
120
121 /// Read a BE-bit-order [`u8`] from `offset` while performing bound checks
122 ///
123 /// # Errors
124 ///
125 /// * Returns [`Error::OutOfBounds`]
126 /// * if <code>(offset / 8) >= [`self.bytes().len()`][Self::bytes]</code>
127 /// * if <code>(offset % 8 != 0) && (offset / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
128 #[inline(always)]
129 pub fn try_read_u8_be_full_at(&self, offset: usize) -> Result<u8> {
130 let byte_idx = offset / 8;
131 let shift = offset % 8;
132
133 let len = self.bytes().len();
134
135 if byte_idx >= len {
136 return Err(Error::OutOfBounds);
137 }
138
139 if shift != 0 && byte_idx + 1 >= len {
140 return Err(Error::OutOfBounds);
141 }
142
143 Ok(unsafe { self.read_u8_be_full_at_unchecked(offset) })
144 }
145
146 /// Read the next BE-bit-order [`u8`] while performing bound checks, advancing the internal cursor
147 ///
148 /// # Errors
149 ///
150 /// * Returns [`Error::OutOfBounds`]
151 /// * if <code>(self.pos() / 8) >= [`self.bytes().len()`][Self::bytes]</code>
152 /// * if <code>(self.pos() % 8 != 0) && (self.pos() / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
153 #[inline(always)]
154 pub fn try_read_u8_be_full(&mut self) -> Result<u8> {
155 let b = self.try_read_u8_be_full_at(self.pos())?;
156 self.advance_bytes(1);
157 Ok(b)
158 }
159
160 /// Read a BE-bit-order [`u8`] from `offset`, panicking on out of bounds
161 ///
162 /// # Panics
163 ///
164 /// * Panics if <code>(offset / 8) >= [`self.bytes().len()`][Self::bytes]</code>
165 /// * Panics if <code>(offset % 8 != 0) && (offset / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
166 #[inline(always)]
167 #[must_use]
168 pub fn read_u8_be_full_at(&self, offset: usize) -> u8 {
169 self
170 .try_read_u8_be_full_at(offset)
171 .expect("BitBuf::read_u8_be_full_at out of bounds")
172 }
173
174 /// Read the next BE-bit-order [`u8`], panicking on out of bounds, advancing the internal cursor
175 ///
176 /// # Panics
177 ///
178 /// * Panics if <code>(self.pos() / 8) >= [`self.bytes().len()`][Self::bytes]</code>
179 /// * Panics if <code>(self.pos() % 8 != 0) && (self.pos() / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
180 #[inline(always)]
181 #[must_use]
182 pub fn read_u8_be_full(&mut self) -> u8 {
183 self
184 .try_read_u8_be_full()
185 .expect("BitBuf::read_u8_be_full out of bounds")
186 }
187
188 /// Read a [BE-bit, BE-byte] order [`u16`] from `byte_offset` without performing bound checks
189 ///
190 /// # Safety
191 ///
192 /// * This is UB if [`byte_offset + 1 >= self.bytes().len()`][Self::bytes]
193 ///
194 /// # Panics
195 ///
196 /// * Panics in debug mode if [`byte_offset + 1 >= self.bytes().len()`][Self::bytes]
197 #[inline(always)]
198 #[must_use]
199 pub unsafe fn read_u16_be_aligned_full_at_unchecked(&self, byte_offset: usize) -> u16 {
200 let bytes = self.bytes();
201
202 debug_assert!(
203 byte_offset + 1 < bytes.len(),
204 "BitBuf::read_u16_be_aligned_full_at_unchecked: index out of bounds! len is {}, offset is {}",
205 bytes.len(),
206 byte_offset + 1,
207 );
208
209 unsafe {
210 let high = *bytes.get_unchecked(byte_offset);
211 let low = *bytes.get_unchecked(byte_offset + 1);
212 u16::from_be_bytes([high, low])
213 }
214 }
215
216 /// Read the next [BE-bit, BE-byte] order [`u16`] without performing bound checks, advancing the internal cursor
217 ///
218 /// # Safety
219 ///
220 /// * The internal cursor must be byte-aligned ([`self.is_aligned()`][Self::is_aligned])
221 /// * This is UB if the internal cursor points past the end of storage (<code>[self.byte_pos()][Self::byte_pos] + 1 >= [self.bytes().len()][Self::bytes]</code>)
222 ///
223 /// # Panics
224 ///
225 /// * Panics in debug mode if the internal cursor is not byte-aligned ([`!self.is_aligned()`][Self::is_aligned])
226 /// * Panics in debug mode if the internal cursor points past the end of storage (<code>[self.byte_pos()][Self::byte_pos] + 1 >= [self.bytes().len()][Self::bytes]</code>)
227 #[inline(always)]
228 #[must_use]
229 pub unsafe fn read_u16_be_aligned_full_unchecked(&mut self) -> u16 {
230 debug_assert!(
231 self.is_aligned(),
232 "BitBuf::read_u16_be_aligned_full_unchecked called at unaligned bit position: {}",
233 self.pos(),
234 );
235
236 let v = unsafe { self.read_u16_be_aligned_full_at_unchecked(self.byte_pos()) };
237 self.advance_bytes(2);
238 v
239 }
240
241 /// Read a [BE-bit, BE-byte] order [`u16`] from `offset` without performing bound checks
242 ///
243 /// # Safety
244 ///
245 /// * This is UB if <code>(offset / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
246 /// * This is UB if <code>(offset % 8 != 0) && (offset / 8) + 2 >= [`self.bytes().len()`][Self::bytes]</code>
247 ///
248 /// # Panics
249 ///
250 /// * Panics in debug mode if <code>(offset / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
251 /// * Panics in debug mode if <code>(offset % 8 != 0) && (offset / 8) + 2 >= [`self.bytes().len()`][Self::bytes]</code>
252 #[inline(always)]
253 #[must_use]
254 pub unsafe fn read_u16_be_full_at_unchecked(&self, offset: usize) -> u16 {
255 let first_idx = offset / 8;
256 let shift = offset % 8;
257
258 let bytes = self.bytes();
259
260 debug_assert!(
261 first_idx + 1 < bytes.len(),
262 "BitBuf::read_u16_be_full_at_unchecked: index out of bounds! len is {}, byte_idx is {}",
263 bytes.len(),
264 first_idx + 1,
265 );
266
267 if shift == 0 {
268 unsafe { self.read_u16_be_aligned_full_at_unchecked(first_idx) }
269 } else {
270 let second_idx = first_idx + 1;
271 let third_idx = first_idx + 2;
272
273 debug_assert!(
274 third_idx < bytes.len(),
275 "BitBuf::read_u16_be_full_at_unchecked: lookahead index out of bounds! len is {}, lookahead byte_idx is {}",
276 bytes.len(),
277 third_idx,
278 );
279
280 let (a, b, c) = unsafe {
281 (
282 *bytes.get_unchecked(first_idx),
283 *bytes.get_unchecked(second_idx),
284 *bytes.get_unchecked(third_idx),
285 )
286 };
287
288 let high = ((a as u16) << shift) | ((b as u16) >> (8 - shift));
289 let low = ((b as u16) << shift) | ((c as u16) >> (8 - shift));
290
291 (high << 8) | (low & 0xFF)
292 }
293 }
294
295 /// Read the next [BE-bit, BE-byte] order [`u16`] without performing bound checks, advancing the internal cursor
296 ///
297 /// # Safety
298 ///
299 /// * This is UB if <code>(self.pos() / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
300 /// * This is UB if <code>(self.pos() % 8 != 0) && (self.pos() / 8) + 2 >= [`self.bytes().len()`][Self::bytes]</code>
301 ///
302 /// # Panics
303 ///
304 /// * Panics in debug mode if <code>(self.pos() / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
305 /// * Panics in debug mode if <code>(self.pos() % 8 != 0) && (self.pos() / 8) + 2 >= [`self.bytes().len()`][Self::bytes]</code>
306 #[inline(always)]
307 #[must_use]
308 pub unsafe fn read_u16_be_full_unchecked(&mut self) -> u16 {
309 let v = unsafe { self.read_u16_be_full_at_unchecked(self.pos()) };
310 self.advance_bytes(2);
311 v
312 }
313
314 /// Read a [BE-bit, BE-byte] order [`u16`] from `offset` while performing bound checks
315 ///
316 /// # Errors
317 ///
318 /// * Returns [`Error::OutOfBounds`]
319 /// * if <code>(offset / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
320 /// * if <code>(offset % 8 != 0) && (offset / 8) + 2 >= [`self.bytes().len()`][Self::bytes]</code>
321 #[inline(always)]
322 pub fn try_read_u16_be_full_at(&self, offset: usize) -> Result<u16> {
323 let first_idx = offset / 8;
324 let shift = offset % 8;
325
326 let len = self.bytes().len();
327
328 if first_idx + 1 >= len {
329 return Err(Error::OutOfBounds);
330 }
331
332 if shift != 0 && first_idx + 2 >= len {
333 return Err(Error::OutOfBounds);
334 }
335
336 Ok(unsafe { self.read_u16_be_full_at_unchecked(offset) })
337 }
338
339 /// Read the next [BE-bit, BE-byte] order [`u16`] while performing bound checks, advancing the internal cursor
340 ///
341 /// # Errors
342 ///
343 /// * Returns [`Error::OutOfBounds`]
344 /// * if <code>(self.pos() / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
345 /// * if <code>(self.pos() % 8 != 0) && (self.pos() / 8) + 2 >= [`self.bytes().len()`][Self::bytes]</code>
346 #[inline(always)]
347 pub fn try_read_u16_be_full(&mut self) -> Result<u16> {
348 let v = self.try_read_u16_be_full_at(self.pos())?;
349 self.advance_bytes(2);
350 Ok(v)
351 }
352
353 /// Read a [BE-bit, BE-byte] order [`u16`] from `offset`, panicking on out of bounds
354 ///
355 /// # Panics
356 ///
357 /// * Panics if <code>(offset / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
358 /// * Panics if <code>(offset % 8 != 0) && (offset / 8) + 2 >= [`self.bytes().len()`][Self::bytes]</code>
359 #[inline(always)]
360 #[must_use]
361 pub fn read_u16_be_full_at(&self, offset: usize) -> u16 {
362 self
363 .try_read_u16_be_full_at(offset)
364 .expect("BitBuf::read_u16_be_full_at out of bounds")
365 }
366
367 /// Read the next [BE-bit, BE-byte] order [`u16`], panicking on out of bounds, advancing the internal cursor
368 ///
369 /// # Panics
370 ///
371 /// * Panics if <code>(self.pos() / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
372 /// * Panics if <code>(self.pos() % 8 != 0) && (self.pos() / 8) + 2 >= [`self.bytes().len()`][Self::bytes]</code>
373 #[inline(always)]
374 #[must_use]
375 pub fn read_u16_be_full(&mut self) -> u16 {
376 self
377 .try_read_u16_be_full()
378 .expect("BitBuf::read_u16_be_full out of bounds")
379 }
380}