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
25impl_read! {
26 u16;
27 bytes = 2;
28 bits = 16;
29 offset = 1;
30 [a, b];
31 [a, [b], c];
32
33 read_u16_be_aligned_at_unchecked;
34 read_u16_be_aligned_unchecked;
35 read_u16_be_at_unchecked;
36 read_u16_be_unchecked;
37 try_read_u16_be_aligned_at;
38 try_read_u16_be_aligned;
39 try_read_u16_be_at;
40 try_read_u16_be;
41 read_u16_be_aligned_at;
42 read_u16_be_aligned;
43 read_u16_be_at;
44 read_u16_be;
45}
46
47impl_read! {
48 u32;
49 bytes = 4;
50 bits = 32;
51 offset = 3;
52 [a, b, c, d];
53 [a, [b, c, d], e];
54
55 read_u32_be_aligned_at_unchecked;
56 read_u32_be_aligned_unchecked;
57 read_u32_be_at_unchecked;
58 read_u32_be_unchecked;
59 try_read_u32_be_aligned_at;
60 try_read_u32_be_aligned;
61 try_read_u32_be_at;
62 try_read_u32_be;
63 read_u32_be_aligned_at;
64 read_u32_be_aligned;
65 read_u32_be_at;
66 read_u32_be;
67}
68
69impl_read! {
70 u64;
71 bytes = 8;
72 bits = 64;
73 offset = 7;
74 [a, b, c, d, e, f, g, h];
75 [a, [b, c, d, e, f, g, h], i];
76
77 read_u64_be_aligned_at_unchecked;
78 read_u64_be_aligned_unchecked;
79 read_u64_be_at_unchecked;
80 read_u64_be_unchecked;
81 try_read_u64_be_aligned_at;
82 try_read_u64_be_aligned;
83 try_read_u64_be_at;
84 try_read_u64_be;
85 read_u64_be_aligned_at;
86 read_u64_be_aligned;
87 read_u64_be_at;
88 read_u64_be;
89}
90
91impl_read! {
92 u128;
93 bytes = 16;
94 bits = 128;
95 offset = 15;
96 [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p];
97 [a, [b, c, d, e, f, g, h, i, j, k, l, m, n, o, p], q];
98
99 read_u128_be_aligned_at_unchecked;
100 read_u128_be_aligned_unchecked;
101 read_u128_be_at_unchecked;
102 read_u128_be_unchecked;
103 try_read_u128_be_aligned_at;
104 try_read_u128_be_aligned;
105 try_read_u128_be_at;
106 try_read_u128_be;
107 read_u128_be_aligned_at;
108 read_u128_be_aligned;
109 read_u128_be_at;
110 read_u128_be;
111}
112
113pub trait Read: Sized {
114 unsafe fn read_be_aligned_at_unchecked<S: Storage>(buf: &BitBuf<S>, byte_offset: usize) -> Self;
115
116 unsafe fn read_be_aligned_unchecked<S: Storage>(buf: &mut BitBuf<S>) -> Self;
117
118 unsafe fn read_be_at_unchecked<S: Storage>(buf: &BitBuf<S>, offset: usize) -> Self;
119
120 unsafe fn read_be_unchecked<S: Storage>(buf: &mut BitBuf<S>) -> Self;
121
122 fn try_read_be_aligned_at<S: Storage>(buf: &BitBuf<S>, byte_offset: usize) -> Result<Self>;
123
124 fn try_read_be_aligned<S: Storage>(buf: &mut BitBuf<S>) -> Result<Self>;
125
126 fn try_read_be_at<S: Storage>(buf: &BitBuf<S>, offset: usize) -> Result<Self>;
127
128 fn try_read_be<S: Storage>(buf: &mut BitBuf<S>) -> Result<Self>;
129
130 fn read_be_aligned_at<S: Storage>(buf: &BitBuf<S>, byte_offset: usize) -> Self;
131
132 fn read_be_aligned<S: Storage>(buf: &mut BitBuf<S>) -> Self;
133
134 fn read_be_at<S: Storage>(buf: &BitBuf<S>, offset: usize) -> Self;
135
136 fn read_be<S: Storage>(buf: &mut BitBuf<S>) -> Self;
137}
138
139impl<S: Storage> BitBuf<S> {
140 #[inline(always)]
150 #[must_use]
151 pub unsafe fn read_be_aligned_at_unchecked<T: Read>(&self, byte_offset: usize) -> T {
152 unsafe { T::read_be_aligned_at_unchecked(self, byte_offset) }
153 }
154
155 #[inline(always)]
165 #[must_use]
166 pub unsafe fn read_be_aligned_unchecked<T: Read>(&mut self) -> T {
167 unsafe { T::read_be_aligned_unchecked(self) }
168 }
169
170 #[inline(always)]
180 #[must_use]
181 pub unsafe fn read_be_at_unchecked<T: Read>(&self, offset: usize) -> T {
182 unsafe { T::read_be_at_unchecked(self, offset) }
183 }
184
185 #[inline(always)]
195 #[must_use]
196 pub unsafe fn read_be_unchecked<T: Read>(&mut self) -> T {
197 unsafe { T::read_be_unchecked(self) }
198 }
199
200 #[inline(always)]
206 pub fn try_read_be_aligned_at<T: Read>(&self, byte_offset: usize) -> Result<T> {
207 T::try_read_be_aligned_at(self, byte_offset)
208 }
209
210 #[inline(always)]
216 pub fn try_read_be_aligned<T: Read>(&mut self) -> Result<T> {
217 T::try_read_be_aligned(self)
218 }
219
220 #[inline(always)]
226 pub fn try_read_be_at<T: Read>(&self, offset: usize) -> Result<T> {
227 T::try_read_be_at(self, offset)
228 }
229
230 #[inline(always)]
236 pub fn try_read_be<T: Read>(&mut self) -> Result<T> {
237 T::try_read_be(self)
238 }
239
240 #[inline(always)]
246 #[must_use]
247 pub fn read_be_aligned_at<T: Read>(&self, byte_offset: usize) -> T {
248 T::read_be_aligned_at(self, byte_offset)
249 }
250
251 #[inline(always)]
257 #[must_use]
258 pub fn read_be_aligned<T: Read>(&mut self) -> T {
259 T::read_be_aligned(self)
260 }
261
262 #[inline(always)]
268 #[must_use]
269 pub fn read_be_at<T: Read>(&self, offset: usize) -> T {
270 T::read_be_at(self, offset)
271 }
272
273 #[inline(always)]
279 #[must_use]
280 pub fn read_be<T: Read>(&mut self) -> T {
281 T::read_be(self)
282 }
283}
284
285macro_rules! impl_read {
286 (
287 $ty:ident;
288 bytes = $bytes:literal;
289 bits = $bits:literal;
290 offset = $offset:literal;
291 [$($byte:ident),*];
292 [$first:ident, $([$($middle:ident),*],)? $last:ident];
293
294 $read_be_aligned_at_unchecked:ident;
295 $read_be_aligned_unchecked:ident;
296 $read_be_at_unchecked:ident;
297 $read_be_unchecked:ident;
298 $try_read_be_aligned_at:ident;
299 $try_read_be_aligned:ident;
300 $try_read_be_at:ident;
301 $try_read_be:ident;
302 $read_be_aligned_at:ident;
303 $read_be_aligned:ident;
304 $read_be_at:ident;
305 $read_be:ident;
306 ) => {
307 impl<S: Storage> BitBuf<S> {
308
309 #[doc = concat!("Read a [`", stringify!($ty), "`] in [BE-bit, BE-byte] order from `byte_offset` without performing bound checks")]
310 #[doc = concat!("* This is UB if <code>byte_offset + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
314 #[doc = concat!("* Panics in debug mode if <code>byte_offset + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
318 #[inline(always)]
319 #[must_use]
320 pub unsafe fn $read_be_aligned_at_unchecked(&self, byte_offset: usize) -> $ty {
321 let bytes = self.bytes();
322 let len = bytes.len();
323
324 ensure!(
325 byte_offset + $offset < len;
326
327 concat!(
328 "BitBuf::",
329 stringify!($read_be_aligned_at_unchecked),
330 ": index out of bounds! len is {}, offset is {}"
331 ),
332 len,
333 byte_offset + $offset,
334 );
335
336 unsafe {
337 $ty::from_be_bytes(
338 *bytes[byte_offset..byte_offset + $bytes]
339 .as_array()
340 .unwrap_unchecked(),
341 )
342 }
343 }
344
345 #[doc = concat!("Read the next [`", stringify!($ty), "`] in [BE-bit, BE-byte] order without performing bound checks, advancing the internal cursor")]
346 #[doc = concat!("* This is UB if <code>[self.byte_pos()][Self::byte_pos] + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
351 #[doc = concat!("* Panics in debug mode if <code>[self.byte_pos()][Self::byte_pos] + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
356 #[inline(always)]
357 #[must_use]
358 pub unsafe fn $read_be_aligned_unchecked(&mut self) -> $ty {
359 ensure!(
360 self.is_aligned();
361
362 concat!(
363 "BitBuf::",
364 stringify!($read_be_aligned_unchecked),
365 " called at unaligned bit position: {}",
366 ),
367 self.pos(),
368 );
369
370 let v = unsafe { self.$read_be_aligned_at_unchecked(self.byte_pos()) };
371 self.advance_bytes($bytes);
372 v
373 }
374
375
376 #[doc = concat!("Read a [`", stringify!($ty), "`] in [BE-bit, BE-byte] order from `offset` without performing bound checks")]
377 #[doc = concat!("* This is UB if <code>(offset / 8) + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
381 #[doc = concat!("* This is UB if <code>(offset % 8 != 0) && (offset / 8) + ", stringify!($bytes), " >= [self.bytes()][Self::bytes].len()</code>")]
382 #[doc = concat!("* Panics in debug mode if <code>(offset / 8) + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
386 #[doc = concat!("* Panics in debug mode if <code>(offset % 8 != 0) && (offset / 8) + ", stringify!($bytes), " >= [self.bytes()][Self::bytes].len()</code>")]
387 #[inline(always)]
388 #[must_use]
389 pub unsafe fn $read_be_at_unchecked(&self, offset: usize) -> $ty {
390 let byte_idx = offset / 8;
391 let shift = offset % 8;
392
393 let bytes = self.bytes();
394 let len = bytes.len();
395
396 ensure!(
397 byte_idx + $offset < len;
398
399 concat!(
400 "BitBuf::",
401 stringify!($read_be_at_unchecked),
402 ": index out of bounds! len is {}, byte_idx is {}",
403 ),
404 len,
405 byte_idx + $offset,
406 );
407
408 if shift == 0 {
409 unsafe { self.$read_be_aligned_at_unchecked(byte_idx) }
410 } else {
411 ensure!(
412 byte_idx + $bytes < len;
413
414 concat!(
415 "BitBuf::",
416 stringify!($read_be_at_unchecked),
417 ": lookahead index out of bounds! len is {}, lookahead byte_idx is {}",
418 ),
419 len,
420 byte_idx + $bytes,
421 );
422
423 unsafe {
424 let ptr = bytes.as_ptr().add(byte_idx);
425 let high = $ty::from_be_bytes(*(ptr as *const [u8; $bytes]));
426 let low = *bytes.get_unchecked(byte_idx + $bytes) as $ty;
427 (high << shift) | (low >> (8 - shift))
428 }
429 }
430 }
431
432 #[doc = concat!("Read the next [`", stringify!($ty), "`] in [BE-bit, BE-byte] order without performing bound checks, advancing the internal cursor")]
433 #[doc = concat!("* This is UB if <code>([self.pos()][Self::pos] / 8) + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
437 #[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>")]
438 #[doc = concat!("* Panics in debug mode if <code>([self.pos()][Self::pos] / 8) + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
442 #[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>")]
443 #[inline(always)]
444 #[must_use]
445 pub unsafe fn $read_be_unchecked(&mut self) -> $ty {
446 let v = unsafe { self.$read_be_at_unchecked(self.pos()) };
447 self.advance_bytes($bytes);
448 v
449 }
450
451 #[doc = concat!("Read a [`", stringify!($ty), "`] in [BE-bit, BE-byte] order from `byte_offset` while performing bound checks")]
452 #[doc = concat!(" * if <code>byte_offset + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
457 #[inline(always)]
458 pub fn $try_read_be_aligned_at(&self, byte_offset: usize) -> Result<$ty> {
459 let len = self.bytes().len();
460
461 if byte_offset + $offset >= len {
462 return Err(Error::OutOfBounds);
463 }
464
465 Ok(unsafe { self.$read_be_aligned_at_unchecked(byte_offset) })
466 }
467
468 #[doc = concat!("Read the next [`", stringify!($ty), "`] in [BE-bit, BE-byte] order while performing alignment and bound checks, advancing the internal cursor")]
469 #[doc = concat!(" * if <code>[self.byte_pos()][Self::byte_pos] + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
476 #[inline(always)]
477 pub fn $try_read_be_aligned(&mut self) -> Result<$ty> {
478 if !self.is_aligned() {
479 return Err(Error::Unaligned);
480 }
481
482 let v = self.$try_read_be_aligned_at(self.byte_pos())?;
483 self.advance_bytes($bytes);
484 Ok(v)
485 }
486
487 #[doc = concat!("Read a [`", stringify!($ty), "`] in [BE-bit, BE-byte] order from `offset` while performing bound checks")]
488 #[doc = concat!(" * if <code>(offset / 8) + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
493 #[doc = concat!(" * if <code>(offset % 8 != 0) && (offset / 8) + ", stringify!($bytes), " >= [self.bytes()][Self::bytes].len()</code>")]
494 #[inline(always)]
495 pub fn $try_read_be_at(&self, offset: usize) -> Result<$ty> {
496 let byte_idx = offset / 8;
497 let shift = offset % 8;
498
499 let len = self.bytes().len();
500
501 if byte_idx + $offset >= len {
502 return Err(Error::OutOfBounds);
503 }
504
505 if shift != 0 && byte_idx + $bytes >= len {
506 return Err(Error::OutOfBounds);
507 }
508
509 Ok(unsafe { self.$read_be_at_unchecked(offset) })
510 }
511
512 #[doc = concat!("Read the next [`", stringify!($ty), "`] in [BE-bit, BE-byte] order while performing bound checks, advancing the internal cursor")]
513 #[doc = concat!(" * if <code>([self.pos()][Self::pos] / 8) + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
518 #[doc = concat!(" * if <code>([self.pos()][Self::pos] % 8 != 0) && ([self.pos()][Self::pos] / 8) + ", stringify!($bytes), " >= [self.bytes()][Self::bytes].len()</code>")]
519 #[inline(always)]
520 pub fn $try_read_be(&mut self) -> Result<$ty> {
521 let v = self.$try_read_be_at(self.pos())?;
522 self.advance_bytes($bytes);
523 Ok(v)
524 }
525
526 #[doc = concat!("Read a [`", stringify!($ty), "`] in [BE-bit, BE-byte] order from `byte_offset` panicking on out of bounds")]
527 #[doc = concat!("* Panics if <code>byte_offset + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
531 #[inline(always)]
532 #[must_use]
533 pub fn $read_be_aligned_at(&self, byte_offset: usize) -> $ty {
534 self
535 .$try_read_be_aligned_at(byte_offset)
536 .expect(concat!("BitBuf::", stringify!($read_be_aligned_at), " out of bounds"))
537 }
538
539 #[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")]
540 #[doc = concat!(" * if <code>[self.byte_pos()][Self::byte_pos] + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
545 #[inline(always)]
546 #[must_use]
547 pub fn $read_be_aligned(&mut self) -> $ty {
548 self
549 .$try_read_be_aligned()
550 .expect(concat!("BitBuf::", stringify!($read_be_aligned), " unaligned cursor or out of bounds"))
551 }
552
553 #[doc = concat!("Read a [`", stringify!($ty), "`] in [BE-bit, BE-byte] order from `offset` panicking on out of bounds")]
554 #[doc = concat!("* Panics if <code>(offset / 8) + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
558 #[doc = concat!("* Panics if <code>(offset % 8 != 0) && (offset / 8) + ", stringify!($bytes), " >= [self.bytes()][Self::bytes].len()</code>")]
559 #[inline(always)]
560 #[must_use]
561 pub fn $read_be_at(&self, offset: usize) -> $ty {
562 self
563 .$try_read_be_at(offset)
564 .expect(concat!("BitBuf::", stringify!($read_be_at), " out of bounds"))
565 }
566
567 #[doc = concat!("Read the next [`", stringify!($ty), "`] in [BE-bit, BE-byte] order panicking on out of bounds, advancing the internal cursor")]
568 #[doc = concat!("* Panics if <code>([self.pos()][Self::pos] / 8) + ", stringify!($offset), " >= [self.bytes()][Self::bytes].len()</code>")]
572 #[doc = concat!("* Panics if <code>([self.pos()][Self::pos] % 8 != 0) && ([self.pos()][Self::pos] / 8) + ", stringify!($bytes), " >= [self.bytes()][Self::bytes].len()</code>")]
573 #[inline(always)]
574 #[must_use]
575 pub fn $read_be(&mut self) -> $ty {
576 self
577 .$try_read_be()
578 .expect(concat!("BitBuf::", stringify!($read_be), " out of bounds"))
579 }
580 }
581
582 impl Read for $ty {
583 #[inline(always)]
584 unsafe fn read_be_aligned_at_unchecked<S: Storage>(buf: &BitBuf<S>, byte_offset: usize) -> Self {
585 unsafe { buf.$read_be_aligned_at_unchecked(byte_offset) }
586 }
587
588 #[inline(always)]
589 unsafe fn read_be_aligned_unchecked<S: Storage>(buf: &mut BitBuf<S>) -> Self {
590 unsafe { buf.$read_be_aligned_unchecked() }
591 }
592
593 #[inline(always)]
594 unsafe fn read_be_at_unchecked<S: Storage>(buf: &BitBuf<S>, offset: usize) -> Self {
595 unsafe { buf.$read_be_at_unchecked(offset) }
596 }
597
598 #[inline(always)]
599 unsafe fn read_be_unchecked<S: Storage>(buf: &mut BitBuf<S>) -> Self {
600 unsafe { buf.$read_be_unchecked() }
601 }
602
603 #[inline(always)]
604 fn try_read_be_aligned_at<S: Storage>(buf: &BitBuf<S>, byte_offset: usize) -> Result<Self> {
605 buf.$try_read_be_aligned_at(byte_offset)
606 }
607
608 #[inline(always)]
609 fn try_read_be_aligned<S: Storage>(buf: &mut BitBuf<S>) -> Result<Self> {
610 buf.$try_read_be_aligned()
611 }
612
613 #[inline(always)]
614 fn try_read_be_at<S: Storage>(buf: &BitBuf<S>, offset: usize) -> Result<Self> {
615 buf.$try_read_be_at(offset)
616 }
617
618 #[inline(always)]
619 fn try_read_be<S: Storage>(buf: &mut BitBuf<S>) -> Result<Self> {
620 buf.$try_read_be()
621 }
622
623 #[inline(always)]
624 fn read_be_aligned_at<S: Storage>(buf: &BitBuf<S>, byte_offset: usize) -> Self {
625 buf.$read_be_aligned_at(byte_offset)
626 }
627
628 #[inline(always)]
629 fn read_be_aligned<S: Storage>(buf: &mut BitBuf<S>) -> Self {
630 buf.$read_be_aligned()
631 }
632
633 #[inline(always)]
634 fn read_be_at<S: Storage>(buf: &BitBuf<S>, offset: usize) -> Self {
635 buf.$read_be_at(offset)
636 }
637
638 #[inline(always)]
639 fn read_be<S: Storage>(buf: &mut BitBuf<S>) -> Self {
640 buf.$read_be()
641 }
642 }
643 };
644}
645
646use impl_read;