Skip to main content

bit_buf/
read.rs

1use crate::{BitBuf, Error, Result, Storage, ensure};
2
3impl_read! {
4  u8;
5  bytes = 1;
6  bits = 8;
7  offset = 0;
8  [a];
9  [a, b];
10
11  read_u8_be_aligned_at_unchecked;
12  read_u8_be_aligned_unchecked;
13  read_u8_be_at_unchecked;
14  read_u8_be_unchecked;
15  try_read_u8_be_aligned_at;
16  try_read_u8_be_aligned;
17  try_read_u8_be_at;
18  try_read_u8_be;
19  read_u8_be_aligned_at;
20  read_u8_be_aligned;
21  read_u8_be_at;
22  read_u8_be;
23
24  read_u8_be_aligned_bits_at_unchecked;
25  read_u8_be_aligned_bits_unchecked;
26  try_read_u8_be_aligned_bits_at;
27  try_read_u8_be_aligned_bits;
28  read_u8_be_aligned_bits_at;
29  read_u8_be_aligned_bits;
30}
31
32impl_read! {
33  u16;
34  bytes = 2;
35  bits = 16;
36  offset = 1;
37  [a, b];
38  [a, [b], c];
39
40  read_u16_be_aligned_at_unchecked;
41  read_u16_be_aligned_unchecked;
42  read_u16_be_at_unchecked;
43  read_u16_be_unchecked;
44  try_read_u16_be_aligned_at;
45  try_read_u16_be_aligned;
46  try_read_u16_be_at;
47  try_read_u16_be;
48  read_u16_be_aligned_at;
49  read_u16_be_aligned;
50  read_u16_be_at;
51  read_u16_be;
52
53  read_u16_be_aligned_bits_at_unchecked;
54  read_u16_be_aligned_bits_unchecked;
55  try_read_u16_be_aligned_bits_at;
56  try_read_u16_be_aligned_bits;
57  read_u16_be_aligned_bits_at;
58  read_u16_be_aligned_bits;
59}
60
61impl_read! {
62  u32;
63  bytes = 4;
64  bits = 32;
65  offset = 3;
66  [a, b, c, d];
67  [a, [b, c, d], e];
68
69  read_u32_be_aligned_at_unchecked;
70  read_u32_be_aligned_unchecked;
71  read_u32_be_at_unchecked;
72  read_u32_be_unchecked;
73  try_read_u32_be_aligned_at;
74  try_read_u32_be_aligned;
75  try_read_u32_be_at;
76  try_read_u32_be;
77  read_u32_be_aligned_at;
78  read_u32_be_aligned;
79  read_u32_be_at;
80  read_u32_be;
81
82  read_u32_be_aligned_bits_at_unchecked;
83  read_u32_be_aligned_bits_unchecked;
84  try_read_u32_be_aligned_bits_at;
85  try_read_u32_be_aligned_bits;
86  read_u32_be_aligned_bits_at;
87  read_u32_be_aligned_bits;
88}
89
90impl_read! {
91  u64;
92  bytes = 8;
93  bits = 64;
94  offset = 7;
95  [a, b, c, d, e, f, g, h];
96  [a, [b, c, d, e, f, g, h], i];
97
98  read_u64_be_aligned_at_unchecked;
99  read_u64_be_aligned_unchecked;
100  read_u64_be_at_unchecked;
101  read_u64_be_unchecked;
102  try_read_u64_be_aligned_at;
103  try_read_u64_be_aligned;
104  try_read_u64_be_at;
105  try_read_u64_be;
106  read_u64_be_aligned_at;
107  read_u64_be_aligned;
108  read_u64_be_at;
109  read_u64_be;
110
111  read_u64_be_aligned_bits_at_unchecked;
112  read_u64_be_aligned_bits_unchecked;
113  try_read_u64_be_aligned_bits_at;
114  try_read_u64_be_aligned_bits;
115  read_u64_be_aligned_bits_at;
116  read_u64_be_aligned_bits;
117}
118
119impl_read! {
120  u128;
121  bytes = 16;
122  bits = 128;
123  offset = 15;
124  [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p];
125  [a, [b, c, d, e, f, g, h, i, j, k, l, m, n, o, p], q];
126
127  read_u128_be_aligned_at_unchecked;
128  read_u128_be_aligned_unchecked;
129  read_u128_be_at_unchecked;
130  read_u128_be_unchecked;
131  try_read_u128_be_aligned_at;
132  try_read_u128_be_aligned;
133  try_read_u128_be_at;
134  try_read_u128_be;
135  read_u128_be_aligned_at;
136  read_u128_be_aligned;
137  read_u128_be_at;
138  read_u128_be;
139
140  read_u128_be_aligned_bits_at_unchecked;
141  read_u128_be_aligned_bits_unchecked;
142  try_read_u128_be_aligned_bits_at;
143  try_read_u128_be_aligned_bits;
144  read_u128_be_aligned_bits_at;
145  read_u128_be_aligned_bits;
146}
147
148pub trait Read: Sized {
149  unsafe fn read_be_aligned_at_unchecked<S: Storage>(buf: &BitBuf<S>, byte_offset: usize) -> Self;
150
151  unsafe fn read_be_aligned_unchecked<S: Storage>(buf: &mut BitBuf<S>) -> Self;
152
153  unsafe fn read_be_at_unchecked<S: Storage>(buf: &BitBuf<S>, offset: usize) -> Self;
154
155  unsafe fn read_be_unchecked<S: Storage>(buf: &mut BitBuf<S>) -> Self;
156
157  fn try_read_be_aligned_at<S: Storage>(buf: &BitBuf<S>, byte_offset: usize) -> Result<Self>;
158
159  fn try_read_be_aligned<S: Storage>(buf: &mut BitBuf<S>) -> Result<Self>;
160
161  fn try_read_be_at<S: Storage>(buf: &BitBuf<S>, offset: usize) -> Result<Self>;
162
163  fn try_read_be<S: Storage>(buf: &mut BitBuf<S>) -> Result<Self>;
164
165  fn read_be_aligned_at<S: Storage>(buf: &BitBuf<S>, byte_offset: usize) -> Self;
166
167  fn read_be_aligned<S: Storage>(buf: &mut BitBuf<S>) -> Self;
168
169  fn read_be_at<S: Storage>(buf: &BitBuf<S>, offset: usize) -> Self;
170
171  fn read_be<S: Storage>(buf: &mut BitBuf<S>) -> Self;
172
173  unsafe fn read_be_aligned_bits_at_unchecked<S: Storage>(
174    buf: &BitBuf<S>,
175    byte_offset: usize,
176    bits: usize,
177  ) -> Self;
178
179  unsafe fn read_be_aligned_bits_unchecked<S: Storage>(buf: &mut BitBuf<S>, bits: usize) -> Self;
180
181  fn try_read_be_aligned_bits_at<S: Storage>(
182    buf: &BitBuf<S>,
183    byte_offset: usize,
184    bits: usize,
185  ) -> Result<Self>;
186
187  fn try_read_be_aligned_bits<S: Storage>(buf: &mut BitBuf<S>, bits: usize) -> Result<Self>;
188
189  fn read_be_aligned_bits_at<S: Storage>(buf: &BitBuf<S>, byte_offset: usize, bits: usize) -> Self;
190
191  fn read_be_aligned_bits<S: Storage>(buf: &mut BitBuf<S>, bits: usize) -> Self;
192}
193
194impl<S: Storage> BitBuf<S> {
195  /// Read a `T` in [BE-bit, BE-byte] order from `byte_offset`, without performing bound checks
196  ///
197  /// # Safety
198  ///
199  /// All semantics of the corresponding function for the type apply
200  ///
201  /// # Panics
202  ///
203  /// All semantics of the corresponding function for the type apply
204  #[inline(always)]
205  #[must_use]
206  pub unsafe fn read_be_aligned_at_unchecked<T: Read>(&self, byte_offset: usize) -> T {
207    unsafe { T::read_be_aligned_at_unchecked(self, byte_offset) }
208  }
209
210  /// Read the next `T` in [BE-bit, BE-byte] order, without validating cursor alignment or performing bound checks, advancing the internal cursor
211  ///
212  /// # Safety
213  ///
214  /// All semantics of the corresponding function for the type apply
215  ///
216  /// # Panics
217  ///
218  /// All semantics of the corresponding function for the type apply
219  #[inline(always)]
220  #[must_use]
221  pub unsafe fn read_be_aligned_unchecked<T: Read>(&mut self) -> T {
222    unsafe { T::read_be_aligned_unchecked(self) }
223  }
224
225  /// Read a `T` in [BE-bit, BE-byte] order from `offset`, without performing bound checks
226  ///
227  /// # Safety
228  ///
229  /// All semantics of the corresponding function for the type apply
230  ///
231  /// # Panics
232  ///
233  /// All semantics of the corresponding function for the type apply
234  #[inline(always)]
235  #[must_use]
236  pub unsafe fn read_be_at_unchecked<T: Read>(&self, offset: usize) -> T {
237    unsafe { T::read_be_at_unchecked(self, offset) }
238  }
239
240  /// Read the next `T` in [BE-bit, BE-byte] order, without performing bound checks, advancing the internal cursor
241  ///
242  /// # Safety
243  ///
244  /// All semantics of the corresponding function for the type apply
245  ///
246  /// # Panics
247  ///
248  /// All semantics of the corresponding function for the type apply
249  #[inline(always)]
250  #[must_use]
251  pub unsafe fn read_be_unchecked<T: Read>(&mut self) -> T {
252    unsafe { T::read_be_unchecked(self) }
253  }
254
255  /// Read a `T` in [BE-bit, BE-byte] order from `byte_offset`, performing bound checks
256  ///
257  /// # Errors
258  ///
259  /// All semantics of the corresponding function for the type apply
260  #[inline(always)]
261  pub fn try_read_be_aligned_at<T: Read>(&self, byte_offset: usize) -> Result<T> {
262    T::try_read_be_aligned_at(self, byte_offset)
263  }
264
265  /// Read the next `T` in [BE-bit, BE-byte] order, validating cursor alignment and performing bound checks, advancing the internal cursor
266  ///
267  /// # Errors
268  ///
269  /// All semantics of the corresponding function for the type apply
270  #[inline(always)]
271  pub fn try_read_be_aligned<T: Read>(&mut self) -> Result<T> {
272    T::try_read_be_aligned(self)
273  }
274
275  /// Read a `T` in [BE-bit, BE-byte] order from `offset`, performing bound checks
276  ///
277  /// # Errors
278  ///
279  /// All semantics of the corresponding function for the type apply
280  #[inline(always)]
281  pub fn try_read_be_at<T: Read>(&self, offset: usize) -> Result<T> {
282    T::try_read_be_at(self, offset)
283  }
284
285  /// Read the next `T` in [BE-bit, BE-byte] order, performing bound checks, advancing the internal cursor
286  ///
287  /// # Errors
288  ///
289  /// All semantics of the corresponding function for the type apply
290  #[inline(always)]
291  pub fn try_read_be<T: Read>(&mut self) -> Result<T> {
292    T::try_read_be(self)
293  }
294
295  /// Read a `T` in [BE-bit, BE-byte] order from `byte_offset`, panicking on out of bounds
296  ///
297  /// # Panics
298  ///
299  /// All semantics of the corresponding function for the type apply
300  #[inline(always)]
301  #[must_use]
302  pub fn read_be_aligned_at<T: Read>(&self, byte_offset: usize) -> T {
303    T::read_be_aligned_at(self, byte_offset)
304  }
305
306  /// Read the next `T` in [BE-bit, BE-byte] order, panicking on an unaligned cursor or out of bounds, advancing the internal cursor
307  ///
308  /// # Panics
309  ///
310  /// All semantics of the corresponding function for the type apply
311  #[inline(always)]
312  #[must_use]
313  pub fn read_be_aligned<T: Read>(&mut self) -> T {
314    T::read_be_aligned(self)
315  }
316
317  /// Read a `T` in [BE-bit, BE-byte] order from `offset`, panicking on out of bounds
318  ///
319  /// # Panics
320  ///
321  /// All semantics of the corresponding function for the type apply
322  #[inline(always)]
323  #[must_use]
324  pub fn read_be_at<T: Read>(&self, offset: usize) -> T {
325    T::read_be_at(self, offset)
326  }
327
328  /// Read the next `T` in [BE-bit, BE-byte] order, panicking on out of bounds, advancing the internal cursor
329  ///
330  /// # Panics
331  ///
332  /// All semantics of the corresponding function for the type apply
333  #[inline(always)]
334  #[must_use]
335  pub fn read_be<T: Read>(&mut self) -> T {
336    T::read_be(self)
337  }
338
339  /// Read a `T` in [BE-bit, BE-byte] order using `bits` bits from `byte_offset`, without validating the bit count or performing bound checks
340  ///
341  /// # Safety
342  ///
343  /// All semantics of the corresponding function for the type apply
344  ///
345  /// # Panics
346  ///
347  /// All semantics of the corresponding function for the type apply
348  #[inline(always)]
349  #[must_use]
350  pub unsafe fn read_be_aligned_bits_at_unchecked<T: Read>(
351    &self,
352    byte_offset: usize,
353    bits: usize,
354  ) -> T {
355    unsafe { T::read_be_aligned_bits_at_unchecked(self, byte_offset, bits) }
356  }
357
358  /// Read the next `T` in [BE-bit, BE-byte] order using `bits` bits, without validating cursor alignment, the bit count, or performing bound checks, advancing the internal cursor
359  ///
360  /// # Safety
361  ///
362  /// All semantics of the corresponding function for the type apply
363  ///
364  /// # Panics
365  ///
366  /// All semantics of the corresponding function for the type apply
367  #[inline(always)]
368  #[must_use]
369  pub unsafe fn read_be_aligned_bits_unchecked<T: Read>(&mut self, bits: usize) -> T {
370    unsafe { T::read_be_aligned_bits_unchecked(self, bits) }
371  }
372
373  /// Read a `T` in [BE-bit, BE-byte] order using `bits` bits from `byte_offset`, validating the bit count and performing bound checks
374  ///
375  /// # Errors
376  ///
377  /// All semantics of the corresponding function for the type apply
378  #[inline(always)]
379  pub fn try_read_be_aligned_bits_at<T: Read>(&self, byte_offset: usize, bits: usize) -> Result<T> {
380    T::try_read_be_aligned_bits_at(self, byte_offset, bits)
381  }
382
383  /// Read the next `T` in [BE-bit, BE-byte] order using `bits` bits, validating cursor alignment, the bit count, and performing bound checks, advancing the internal cursor
384  ///
385  /// # Errors
386  ///
387  /// All semantics of the corresponding function for the type apply
388  #[inline(always)]
389  pub fn try_read_be_aligned_bits<T: Read>(&mut self, bits: usize) -> Result<T> {
390    T::try_read_be_aligned_bits(self, bits)
391  }
392
393  /// Read a `T` in [BE-bit, BE-byte] order using `bits` bits from `byte_offset`, panicking on an invalid bit count or out of bounds
394  ///
395  /// # Panics
396  ///
397  /// All semantics of the corresponding function for the type apply
398  #[inline(always)]
399  #[must_use]
400  pub fn read_be_aligned_bits_at<T: Read>(&self, byte_offset: usize, bits: usize) -> T {
401    T::read_be_aligned_bits_at(self, byte_offset, bits)
402  }
403
404  /// Read the next `T` in [BE-bit, BE-byte] order using `bits` bits, panicking on an unaligned cursor, invalid bit count, or out of bounds, advancing the internal cursor
405  ///
406  /// # Panics
407  ///
408  /// All semantics of the corresponding function for the type apply
409  #[inline(always)]
410  #[must_use]
411  pub fn read_be_aligned_bits<T: Read>(&mut self, bits: usize) -> T {
412    T::read_be_aligned_bits(self, bits)
413  }
414}
415
416macro_rules! impl_read {
417  (
418    $ty:ident;
419    bytes = $bytes:literal;
420    bits = $bits:literal;
421    offset = $offset:literal;
422    [$($byte:ident),*];
423    [$first:ident, $([$($middle:ident),*],)? $last:ident];
424
425    $read_be_aligned_at_unchecked:ident;
426    $read_be_aligned_unchecked:ident;
427    $read_be_at_unchecked:ident;
428    $read_be_unchecked:ident;
429    $try_read_be_aligned_at:ident;
430    $try_read_be_aligned:ident;
431    $try_read_be_at:ident;
432    $try_read_be:ident;
433    $read_be_aligned_at:ident;
434    $read_be_aligned:ident;
435    $read_be_at:ident;
436    $read_be:ident;
437
438    $read_be_aligned_bits_at_unchecked:ident;
439    $read_be_aligned_bits_unchecked:ident;
440    $try_read_be_aligned_bits_at:ident;
441    $try_read_be_aligned_bits:ident;
442    $read_be_aligned_bits_at:ident;
443    $read_be_aligned_bits:ident;
444  ) => {
445    impl<S: Storage> BitBuf<S> {
446      #[doc = concat!("Read a [`", stringify!($ty), "`] in [BE-bit, BE-byte] order from `byte_offset`, without performing bound checks")]
447      ///
448      /// # Safety
449      ///
450      #[doc = concat!("* This is UB if <code>byte_offset + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
451      ///
452      /// # Panics
453      ///
454      #[doc = concat!("* Panics in debug mode if <code>byte_offset + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
455      #[inline(always)]
456      #[must_use]
457      pub unsafe fn $read_be_aligned_at_unchecked(&self, byte_offset: usize) -> $ty {
458        let bytes = self.bytes();
459        let len = bytes.len();
460
461        ensure!(
462          byte_offset + $offset < len;
463
464          concat!(
465            "BitBuf::",
466            stringify!($read_be_aligned_at_unchecked),
467            ": index out of bounds! len is {}, offset is {}"
468          ),
469          len,
470          byte_offset + $offset,
471        );
472
473        unsafe {
474          $ty::from_be_bytes(
475            *bytes[byte_offset..byte_offset + $bytes]
476              .as_array()
477              .unwrap_unchecked(),
478          )
479        }
480      }
481
482      #[doc = concat!("Read the next [`", stringify!($ty), "`] in [BE-bit, BE-byte] order, without validating cursor alignment or performing bound checks, advancing the internal cursor")]
483      ///
484      /// # Safety
485      ///
486      /// * The internal cursor must be byte-aligned ([`self.is_aligned()`][Self::is_aligned])
487      #[doc = concat!("* This is UB if <code>[self.byte_pos()][Self::byte_pos] + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
488      ///
489      /// # Panics
490      ///
491      /// * Panics in debug mode if the internal cursor is not byte-aligned (<code>\![self.is_aligned()][Self::is_aligned]</code>)
492      #[doc = concat!("* Panics in debug mode if <code>[self.byte_pos()][Self::byte_pos] + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
493      #[inline(always)]
494      #[must_use]
495      pub unsafe fn $read_be_aligned_unchecked(&mut self) -> $ty {
496        ensure!(
497          self.is_aligned();
498
499          concat!(
500            "BitBuf::",
501            stringify!($read_be_aligned_unchecked),
502            " called at unaligned bit position: {}",
503          ),
504          self.pos(),
505        );
506
507        let v = unsafe { self.$read_be_aligned_at_unchecked(self.byte_pos()) };
508        self.advance_bytes($bytes);
509        v
510      }
511
512      #[doc = concat!("Read a [`", stringify!($ty), "`] in [BE-bit, BE-byte] order from `offset`, without performing bound checks")]
513      ///
514      /// # Safety
515      ///
516      #[doc = concat!("* This is UB if <code>(offset / 8) + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
517      #[doc = concat!("* This is UB if <code>(offset % 8 != 0) && (offset / 8) + ", stringify!($bytes), " >= [self.bytes()][Self::bytes].len()</code>")]
518      ///
519      /// # Panics
520      ///
521      #[doc = concat!("* Panics in debug mode if <code>(offset / 8) + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
522      #[doc = concat!("* Panics in debug mode if <code>(offset % 8 != 0) && (offset / 8) + ", stringify!($bytes), " >= [self.bytes()][Self::bytes].len()</code>")]
523      #[inline(always)]
524      #[must_use]
525      pub unsafe fn $read_be_at_unchecked(&self, offset: usize) -> $ty {
526        let byte_idx = offset / 8;
527        let shift = offset % 8;
528
529        let bytes = self.bytes();
530        let len = bytes.len();
531
532        ensure!(
533          byte_idx + $offset < len;
534
535          concat!(
536            "BitBuf::",
537            stringify!($read_be_at_unchecked),
538            ": index out of bounds! len is {}, byte_idx is {}",
539          ),
540          len,
541          byte_idx + $offset,
542        );
543
544        if shift == 0 {
545          unsafe { self.$read_be_aligned_at_unchecked(byte_idx) }
546        } else {
547          ensure!(
548            byte_idx + $bytes < len;
549
550            concat!(
551              "BitBuf::",
552              stringify!($read_be_at_unchecked),
553              ": lookahead index out of bounds! len is {}, lookahead byte_idx is {}",
554            ),
555            len,
556            byte_idx + $bytes,
557          );
558
559          unsafe {
560            let ptr = bytes.as_ptr().add(byte_idx);
561            let high = $ty::from_be_bytes(*(ptr as *const [u8; $bytes]));
562            let low = *bytes.get_unchecked(byte_idx + $bytes) as $ty;
563            (high << shift) | (low >> (8 - shift))
564          }
565        }
566      }
567
568      #[doc = concat!("Read the next [`", stringify!($ty), "`] in [BE-bit, BE-byte] order, without performing bound checks, advancing the internal cursor")]
569      ///
570      /// # Safety
571      ///
572      #[doc = concat!("* This is UB if <code>([self.pos()][Self::pos] / 8) + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
573      #[doc = concat!("* This is UB if <code>([self.pos()][Self::pos] % 8 != 0) && ([self.pos()][Self::pos] / 8) + ", stringify!($bytes), " >= [self.bytes()][Self::bytes].len()</code>")]
574      ///
575      /// # Panics
576      ///
577      #[doc = concat!("* Panics in debug mode if <code>([self.pos()][Self::pos] / 8) + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
578      #[doc = concat!("* Panics in debug mode if <code>([self.pos()][Self::pos] % 8 != 0) && ([self.pos()][Self::pos] / 8) + ", stringify!($bytes), " >= [self.bytes()][Self::bytes].len()</code>")]
579      #[inline(always)]
580      #[must_use]
581      pub unsafe fn $read_be_unchecked(&mut self) -> $ty {
582        let v = unsafe { self.$read_be_at_unchecked(self.pos()) };
583        self.advance_bytes($bytes);
584        v
585      }
586
587      #[doc = concat!("Read a [`", stringify!($ty), "`] in [BE-bit, BE-byte] order from `byte_offset`, performing bound checks")]
588      ///
589      /// # Errors
590      ///
591      /// * Returns [`Error::OutOfBounds`]
592      #[doc = concat!("  * if <code>byte_offset + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
593      #[inline(always)]
594      pub fn $try_read_be_aligned_at(&self, byte_offset: usize) -> Result<$ty> {
595        let len = self.bytes().len();
596
597        if byte_offset + $offset >= len {
598          return Err(Error::OutOfBounds);
599        }
600
601        Ok(unsafe { self.$read_be_aligned_at_unchecked(byte_offset) })
602      }
603
604      #[doc = concat!("Read the next [`", stringify!($ty), "`] in [BE-bit, BE-byte] order, validating cursor alignment and performing bound checks, advancing the internal cursor")]
605      ///
606      /// # Errors
607      ///
608      /// * Returns [`Error::Unaligned`]
609      ///   * if the internal cursor is not byte-aligned (<code>\![self.is_aligned()][Self::is_aligned]</code>)
610      /// * Returns [`Error::OutOfBounds`]
611      #[doc = concat!("  * if <code>[self.byte_pos()][Self::byte_pos] + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
612      #[inline(always)]
613      pub fn $try_read_be_aligned(&mut self) -> Result<$ty> {
614        if !self.is_aligned() {
615          return Err(Error::Unaligned);
616        }
617
618        let v = self.$try_read_be_aligned_at(self.byte_pos())?;
619        self.advance_bytes($bytes);
620        Ok(v)
621      }
622
623      #[doc = concat!("Read a [`", stringify!($ty), "`] in [BE-bit, BE-byte] order from `offset`, performing bound checks")]
624      ///
625      /// # Errors
626      ///
627      /// * Returns [`Error::OutOfBounds`]
628      #[doc = concat!("  * if <code>(offset / 8) + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
629      #[doc = concat!("  * if <code>(offset % 8 != 0) && (offset / 8) + ", stringify!($bytes), " >= [self.bytes()][Self::bytes].len()</code>")]
630      #[inline(always)]
631      pub fn $try_read_be_at(&self, offset: usize) -> Result<$ty> {
632        let byte_idx = offset / 8;
633        let shift = offset % 8;
634
635        let len = self.bytes().len();
636
637        if byte_idx + $offset >= len {
638          return Err(Error::OutOfBounds);
639        }
640
641        if shift != 0 && byte_idx + $bytes >= len {
642          return Err(Error::OutOfBounds);
643        }
644
645        Ok(unsafe { self.$read_be_at_unchecked(offset) })
646      }
647
648      #[doc = concat!("Read the next [`", stringify!($ty), "`] in [BE-bit, BE-byte] order, performing bound checks, advancing the internal cursor")]
649      ///
650      /// # Errors
651      ///
652      /// * Returns [`Error::OutOfBounds`]
653      #[doc = concat!("  * if <code>([self.pos()][Self::pos] / 8) + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
654      #[doc = concat!("  * if <code>([self.pos()][Self::pos] % 8 != 0) && ([self.pos()][Self::pos] / 8) + ", stringify!($bytes), " >= [self.bytes()][Self::bytes].len()</code>")]
655      #[inline(always)]
656      pub fn $try_read_be(&mut self) -> Result<$ty> {
657        let v = self.$try_read_be_at(self.pos())?;
658        self.advance_bytes($bytes);
659        Ok(v)
660      }
661
662      #[doc = concat!("Read a [`", stringify!($ty), "`] in [BE-bit, BE-byte] order from `byte_offset`, panicking on out of bounds")]
663      ///
664      /// # Panics
665      ///
666      #[doc = concat!("* Panics if <code>byte_offset + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
667      #[inline(always)]
668      #[must_use]
669      pub fn $read_be_aligned_at(&self, byte_offset: usize) -> $ty {
670        self
671          .$try_read_be_aligned_at(byte_offset)
672          .expect(concat!("BitBuf::", stringify!($read_be_aligned_at), " out of bounds"))
673      }
674
675      #[doc = concat!("Read the next [`", stringify!($ty), "`] in [BE-bit, BE-byte] order, panicking on an unaligned cursor or out of bounds, advancing the internal cursor")]
676      ///
677      /// # Panics
678      ///
679      /// * if the internal cursor is not byte-aligned (<code>\![self.is_aligned()][Self::is_aligned]</code>)
680      #[doc = concat!("* if <code>[self.byte_pos()][Self::byte_pos] + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
681      #[inline(always)]
682      #[must_use]
683      pub fn $read_be_aligned(&mut self) -> $ty {
684        self
685          .$try_read_be_aligned()
686          .expect(concat!("BitBuf::", stringify!($read_be_aligned), " unaligned cursor or out of bounds"))
687      }
688
689      #[doc = concat!("Read a [`", stringify!($ty), "`] in [BE-bit, BE-byte] order from `offset`, panicking on out of bounds")]
690      ///
691      /// # Panics
692      ///
693      #[doc = concat!("* Panics if <code>(offset / 8) + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
694      #[doc = concat!("* Panics if <code>(offset % 8 != 0) && (offset / 8) + ", stringify!($bytes), " >= [self.bytes()][Self::bytes].len()</code>")]
695      #[inline(always)]
696      #[must_use]
697      pub fn $read_be_at(&self, offset: usize) -> $ty {
698        self
699          .$try_read_be_at(offset)
700          .expect(concat!("BitBuf::", stringify!($read_be_at), " out of bounds"))
701      }
702
703      #[doc = concat!("Read the next [`", stringify!($ty), "`] in [BE-bit, BE-byte] order, panicking on out of bounds, advancing the internal cursor")]
704      ///
705      /// # Panics
706      ///
707      #[doc = concat!("* Panics if <code>([self.pos()][Self::pos] / 8) + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
708      #[doc = concat!("* Panics if <code>([self.pos()][Self::pos] % 8 != 0) && ([self.pos()][Self::pos] / 8) + ", stringify!($bytes), " >= [self.bytes()][Self::bytes].len()</code>")]
709      #[inline(always)]
710      #[must_use]
711      pub fn $read_be(&mut self) -> $ty {
712        self
713          .$try_read_be()
714          .expect(concat!("BitBuf::", stringify!($read_be), " out of bounds"))
715      }
716    }
717
718    impl<S: Storage> BitBuf<S> {
719      #[doc = concat!("Read a [`", stringify!($ty), "`] in [BE-bit, BE-byte] order using `bits` bits from `byte_offset`, without validating the bit count or performing bound checks")]
720      ///
721      /// # Safety
722      ///
723      /// * This is UB
724      #[doc = concat!("  * if `bits > ", stringify!($bits), "`")]
725      #[doc = concat!("  * if <code>byte_offset + [bits.div_ceil(8)][usize::div_ceil] > [self.bytes()][Self::bytes].len()</code>")]
726      ///
727      /// # Panics
728      ///
729      /// * Panics in debug mode
730      #[doc = concat!("  * if `bits > ", stringify!($bits), "`")]
731      #[doc = concat!("  * if <code>byte_offset + [bits.div_ceil(8)][usize::div_ceil] > [self.bytes()][Self::bytes].len()</code>")]
732      #[inline(always)]
733      #[must_use]
734      pub unsafe fn $read_be_aligned_bits_at_unchecked(&self, byte_offset: usize, bits: usize) -> $ty {
735        ensure!(
736          bits <= $bits;
737
738          concat!(
739            "BitBuf::",
740            stringify!($read_be_aligned_bits_at_unchecked),
741            ": bits requested ({}) exceeds ",
742            stringify!($ty),
743            " width!"
744          ),
745          bits,
746        );
747
748        if bits == 0 {
749          return 0;
750        }
751
752        let required_bytes = bits.div_ceil(8);
753
754        let bytes = self.bytes();
755        let len = bytes.len();
756
757        ensure!(
758          byte_offset + required_bytes <= len;
759
760          concat!(
761            "BitBuf::",
762            stringify!($read_be_aligned_bits_at_unchecked),
763            ": index out of bounds! len is {}, required end is {}"
764          ),
765          len,
766          byte_offset + required_bytes,
767        );
768
769        let ptr = unsafe { bytes.as_ptr().add(byte_offset) };
770
771        // @note(perf)
772        // the general pattern is to construct a value of the same size as the number of bytes
773        // need by combining the least amount of reads of different sizes, kind of like trying to
774        // make x amount of money using the least amount of bills and coins
775        //
776        // it is faster than reading byte by byte because there is 1 shift+or needed per *read*
777        // instead of per *byte*
778        let v: $ty = unsafe {
779          if bits <= 8 {
780            *bytes.get_unchecked(byte_offset) as _
781          } else if bits <= 16 {
782            u16::from_be_bytes(*(ptr as *const _)) as _
783          } else if bits <= 24 {
784            let hi = u16::from_be_bytes(*(ptr as *const _)) as u32;
785            let lo = *bytes.get_unchecked(byte_offset + 2) as u32;
786            ((hi << 8) | lo) as _
787          } else if bits <= 32 {
788            u32::from_be_bytes(*(ptr as *const _)) as _
789          } else if bits <= 40 {
790            let hi = u32::from_be_bytes(*(ptr as *const _)) as u64;
791            let lo = *ptr.add(4) as u64;
792            ((hi << 8) | lo) as _
793          } else if bits <= 48 {
794            let hi = u32::from_be_bytes(*(ptr as *const _)) as u64;
795            let lo = u16::from_be_bytes(*(ptr.add(4) as *const _)) as u64;
796            ((hi << 16) | lo) as _
797          } else if bits <= 56 {
798            let hi = u32::from_be_bytes(*(ptr as *const _)) as u64;
799            let mid = u16::from_be_bytes(*(ptr.add(4) as *const _)) as u64;
800            let lo = *ptr.add(6) as u64;
801            ((hi << 24) | (mid << 8) | lo) as _
802          } else if bits <= 64 {
803            u64::from_be_bytes(*(ptr as *const _)) as _
804          }
805          // @note(perf)
806          // originally I tried using the below code for `bits > 64` but the u128 test took ~177s
807          // ```
808          // let mut buf = [0u8; 16];
809          // ptr::copy_nonoverlapping(
810          //   bytes.as_ptr().add(byte_offset),
811          //   buf.as_mut_ptr().add(16 - required_bytes),
812          //   required_bytes,
813          // );
814          // u128::from_be_bytes(buf) as _
815          // ```
816          // checking the assembly showed it was using memcpy which is probably why it was so slow.
817          // continuing the same pattern below brought it down to ~90s
818          else if bits <= 72 {
819            let hi = u64::from_be_bytes(*(ptr as *const _)) as u128;
820            let lo = *ptr.add(8) as u128;
821            ((hi << 8) | lo) as _
822          } else if bits <= 80 {
823            let hi = u64::from_be_bytes(*(ptr as *const _)) as u128;
824            let lo = u16::from_be_bytes(*(ptr.add(8) as *const _)) as u128;
825            ((hi << 16) | lo) as _
826          } else if bits <= 88 {
827            let hi = u64::from_be_bytes(*(ptr as *const _)) as u128;
828            let mid = u16::from_be_bytes(*(ptr.add(8) as *const _)) as u128;
829            let lo = *ptr.add(10) as u128;
830            ((hi << 24) | (mid << 8) | lo) as _
831          } else if bits <= 96 {
832            let hi = u64::from_be_bytes(*(ptr as *const _)) as u128;
833            let lo = u32::from_be_bytes(*(ptr.add(8) as *const _)) as u128;
834            ((hi << 32) | lo) as _
835          } else if bits <= 104 {
836            let hi = u64::from_be_bytes(*(ptr as *const _)) as u128;
837            let mid = u32::from_be_bytes(*(ptr.add(8) as *const _)) as u128;
838            let lo = *ptr.add(12) as u128;
839            ((hi << 40) | (mid << 8) | lo) as _
840          } else if bits <= 112 {
841            let hi = u64::from_be_bytes(*(ptr as *const _)) as u128;
842            let mid = u32::from_be_bytes(*(ptr.add(8) as *const _)) as u128;
843            let lo = u16::from_be_bytes(*(ptr.add(12) as *const _)) as u128;
844            ((hi << 48) | (mid << 16) | lo) as _
845          } else if bits <= 120 {
846            let hi = u64::from_be_bytes(*(ptr as *const _)) as u128;
847            let mid1 = u32::from_be_bytes(*(ptr.add(8) as *const _)) as u128;
848            let mid2 = u16::from_be_bytes(*(ptr.add(12) as *const _)) as u128;
849            let lo = *ptr.add(14) as u128;
850            ((hi << 56) | (mid1 << 24) | (mid2 << 8) | lo) as _
851          } else {
852            u128::from_be_bytes(*(ptr as *const _)) as _
853          }
854        };
855
856        // finally, just shift the whole constructed value down so that the bits are moved into the
857        // lower positions
858        v >> ((required_bytes * 8) - bits)
859      }
860
861      #[doc = concat!("Read the next [`", stringify!($ty), "`] in [BE-bit, BE-byte] order using `bits` bits, without validating cursor alignment, the bit count, or performing bound checks, advancing the internal cursor")]
862      ///
863      /// # Safety
864      ///
865      /// * The internal cursor must be byte-aligned ([`self.is_aligned()`][Self::is_aligned])
866      /// * This is UB
867      #[doc = concat!("  * if `bits > ", stringify!($bits), "`")]
868      #[doc = concat!("  * if <code>[self.byte_pos()][Self::byte_pos] + [bits.div_ceil(8)][usize::div_ceil] > [self.bytes()][Self::bytes].len()</code>")]
869      ///
870      /// # Panics
871      ///
872      /// * Panics in debug mode
873      ///   * if the internal cursor is not byte-aligned (<code>\![self.is_aligned()][Self::is_aligned]</code>)
874      #[doc = concat!("  * if `bits > ", stringify!($bits), "`")]
875      #[doc = concat!("  * if <code>[self.byte_pos()][Self::byte_pos] + [bits.div_ceil(8)][usize::div_ceil] > [self.bytes()][Self::bytes].len()</code>")]
876      #[inline(always)]
877      #[must_use]
878      pub unsafe fn $read_be_aligned_bits_unchecked(&mut self, bits: usize) -> $ty {
879        ensure!(
880          self.is_aligned();
881
882          concat!(
883            "BitBuf::",
884            stringify!($read_be_aligned_bits_unchecked),
885            " called at unaligned bit position: {}",
886          ),
887          self.pos(),
888        );
889
890        let v = unsafe { self.$read_be_aligned_bits_at_unchecked(self.byte_pos(), bits) };
891        self.advance(bits);
892        v
893      }
894
895      #[doc = concat!("Read a [`", stringify!($ty), "`] in [BE-bit, BE-byte] order using `bits` bits from `byte_offset`, validating the bit count and performing bound checks")]
896      ///
897      /// # Errors
898      ///
899      /// * Returns [`Error::InvalidBitCount`]
900      #[doc = concat!("  * if `bits > ", stringify!($bits), "`")]
901      /// * Returns [`Error::OutOfBounds`]
902      #[doc = concat!("  * if <code>byte_offset + [bits.div_ceil(8)][usize::div_ceil] > [self.bytes()][Self::bytes].len()</code>")]
903      #[inline(always)]
904      pub fn $try_read_be_aligned_bits_at(&self, byte_offset: usize, bits: usize) -> Result<$ty> {
905        if bits > $bits {
906          return Err(Error::InvalidBitCount);
907        }
908
909        let required_bytes = bits.div_ceil(8);
910
911        let len = self.bytes().len();
912
913        if byte_offset + required_bytes > len {
914          return Err(Error::OutOfBounds);
915        }
916
917        Ok(unsafe { self.$read_be_aligned_bits_at_unchecked(byte_offset, bits) })
918      }
919
920      #[doc = concat!("Read the next [`", stringify!($ty), "`] in [BE-bit, BE-byte] order using `bits` bits, validating cursor alignment, the bit count, and performing bound checks, advancing the internal cursor")]
921      ///
922      /// # Errors
923      ///
924      /// * Returns [`Error::Unaligned`]
925      ///   * if the internal cursor is not byte-aligned (<code>\![self.is_aligned()][Self::is_aligned]</code>)
926      /// * Returns [`Error::InvalidBitCount`]
927      #[doc = concat!("  * if `bits > ", stringify!($bits), "`")]
928      /// * Returns [`Error::OutOfBounds`]
929      #[doc = concat!("  * if <code>[self.byte_pos()][Self::byte_pos] + [bits.div_ceil(8)][usize::div_ceil] > [self.bytes()][Self::bytes].len()</code>")]
930      #[inline(always)]
931      pub fn $try_read_be_aligned_bits(&mut self, bits: usize) -> Result<$ty> {
932        if !self.is_aligned() {
933          return Err(Error::Unaligned);
934        }
935
936        let v = self.$try_read_be_aligned_bits_at(self.byte_pos(), bits)?;
937        self.advance(bits);
938        Ok(v)
939      }
940
941      #[doc = concat!("Read a [`", stringify!($ty), "`] in [BE-bit, BE-byte] order using `bits` bits from `byte_offset`, panicking on an invalid bit count or out of bounds")]
942      ///
943      /// # Panics
944      #[doc = concat!("  * if `bits > ", stringify!($bits), "`")]
945      #[doc = concat!("  * if <code>byte_offset + [bits.div_ceil(8)][usize::div_ceil] > [self.bytes()][Self::bytes].len()</code>")]
946      #[inline(always)]
947      pub fn $read_be_aligned_bits_at(&self, byte_offset: usize, bits: usize) -> $ty {
948        self
949          .$try_read_be_aligned_bits_at(byte_offset, bits)
950          .expect(concat!("BitBuf::", stringify!($read_be_aligned_bits_at), " invalid bit count or out of bounds"))
951      }
952
953      #[doc = concat!("Read the next [`", stringify!($ty), "`] in [BE-bit, BE-byte] order using `bits` bits, panicking on an unaligned cursor, invalid bit count, or out of bounds, advancing the internal cursor")]
954      ///
955      /// # Panics
956      ///   * if the internal cursor is not byte-aligned (<code>\![self.is_aligned()][Self::is_aligned]</code>)
957      #[doc = concat!("  * if `bits > ", stringify!($bits), "`")]
958      #[doc = concat!("  * if <code>[self.byte_pos()][Self::byte_pos] + [bits.div_ceil(8)][usize::div_ceil] > [self.bytes()][Self::bytes].len()</code>")]
959      #[inline(always)]
960      pub fn $read_be_aligned_bits(&mut self, bits: usize) -> $ty {
961        self
962          .$try_read_be_aligned_bits(bits)
963          .expect(concat!("BitBuf::", stringify!($read_be_aligned_bits), " unaligned cursor, invalid bit count, or out of bounds"))
964      }
965    }
966
967    impl Read for $ty {
968      #[inline(always)]
969      unsafe fn read_be_aligned_at_unchecked<S: Storage>(buf: &BitBuf<S>, byte_offset: usize) -> Self {
970        unsafe { buf.$read_be_aligned_at_unchecked(byte_offset) }
971      }
972
973      #[inline(always)]
974      unsafe fn read_be_aligned_unchecked<S: Storage>(buf: &mut BitBuf<S>) -> Self {
975        unsafe { buf.$read_be_aligned_unchecked() }
976      }
977
978      #[inline(always)]
979      unsafe fn read_be_at_unchecked<S: Storage>(buf: &BitBuf<S>, offset: usize) -> Self {
980        unsafe { buf.$read_be_at_unchecked(offset) }
981      }
982
983      #[inline(always)]
984      unsafe fn read_be_unchecked<S: Storage>(buf: &mut BitBuf<S>) -> Self {
985        unsafe { buf.$read_be_unchecked() }
986      }
987
988      #[inline(always)]
989      fn try_read_be_aligned_at<S: Storage>(buf: &BitBuf<S>, byte_offset: usize) -> Result<Self> {
990        buf.$try_read_be_aligned_at(byte_offset)
991      }
992
993      #[inline(always)]
994      fn try_read_be_aligned<S: Storage>(buf: &mut BitBuf<S>) -> Result<Self> {
995        buf.$try_read_be_aligned()
996      }
997
998      #[inline(always)]
999      fn try_read_be_at<S: Storage>(buf: &BitBuf<S>, offset: usize) -> Result<Self> {
1000        buf.$try_read_be_at(offset)
1001      }
1002
1003      #[inline(always)]
1004      fn try_read_be<S: Storage>(buf: &mut BitBuf<S>) -> Result<Self> {
1005        buf.$try_read_be()
1006      }
1007
1008      #[inline(always)]
1009      fn read_be_aligned_at<S: Storage>(buf: &BitBuf<S>, byte_offset: usize) -> Self {
1010        buf.$read_be_aligned_at(byte_offset)
1011      }
1012
1013      #[inline(always)]
1014      fn read_be_aligned<S: Storage>(buf: &mut BitBuf<S>) -> Self {
1015        buf.$read_be_aligned()
1016      }
1017
1018      #[inline(always)]
1019      fn read_be_at<S: Storage>(buf: &BitBuf<S>, offset: usize) -> Self {
1020        buf.$read_be_at(offset)
1021      }
1022
1023      #[inline(always)]
1024      fn read_be<S: Storage>(buf: &mut BitBuf<S>) -> Self {
1025        buf.$read_be()
1026      }
1027
1028      #[inline(always)]
1029      unsafe fn read_be_aligned_bits_at_unchecked<S: Storage>(buf: &BitBuf<S>, byte_offset: usize, bits: usize) -> Self {
1030        unsafe { buf.$read_be_aligned_bits_at_unchecked(byte_offset, bits) }
1031      }
1032
1033      #[inline(always)]
1034      unsafe fn read_be_aligned_bits_unchecked<S: Storage>(buf: &mut BitBuf<S>, bits: usize) -> Self {
1035        unsafe { buf.$read_be_aligned_bits_unchecked(bits) }
1036      }
1037
1038      #[inline(always)]
1039      fn try_read_be_aligned_bits_at<S: Storage>(buf: &BitBuf<S>, byte_offset: usize, bits: usize) -> Result<Self> {
1040        buf.$try_read_be_aligned_bits_at(byte_offset, bits)
1041      }
1042
1043      #[inline(always)]
1044      fn try_read_be_aligned_bits<S: Storage>(buf: &mut BitBuf<S>, bits: usize) -> Result<Self> {
1045        buf.$try_read_be_aligned_bits(bits)
1046      }
1047
1048      #[inline(always)]
1049      fn read_be_aligned_bits_at<S: Storage>(buf: &BitBuf<S>, byte_offset: usize, bits: usize) -> Self {
1050        buf.$read_be_aligned_bits_at(byte_offset, bits)
1051      }
1052
1053      #[inline(always)]
1054      fn read_be_aligned_bits<S: Storage>(buf: &mut BitBuf<S>, bits: usize) -> Self {
1055        buf.$read_be_aligned_bits(bits)
1056      }
1057    }
1058  };
1059}
1060
1061use impl_read;