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 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}