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 a BE-bit-order [`u8`] from `offset` while performing bound checks
103 ///
104 /// # Errors
105 ///
106 /// * Returns [`Error::OutOfBounds`]
107 /// * if <code>(offset / 8) >= [`self.bytes().len()`][Self::bytes]</code>
108 /// * if <code>(offset % 8 != 0) && (offset / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
109 #[inline(always)]
110 pub fn try_read_u8_be_full_at(&self, offset: usize) -> Result<u8> {
111 let byte_idx = offset / 8;
112 let shift = offset % 8;
113
114 let len = self.bytes().len();
115
116 if byte_idx >= len {
117 return Err(Error::OutOfBounds);
118 }
119
120 if shift != 0 && byte_idx + 1 >= len {
121 return Err(Error::OutOfBounds);
122 }
123
124 Ok(unsafe { self.read_u8_be_full_at_unchecked(offset) })
125 }
126
127 /// Read a BE-bit-order [`u8`] from `offset`, panicking on out of bounds
128 ///
129 /// # Panics
130 ///
131 /// * Panics if <code>(offset / 8) >= [`self.bytes().len()`][Self::bytes]</code>
132 /// * Panics if <code>(offset % 8 != 0) && (offset / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
133 #[inline(always)]
134 #[must_use]
135 pub fn read_u8_be_full_at(&self, offset: usize) -> u8 {
136 self
137 .try_read_u8_be_full_at(offset)
138 .expect("BitBuf::read_u8_be_full_at out of bounds")
139 }
140}