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_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_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_unchecked(&mut self) -> u8 {
42 debug_assert!(
43 self.is_aligned(),
44 "BitBuf::read_u8_be_aligned_unchecked called at unaligned bit position: {}",
45 self.pos(),
46 );
47
48 let b = unsafe { self.read_u8_be_aligned_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_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_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_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_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_unchecked(&mut self) -> u8 {
116 let b = unsafe { self.read_u8_be_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_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_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(&mut self) -> Result<u8> {
155 let b = self.try_read_u8_be_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_at(&self, offset: usize) -> u8 {
169 self
170 .try_read_u8_be_at(offset)
171 .expect("BitBuf::read_u8_be_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(&mut self) -> u8 {
183 self
184 .try_read_u8_be()
185 .expect("BitBuf::read_u8_be out of bounds")
186 }
187
188 /// Read a [`u8`] containing `bits` count of BE-bit-order bits from `byte_offset` without performing bound checks
189 ///
190 /// # Safety
191 ///
192 /// * This is UB if `bits > 8`
193 /// * This is UB if [`byte_offset >= self.bytes().len()`][Self::bytes]
194 ///
195 /// # Panics
196 ///
197 /// * Panics in debug mode if `bits > 8`
198 /// * Panics in debug mode if [`byte_offset >= self.bytes().len()`][Self::bytes]
199 #[inline(always)]
200 #[must_use]
201 pub unsafe fn read_u8_be_aligned_bits_at_unchecked(&self, byte_offset: usize, bits: usize) -> u8 {
202 debug_assert!(
203 bits <= 8,
204 "BitBuf::read_u8_be_aligned_bits_at_unchecked: bits requested ({}) exceeds u8 width!",
205 bits,
206 );
207
208 let bytes = self.bytes();
209
210 debug_assert!(
211 byte_offset < bytes.len(),
212 "BitBuf::read_u8_be_aligned_bits_at_unchecked: index out of bounds! len is {}, offset is {}",
213 bytes.len(),
214 byte_offset,
215 );
216
217 if bits == 0 {
218 return 0;
219 }
220
221 let b = unsafe { *bytes.get_unchecked(byte_offset) };
222
223 b >> (8 - bits)
224 }
225
226 /// Read the next [`u8`] containing `bits` count of BE-bit-order bits without performing bound checks, advancing the internal cursor
227 ///
228 /// # Safety
229 ///
230 /// * This is UB if `bits > 8`
231 /// * The internal cursor must be byte-aligned ([`self.is_aligned()`][Self::is_aligned])
232 /// * 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>)
233 ///
234 /// # Panics
235 ///
236 /// * Panics in debug mode if `bits > 8`
237 /// * Panics in debug mode if the internal cursor is not byte-aligned ([`!self.is_aligned()`][Self::is_aligned])
238 /// * 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>)
239 #[inline(always)]
240 #[must_use]
241 pub unsafe fn read_u8_be_aligned_bits_unchecked(&mut self, bits: usize) -> u8 {
242 debug_assert!(
243 bits <= 8,
244 "BitBuf::read_u8_be_aligned_bits_unchecked: bits requested ({}) exceeds u8 width!",
245 bits,
246 );
247
248 debug_assert!(
249 self.is_aligned(),
250 "BitBuf::read_u8_be_aligned_bits_unchecked called at unaligned bit position: {}",
251 self.pos(),
252 );
253
254 let b = unsafe { self.read_u8_be_aligned_bits_at_unchecked(self.byte_pos(), bits) };
255 self.advance(bits);
256 b
257 }
258
259 /// Read a [`u8`] containing `bits` count of BE-bit-order bits from `offset` without performing bound checks
260 ///
261 /// # Safety
262 ///
263 /// * This is UB if `bits > 8`
264 /// * This is UB if <code>(offset / 8) >= [`self.bytes().len()`][Self::bytes]</code>
265 /// * This is UB if <code>(offset % 8 + bits > 8) && (offset / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
266 ///
267 /// # Panics
268 ///
269 /// * Panics in debug mode if `bits > 8`
270 /// * Panics in debug mode if <code>(offset / 8) >= [`self.bytes().len()`][Self::bytes]</code>
271 /// * Panics in debug mode if <code>(offset % 8 + bits > 8) && (offset / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
272 #[inline(always)]
273 #[must_use]
274 pub unsafe fn read_u8_be_bits_at_unchecked(&self, offset: usize, bits: usize) -> u8 {
275 debug_assert!(
276 bits <= 8,
277 "BitBuf::read_u8_be_bits_at_unchecked: bits requested ({}) exceeds u8 width!",
278 bits,
279 );
280
281 if bits == 0 {
282 return 0;
283 }
284
285 let byte_idx = offset / 8;
286 let shift = offset % 8;
287
288 let bytes = self.bytes();
289
290 debug_assert!(
291 byte_idx < bytes.len(),
292 "BitBuf::read_u8_be_bits_at_unchecked: index out of bounds! len is {}, byte_idx is {}",
293 bytes.len(),
294 byte_idx,
295 );
296
297 let high = unsafe { *bytes.get_unchecked(byte_idx) };
298
299 if shift + bits <= 8 {
300 (high << shift) >> (8 - bits)
301 } else {
302 let next_idx = byte_idx + 1;
303
304 debug_assert!(
305 next_idx < bytes.len(),
306 "BitBuf::read_u8_be_bits_at_unchecked: lookahead index out of bounds! len is {}, lookahead byte_idx is {}",
307 bytes.len(),
308 next_idx,
309 );
310
311 let low = unsafe { *bytes.get_unchecked(next_idx) };
312
313 let v = ((high as u16) << 8) | (low as u16);
314 ((v << shift) >> (16 - bits)) as u8
315 }
316 }
317
318 /// Read the next [`u8`] containing `bits` count of BE-bit-order bits without performing bound checks, advancing the internal cursor
319 ///
320 /// # Safety
321 ///
322 /// * This is UB if `bits > 8`
323 /// * This is UB if <code>(self.pos() / 8) >= [`self.bytes().len()`][Self::bytes]</code>
324 /// * This is UB if <code>(self.pos() % 8 + bits > 8) && (self.pos() / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
325 ///
326 /// # Panics
327 ///
328 /// * Panics in debug mode if `bits > 8`
329 /// * Panics in debug mode if <code>(self.pos() / 8) >= [`self.bytes().len()`][Self::bytes]</code>
330 /// * Panics in debug mode if <code>(self.pos() % 8 + bits > 8) && (self.pos() / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
331 #[inline(always)]
332 #[must_use]
333 pub unsafe fn read_u8_be_bits_unchecked(&mut self, bits: usize) -> u8 {
334 let b = unsafe { self.read_u8_be_bits_at_unchecked(self.pos(), bits) };
335 self.advance(bits);
336 b
337 }
338
339 /// Read a [`u8`] containing `bits` count of BE-bit-order bits from `offset` while performing bound checks
340 ///
341 /// # Errors
342 ///
343 /// * Returns [`Error::InvalidBitCount`] if `bits > 8`
344 /// * Returns [`Error::OutOfBounds`] if <code>(offset / 8) >= [`self.bytes().len()`][Self::bytes]</code>
345 /// * Returns [`Error::OutOfBounds`] if <code>(offset % 8 + bits > 8) && (offset / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
346 #[inline(always)]
347 pub fn try_read_u8_be_bits_at(&self, offset: usize, bits: usize) -> Result<u8> {
348 if bits > 8 {
349 return Err(Error::InvalidBitCount);
350 }
351
352 if bits == 0 {
353 return Ok(0);
354 }
355
356 let byte_idx = offset / 8;
357 let shift = offset % 8;
358
359 let len = self.bytes().len();
360
361 if byte_idx >= len {
362 return Err(Error::OutOfBounds);
363 }
364
365 if shift + bits > 8 && byte_idx + 1 >= len {
366 return Err(Error::OutOfBounds);
367 }
368
369 Ok(unsafe { self.read_u8_be_bits_at_unchecked(offset, bits) })
370 }
371
372 /// Read the next [`u8`] containing `bits` count of BE-bit-order bits while performing bound checks, advancing the internal cursor
373 ///
374 /// # Errors
375 ///
376 /// * Returns [`Error::InvalidBitCount`] if `bits > 8`
377 /// * Returns [`Error::OutOfBounds`] if <code>(self.pos() / 8) >= [`self.bytes().len()`][Self::bytes]</code>
378 /// * Returns [`Error::OutOfBounds`] if <code>(self.pos() % 8 + bits > 8) && (self.pos() / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
379 #[inline(always)]
380 pub fn try_read_u8_be_bits(&mut self, bits: usize) -> Result<u8> {
381 let b = self.try_read_u8_be_bits_at(self.pos(), bits)?;
382 self.advance(bits);
383 Ok(b)
384 }
385
386 /// Read a [`u8`] containing `bits` count of BE-bit-order bits from `offset`, panicking on out of bounds or if bit count is invalid
387 ///
388 /// # Panics
389 ///
390 /// * Panics if `bits > 8`
391 /// * Panics if <code>(offset / 8) >= [`self.bytes().len()`][Self::bytes]</code>
392 /// * Panics if <code>(offset % 8 + bits > 8) && (offset / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
393 #[inline(always)]
394 #[must_use]
395 pub fn read_u8_be_bits_at(&self, offset: usize, bits: usize) -> u8 {
396 self
397 .try_read_u8_be_bits_at(offset, bits)
398 .expect("BitBuf::read_u8_be_bits_at failed")
399 }
400
401 /// Read the next [`u8`] containing `bits` count of BE-bit-order bits, panicking on out of bounds or if bit count is invalid, advancing the internal cursor
402 ///
403 /// # Panics
404 ///
405 /// * Panics if `bits > 8`
406 /// * Panics if <code>(self.pos() / 8) >= [`self.bytes().len()`][Self::bytes]</code>
407 /// * Panics if <code>(self.pos() % 8 + bits > 8) && (self.pos() / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
408 #[inline(always)]
409 #[must_use]
410 pub fn read_u8_be_bits(&mut self, bits: usize) -> u8 {
411 self
412 .try_read_u8_be_bits(bits)
413 .expect("BitBuf::read_u8_be_bits failed")
414 }
415
416 /// Read a [BE-bit, BE-byte] order [`u16`] from `byte_offset` without performing bound checks
417 ///
418 /// # Safety
419 ///
420 /// * This is UB if [`byte_offset + 1 >= self.bytes().len()`][Self::bytes]
421 ///
422 /// # Panics
423 ///
424 /// * Panics in debug mode if [`byte_offset + 1 >= self.bytes().len()`][Self::bytes]
425 #[inline(always)]
426 #[must_use]
427 pub unsafe fn read_u16_be_aligned_at_unchecked(&self, byte_offset: usize) -> u16 {
428 let bytes = self.bytes();
429
430 debug_assert!(
431 byte_offset + 1 < bytes.len(),
432 "BitBuf::read_u16_be_aligned_at_unchecked: index out of bounds! len is {}, offset is {}",
433 bytes.len(),
434 byte_offset + 1,
435 );
436
437 unsafe {
438 let high = *bytes.get_unchecked(byte_offset);
439 let low = *bytes.get_unchecked(byte_offset + 1);
440 u16::from_be_bytes([high, low])
441 }
442 }
443
444 /// Read the next [BE-bit, BE-byte] order [`u16`] without performing bound checks, advancing the internal cursor
445 ///
446 /// # Safety
447 ///
448 /// * The internal cursor must be byte-aligned ([`self.is_aligned()`][Self::is_aligned])
449 /// * 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>)
450 ///
451 /// # Panics
452 ///
453 /// * Panics in debug mode if the internal cursor is not byte-aligned ([`!self.is_aligned()`][Self::is_aligned])
454 /// * 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>)
455 #[inline(always)]
456 #[must_use]
457 pub unsafe fn read_u16_be_aligned_unchecked(&mut self) -> u16 {
458 debug_assert!(
459 self.is_aligned(),
460 "BitBuf::read_u16_be_aligned_unchecked called at unaligned bit position: {}",
461 self.pos(),
462 );
463
464 let v = unsafe { self.read_u16_be_aligned_at_unchecked(self.byte_pos()) };
465 self.advance_bytes(2);
466 v
467 }
468
469 /// Read a [BE-bit, BE-byte] order [`u16`] from `offset` without performing bound checks
470 ///
471 /// # Safety
472 ///
473 /// * This is UB if <code>(offset / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
474 /// * This is UB if <code>(offset % 8 != 0) && (offset / 8) + 2 >= [`self.bytes().len()`][Self::bytes]</code>
475 ///
476 /// # Panics
477 ///
478 /// * Panics in debug mode if <code>(offset / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
479 /// * Panics in debug mode if <code>(offset % 8 != 0) && (offset / 8) + 2 >= [`self.bytes().len()`][Self::bytes]</code>
480 #[inline(always)]
481 #[must_use]
482 pub unsafe fn read_u16_be_at_unchecked(&self, offset: usize) -> u16 {
483 let first_idx = offset / 8;
484 let shift = offset % 8;
485
486 let bytes = self.bytes();
487
488 debug_assert!(
489 first_idx + 1 < bytes.len(),
490 "BitBuf::read_u16_be_at_unchecked: index out of bounds! len is {}, byte_idx is {}",
491 bytes.len(),
492 first_idx + 1,
493 );
494
495 if shift == 0 {
496 unsafe { self.read_u16_be_aligned_at_unchecked(first_idx) }
497 } else {
498 let second_idx = first_idx + 1;
499 let third_idx = first_idx + 2;
500
501 debug_assert!(
502 third_idx < bytes.len(),
503 "BitBuf::read_u16_be_at_unchecked: lookahead index out of bounds! len is {}, lookahead byte_idx is {}",
504 bytes.len(),
505 third_idx,
506 );
507
508 let (a, b, c) = unsafe {
509 (
510 *bytes.get_unchecked(first_idx),
511 *bytes.get_unchecked(second_idx),
512 *bytes.get_unchecked(third_idx),
513 )
514 };
515
516 let high = ((a as u16) << shift) | ((b as u16) >> (8 - shift));
517 let low = ((b as u16) << shift) | ((c as u16) >> (8 - shift));
518
519 (high << 8) | (low & 0xFF)
520 }
521 }
522
523 /// Read the next [BE-bit, BE-byte] order [`u16`] without performing bound checks, advancing the internal cursor
524 ///
525 /// # Safety
526 ///
527 /// * This is UB if <code>(self.pos() / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
528 /// * This is UB if <code>(self.pos() % 8 != 0) && (self.pos() / 8) + 2 >= [`self.bytes().len()`][Self::bytes]</code>
529 ///
530 /// # Panics
531 ///
532 /// * Panics in debug mode if <code>(self.pos() / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
533 /// * Panics in debug mode if <code>(self.pos() % 8 != 0) && (self.pos() / 8) + 2 >= [`self.bytes().len()`][Self::bytes]</code>
534 #[inline(always)]
535 #[must_use]
536 pub unsafe fn read_u16_be_unchecked(&mut self) -> u16 {
537 let v = unsafe { self.read_u16_be_at_unchecked(self.pos()) };
538 self.advance_bytes(2);
539 v
540 }
541
542 /// Read a [BE-bit, BE-byte] order [`u16`] from `offset` while performing bound checks
543 ///
544 /// # Errors
545 ///
546 /// * Returns [`Error::OutOfBounds`]
547 /// * if <code>(offset / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
548 /// * if <code>(offset % 8 != 0) && (offset / 8) + 2 >= [`self.bytes().len()`][Self::bytes]</code>
549 #[inline(always)]
550 pub fn try_read_u16_be_at(&self, offset: usize) -> Result<u16> {
551 let first_idx = offset / 8;
552 let shift = offset % 8;
553
554 let len = self.bytes().len();
555
556 if first_idx + 1 >= len {
557 return Err(Error::OutOfBounds);
558 }
559
560 if shift != 0 && first_idx + 2 >= len {
561 return Err(Error::OutOfBounds);
562 }
563
564 Ok(unsafe { self.read_u16_be_at_unchecked(offset) })
565 }
566
567 /// Read the next [BE-bit, BE-byte] order [`u16`] while performing bound checks, advancing the internal cursor
568 ///
569 /// # Errors
570 ///
571 /// * Returns [`Error::OutOfBounds`]
572 /// * if <code>(self.pos() / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
573 /// * if <code>(self.pos() % 8 != 0) && (self.pos() / 8) + 2 >= [`self.bytes().len()`][Self::bytes]</code>
574 #[inline(always)]
575 pub fn try_read_u16_be(&mut self) -> Result<u16> {
576 let v = self.try_read_u16_be_at(self.pos())?;
577 self.advance_bytes(2);
578 Ok(v)
579 }
580
581 /// Read a [BE-bit, BE-byte] order [`u16`] from `offset`, panicking on out of bounds
582 ///
583 /// # Panics
584 ///
585 /// * Panics if <code>(offset / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
586 /// * Panics if <code>(offset % 8 != 0) && (offset / 8) + 2 >= [`self.bytes().len()`][Self::bytes]</code>
587 #[inline(always)]
588 #[must_use]
589 pub fn read_u16_be_at(&self, offset: usize) -> u16 {
590 self
591 .try_read_u16_be_at(offset)
592 .expect("BitBuf::read_u16_be_at out of bounds")
593 }
594
595 /// Read the next [BE-bit, BE-byte] order [`u16`], panicking on out of bounds, advancing the internal cursor
596 ///
597 /// # Panics
598 ///
599 /// * Panics if <code>(self.pos() / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
600 /// * Panics if <code>(self.pos() % 8 != 0) && (self.pos() / 8) + 2 >= [`self.bytes().len()`][Self::bytes]</code>
601 #[inline(always)]
602 #[must_use]
603 pub fn read_u16_be(&mut self) -> u16 {
604 self
605 .try_read_u16_be()
606 .expect("BitBuf::read_u16_be out of bounds")
607 }
608
609 /// Read a [`u32`] in [BE-bit, BE-byte] order at `byte_offset` without performing bound checks
610 ///
611 /// # Safety
612 ///
613 /// * This is UB if [`byte_offset + 3 >= self.bytes().len()`][Self::bytes]
614 ///
615 /// # Panics
616 ///
617 /// * Panics in debug mode if [`byte_offset + 3 >= self.bytes().len()`][Self::bytes]
618 #[inline(always)]
619 #[must_use]
620 pub unsafe fn read_u32_be_aligned_at_unchecked(&self, byte_offset: usize) -> u32 {
621 let bytes = self.bytes();
622
623 debug_assert!(
624 byte_offset + 3 < bytes.len(),
625 "BitBuf::read_u32_be_aligned_at_unchecked: index out of bounds! len is {}, offset is {}",
626 bytes.len(),
627 byte_offset + 3,
628 );
629
630 unsafe {
631 let a = *bytes.get_unchecked(byte_offset);
632 let b = *bytes.get_unchecked(byte_offset + 1);
633 let c = *bytes.get_unchecked(byte_offset + 2);
634 let d = *bytes.get_unchecked(byte_offset + 3);
635 u32::from_be_bytes([a, b, c, d])
636 }
637 }
638
639 /// Read the next [`u32`] in [BE-bit, BE-byte] order without performing bound checks, advancing the internal cursor
640 ///
641 /// # Safety
642 ///
643 /// * The internal cursor must be byte-aligned ([`self.is_aligned()`][Self::is_aligned])
644 /// * This is UB if the internal cursor points past the end of storage (<code>[self.byte_pos()][Self::byte_pos] + 3 >= [self.bytes().len()][Self::bytes]</code>)
645 ///
646 /// # Panics
647 ///
648 /// * Panics in debug mode if the internal cursor is not byte-aligned ([`!self.is_aligned()`][Self::is_aligned])
649 /// * Panics in debug mode if the internal cursor points past the end of storage (<code>[self.byte_pos()][Self::byte_pos] + 3 >= [self.bytes().len()][Self::bytes]</code>)
650 #[inline(always)]
651 #[must_use]
652 pub unsafe fn read_u32_be_aligned_unchecked(&mut self) -> u32 {
653 debug_assert!(
654 self.is_aligned(),
655 "BitBuf::read_u32_be_aligned_unchecked called at unaligned bit position: {}",
656 self.pos(),
657 );
658
659 let v = unsafe { self.read_u32_be_aligned_at_unchecked(self.byte_pos()) };
660 self.advance_bytes(4);
661 v
662 }
663
664 /// Read a [`u32`] in [BE-bit, BE-byte] order from `offset` without performing bound checks
665 ///
666 /// # Safety
667 ///
668 /// * This is UB if <code>(offset / 8) + 3 >= [`self.bytes().len()`][Self::bytes]</code>
669 /// * This is UB if <code>(offset % 8 != 0) && (offset / 8) + 4 >= [`self.bytes().len()`][Self::bytes]</code>
670 ///
671 /// # Panics
672 ///
673 /// * Panics in debug mode if <code>(offset / 8) + 3 >= [`self.bytes().len()`][Self::bytes]</code>
674 /// * Panics in debug mode if <code>(offset % 8 != 0) && (offset / 8) + 4 >= [`self.bytes().len()`][Self::bytes]</code>
675 #[inline(always)]
676 #[must_use]
677 pub unsafe fn read_u32_be_at_unchecked(&self, offset: usize) -> u32 {
678 let first_idx = offset / 8;
679 let shift = offset % 8;
680
681 let bytes = self.bytes();
682
683 debug_assert!(
684 first_idx + 3 < bytes.len(),
685 "BitBuf::read_u32_be_at_unchecked: index out of bounds! len is {}, byte_idx is {}",
686 bytes.len(),
687 first_idx + 3,
688 );
689
690 if shift == 0 {
691 unsafe { self.read_u32_be_aligned_at_unchecked(first_idx) }
692 } else {
693 let second_idx = first_idx + 1;
694 let third_idx = first_idx + 2;
695 let fourth_idx = first_idx + 3;
696 let fifth_idx = first_idx + 4;
697
698 debug_assert!(
699 fifth_idx < bytes.len(),
700 "BitBuf::read_u32_be_at_unchecked: lookahead index out of bounds! len is {}, lookahead byte_idx is {}",
701 bytes.len(),
702 fifth_idx,
703 );
704
705 let (a, b, c, d, e) = unsafe {
706 (
707 *bytes.get_unchecked(first_idx),
708 *bytes.get_unchecked(second_idx),
709 *bytes.get_unchecked(third_idx),
710 *bytes.get_unchecked(fourth_idx),
711 *bytes.get_unchecked(fifth_idx),
712 )
713 };
714
715 let b0 = ((a as u32) << shift) | ((b as u32) >> (8 - shift));
716 let b1 = ((b as u32) << shift) | ((c as u32) >> (8 - shift));
717 let b2 = ((c as u32) << shift) | ((d as u32) >> (8 - shift));
718 let b3 = ((d as u32) << shift) | ((e as u32) >> (8 - shift));
719
720 (b0 << 24) | ((b1 & 0xFF) << 16) | ((b2 & 0xFF) << 8) | (b3 & 0xFF)
721 }
722 }
723
724 /// Read the next [`u32`] in [BE-bit, BE-byte] order without performing bound checks, advancing the internal cursor
725 ///
726 /// # Safety
727 ///
728 /// * This is UB if <code>(self.pos() / 8) + 3 >= [`self.bytes().len()`][Self::bytes]</code>
729 /// * This is UB if <code>(self.pos() % 8 != 0) && (self.pos() / 8) + 4 >= [`self.bytes().len()`][Self::bytes]</code>
730 ///
731 /// # Panics
732 ///
733 /// * Panics in debug mode if <code>(self.pos() / 8) + 3 >= [`self.bytes().len()`][Self::bytes]</code>
734 /// * Panics in debug mode if <code>(self.pos() % 8 != 0) && (self.pos() / 8) + 4 >= [`self.bytes().len()`][Self::bytes]</code>
735 #[inline(always)]
736 #[must_use]
737 pub unsafe fn read_u32_be_unchecked(&mut self) -> u32 {
738 let v = unsafe { self.read_u32_be_at_unchecked(self.pos()) };
739 self.advance_bytes(4);
740 v
741 }
742
743 /// Read a [BE-bit, BE-byte] order [`u32`] from `offset` while performing bound checks
744 ///
745 /// # Errors
746 ///
747 /// * Returns [`Error::OutOfBounds`]
748 /// * if <code>(offset / 8) + 3 >= [`self.bytes().len()`][Self::bytes]</code>
749 /// * if <code>(offset % 8 != 0) && (offset / 8) + 4 >= [`self.bytes().len()`][Self::bytes]</code>
750 #[inline(always)]
751 pub fn try_read_u32_be_at(&self, offset: usize) -> Result<u32> {
752 let first_idx = offset / 8;
753 let shift = offset % 8;
754
755 let len = self.bytes().len();
756
757 if first_idx + 3 >= len {
758 return Err(Error::OutOfBounds);
759 }
760
761 if shift != 0 && first_idx + 4 >= len {
762 return Err(Error::OutOfBounds);
763 }
764
765 Ok(unsafe { self.read_u32_be_at_unchecked(offset) })
766 }
767
768 /// Read the next [BE-bit, BE-byte] order [`u32`] while performing bound checks, advancing the internal cursor
769 ///
770 /// # Errors
771 ///
772 /// * Returns [`Error::OutOfBounds`]
773 /// * if <code>(self.pos() / 8) + 3 >= [`self.bytes().len()`][Self::bytes]</code>
774 /// * if <code>(self.pos() % 8 != 0) && (self.pos() / 8) + 4 >= [`self.bytes().len()`][Self::bytes]</code>
775 #[inline(always)]
776 pub fn try_read_u32_be(&mut self) -> Result<u32> {
777 let v = self.try_read_u32_be_at(self.pos())?;
778 self.advance_bytes(4);
779 Ok(v)
780 }
781
782 /// Read a [BE-bit, BE-byte] order [`u32`] from `offset`, panicking on out of bounds
783 ///
784 /// # Panics
785 ///
786 /// * Panics if <code>(offset / 8) + 3 >= [`self.bytes().len()`][Self::bytes]</code>
787 /// * Panics if <code>(offset % 8 != 0) && (offset / 8) + 4 >= [`self.bytes().len()`][Self::bytes]</code>
788 #[inline(always)]
789 #[must_use]
790 pub fn read_u32_be_at(&self, offset: usize) -> u32 {
791 self
792 .try_read_u32_be_at(offset)
793 .expect("BitBuf::read_u32_be_at out of bounds")
794 }
795
796 /// Read the next [BE-bit, BE-byte] order [`u32`], panicking on out of bounds, advancing the internal cursor
797 ///
798 /// # Panics
799 ///
800 /// * Panics if <code>(self.pos() / 8) + 3 >= [`self.bytes().len()`][Self::bytes]</code>
801 /// * Panics if <code>(self.pos() % 8 != 0) && (self.pos() / 8) + 4 >= [`self.bytes().len()`][Self::bytes]</code>
802 #[inline(always)]
803 #[must_use]
804 pub fn read_u32_be(&mut self) -> u32 {
805 self
806 .try_read_u32_be()
807 .expect("BitBuf::read_u32_be out of bounds")
808 }
809}
810
811pub trait Read: Sized {
812 unsafe fn read_be_aligned_at_unchecked<S: Storage>(buf: &BitBuf<S>, byte_offset: usize) -> Self;
813
814 unsafe fn read_be_aligned_unchecked<S: Storage>(buf: &mut BitBuf<S>) -> Self;
815
816 unsafe fn read_be_at_unchecked<S: Storage>(buf: &BitBuf<S>, offset: usize) -> Self;
817
818 unsafe fn read_be_unchecked<S: Storage>(buf: &mut BitBuf<S>) -> Self;
819
820 fn try_read_be_at<S: Storage>(buf: &BitBuf<S>, offset: usize) -> Result<Self>;
821
822 fn try_read_be<S: Storage>(buf: &mut BitBuf<S>) -> Result<Self>;
823
824 fn read_be_at<S: Storage>(buf: &BitBuf<S>, offset: usize) -> Self;
825
826 fn read_be<S: Storage>(buf: &mut BitBuf<S>) -> Self;
827}
828
829impl Read for u8 {
830 #[inline(always)]
831 unsafe fn read_be_aligned_at_unchecked<S: Storage>(buf: &BitBuf<S>, byte_offset: usize) -> Self {
832 unsafe { buf.read_u8_be_aligned_at_unchecked(byte_offset) }
833 }
834
835 #[inline(always)]
836 unsafe fn read_be_aligned_unchecked<S: Storage>(buf: &mut BitBuf<S>) -> Self {
837 unsafe { buf.read_u8_be_aligned_unchecked() }
838 }
839
840 #[inline(always)]
841 unsafe fn read_be_at_unchecked<S: Storage>(buf: &BitBuf<S>, offset: usize) -> Self {
842 unsafe { buf.read_u8_be_at_unchecked(offset) }
843 }
844
845 #[inline(always)]
846 unsafe fn read_be_unchecked<S: Storage>(buf: &mut BitBuf<S>) -> Self {
847 unsafe { buf.read_u8_be_unchecked() }
848 }
849
850 #[inline(always)]
851 fn try_read_be_at<S: Storage>(buf: &BitBuf<S>, offset: usize) -> Result<Self> {
852 buf.try_read_u8_be_at(offset)
853 }
854
855 #[inline(always)]
856 fn try_read_be<S: Storage>(buf: &mut BitBuf<S>) -> Result<Self> {
857 buf.try_read_u8_be()
858 }
859
860 #[inline(always)]
861 fn read_be_at<S: Storage>(buf: &BitBuf<S>, offset: usize) -> Self {
862 buf.read_u8_be_at(offset)
863 }
864
865 #[inline(always)]
866 fn read_be<S: Storage>(buf: &mut BitBuf<S>) -> Self {
867 buf.read_u8_be()
868 }
869}
870
871impl Read for u16 {
872 #[inline(always)]
873 unsafe fn read_be_aligned_at_unchecked<S: Storage>(buf: &BitBuf<S>, byte_offset: usize) -> Self {
874 unsafe { buf.read_u16_be_aligned_at_unchecked(byte_offset) }
875 }
876
877 #[inline(always)]
878 unsafe fn read_be_aligned_unchecked<S: Storage>(buf: &mut BitBuf<S>) -> Self {
879 unsafe { buf.read_u16_be_aligned_unchecked() }
880 }
881
882 #[inline(always)]
883 unsafe fn read_be_at_unchecked<S: Storage>(buf: &BitBuf<S>, offset: usize) -> Self {
884 unsafe { buf.read_u16_be_at_unchecked(offset) }
885 }
886
887 #[inline(always)]
888 unsafe fn read_be_unchecked<S: Storage>(buf: &mut BitBuf<S>) -> Self {
889 unsafe { buf.read_u16_be_unchecked() }
890 }
891
892 #[inline(always)]
893 fn try_read_be_at<S: Storage>(buf: &BitBuf<S>, offset: usize) -> Result<Self> {
894 buf.try_read_u16_be_at(offset)
895 }
896
897 #[inline(always)]
898 fn try_read_be<S: Storage>(buf: &mut BitBuf<S>) -> Result<Self> {
899 buf.try_read_u16_be()
900 }
901
902 #[inline(always)]
903 fn read_be_at<S: Storage>(buf: &BitBuf<S>, offset: usize) -> Self {
904 buf.read_u16_be_at(offset)
905 }
906
907 #[inline(always)]
908 fn read_be<S: Storage>(buf: &mut BitBuf<S>) -> Self {
909 buf.read_u16_be()
910 }
911}
912
913impl Read for u32 {
914 #[inline(always)]
915 unsafe fn read_be_aligned_at_unchecked<S: Storage>(buf: &BitBuf<S>, byte_offset: usize) -> Self {
916 unsafe { buf.read_u32_be_aligned_at_unchecked(byte_offset) }
917 }
918
919 #[inline(always)]
920 unsafe fn read_be_aligned_unchecked<S: Storage>(buf: &mut BitBuf<S>) -> Self {
921 unsafe { buf.read_u32_be_aligned_unchecked() }
922 }
923
924 #[inline(always)]
925 unsafe fn read_be_at_unchecked<S: Storage>(buf: &BitBuf<S>, offset: usize) -> Self {
926 unsafe { buf.read_u32_be_at_unchecked(offset) }
927 }
928
929 #[inline(always)]
930 unsafe fn read_be_unchecked<S: Storage>(buf: &mut BitBuf<S>) -> Self {
931 unsafe { buf.read_u32_be_unchecked() }
932 }
933
934 #[inline(always)]
935 fn try_read_be_at<S: Storage>(buf: &BitBuf<S>, offset: usize) -> Result<Self> {
936 buf.try_read_u32_be_at(offset)
937 }
938
939 #[inline(always)]
940 fn try_read_be<S: Storage>(buf: &mut BitBuf<S>) -> Result<Self> {
941 buf.try_read_u32_be()
942 }
943
944 #[inline(always)]
945 fn read_be_at<S: Storage>(buf: &BitBuf<S>, offset: usize) -> Self {
946 buf.read_u32_be_at(offset)
947 }
948
949 #[inline(always)]
950 fn read_be<S: Storage>(buf: &mut BitBuf<S>) -> Self {
951 buf.read_u32_be()
952 }
953}
954
955impl<S: Storage> BitBuf<S> {
956 /// Read a [BE-bit, BE-byte] order type `T` from `byte_offset` without performing bound checks
957 ///
958 /// # Safety
959 ///
960 /// All semantics of the corresponding function for the type apply
961 ///
962 /// # Panics
963 ///
964 /// All semantics of the corresponding function for the type apply
965 #[inline(always)]
966 #[must_use]
967 pub unsafe fn read_be_aligned_at_unchecked<T: Read>(&self, byte_offset: usize) -> T {
968 unsafe { T::read_be_aligned_at_unchecked(self, byte_offset) }
969 }
970
971 /// Read the next [BE-bit, BE-byte] order type `T` without performing bound checks, advancing the internal cursor
972 ///
973 /// # Safety
974 ///
975 /// All semantics of the corresponding function for the type apply
976 ///
977 /// # Panics
978 ///
979 /// All semantics of the corresponding function for the type apply
980 #[inline(always)]
981 #[must_use]
982 pub unsafe fn read_be_aligned_unchecked<T: Read>(&mut self) -> T {
983 unsafe { T::read_be_aligned_unchecked(self) }
984 }
985
986 /// Read a [BE-bit, BE-byte] order type `T` from `offset` without performing bound checks
987 ///
988 /// # Safety
989 ///
990 /// All semantics of the corresponding function for the type apply
991 ///
992 /// # Panics
993 ///
994 /// All semantics of the corresponding function for the type apply
995 #[inline(always)]
996 #[must_use]
997 pub unsafe fn read_be_at_unchecked<T: Read>(&self, offset: usize) -> T {
998 unsafe { T::read_be_at_unchecked(self, offset) }
999 }
1000
1001 /// Read the next [BE-bit, BE-byte] order type `T` without performing bound checks, advancing the internal cursor
1002 ///
1003 /// # Safety
1004 ///
1005 /// All semantics of the corresponding function for the type apply
1006 ///
1007 /// # Panics
1008 ///
1009 /// All semantics of the corresponding function for the type apply
1010 #[inline(always)]
1011 #[must_use]
1012 pub unsafe fn read_be_unchecked<T: Read>(&mut self) -> T {
1013 unsafe { T::read_be_unchecked(self) }
1014 }
1015
1016 /// Read a [BE-bit, BE-byte] order type `T` from `offset` while performing bound checks
1017 ///
1018 /// # Errors
1019 ///
1020 /// All semantics of the corresponding function for the type apply
1021 #[inline(always)]
1022 pub fn try_read_be_at<T: Read>(&self, offset: usize) -> Result<T> {
1023 T::try_read_be_at(self, offset)
1024 }
1025
1026 /// Read the next [BE-bit, BE-byte] order type `T` while performing bound checks, advancing the internal cursor
1027 ///
1028 /// # Errors
1029 ///
1030 /// All semantics of the corresponding function for the type apply
1031 #[inline(always)]
1032 pub fn try_read_be<T: Read>(&mut self) -> Result<T> {
1033 T::try_read_be(self)
1034 }
1035
1036 /// Read a [BE-bit, BE-byte] order type `T` from `offset`, panicking on out of bounds
1037 ///
1038 /// # Panics
1039 ///
1040 /// All semantics of the corresponding function for the type apply
1041 #[inline(always)]
1042 #[must_use]
1043 pub fn read_be_at<T: Read>(&self, offset: usize) -> T {
1044 T::read_be_at(self, offset)
1045 }
1046
1047 /// Read the next [BE-bit, BE-byte] order type `T`, panicking on out of bounds, advancing the internal cursor
1048 ///
1049 /// # Panics
1050 ///
1051 /// All semantics of the corresponding function for the type apply
1052 #[inline(always)]
1053 #[must_use]
1054 pub fn read_be<T: Read>(&mut self) -> T {
1055 T::read_be(self)
1056 }
1057}