Skip to main content

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}