1#![no_std]
2#![forbid(unsafe_code)]
3
4macro_rules! bounded_reader {
25 ($name:ident, $ty:ty, $width:literal, $from_bytes:ident) => {
26 #[doc = concat!("Read a ", stringify!($ty), " at `off`; 0 if out of range. Never panics.")]
27 #[must_use]
28 pub fn $name(data: &[u8], off: usize) -> $ty {
29 let Some(end) = off.checked_add($width) else {
30 return 0;
31 };
32 match data.get(off..end) {
33 Some(slice) => {
34 let mut buf = [0u8; $width];
35 buf.copy_from_slice(slice);
36 <$ty>::$from_bytes(buf)
37 }
38 None => 0,
39 }
40 }
41 };
42}
43
44bounded_reader!(be_u16, u16, 2, from_be_bytes);
45bounded_reader!(be_u32, u32, 4, from_be_bytes);
46bounded_reader!(be_u64, u64, 8, from_be_bytes);
47bounded_reader!(le_u16, u16, 2, from_le_bytes);
48bounded_reader!(le_u32, u32, 4, from_le_bytes);
49bounded_reader!(le_u64, u64, 8, from_le_bytes);
50
51#[cfg(test)]
52mod tests {
53 use super::{be_u16, be_u32, be_u64, le_u16, le_u32, le_u64};
54
55 #[test]
56 fn big_endian_reads_in_range() {
57 assert_eq!(be_u16(&[0x12, 0x34], 0), 0x1234);
58 assert_eq!(be_u32(&[0, 0, 1, 0], 0), 256);
59 assert_eq!(
60 be_u64(&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08], 0),
61 0x0102_0304_0506_0708
62 );
63 }
64
65 #[test]
66 fn little_endian_reads_in_range() {
67 assert_eq!(le_u16(&[0x34, 0x12], 0), 0x1234);
68 assert_eq!(le_u32(&[0, 1, 0, 0], 0), 256);
69 assert_eq!(
70 le_u64(&[0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01], 0),
71 0x0102_0304_0506_0708
72 );
73 }
74
75 #[test]
76 fn reads_honor_offset() {
77 assert_eq!(be_u16(&[0xaa, 0x12, 0x34], 1), 0x1234);
78 assert_eq!(le_u32(&[0xff, 0xff, 0, 1, 0, 0], 2), 256);
79 }
80
81 #[test]
82 fn out_of_range_returns_zero_never_panics() {
83 assert_eq!(be_u32(&[1, 2, 3], 0), 0);
85 assert_eq!(be_u64(&[1, 2, 3, 4, 5, 6, 7], 0), 0);
86 assert_eq!(be_u32(&[1, 2, 3, 4], 2), 0);
88 assert_eq!(le_u16(&[1, 2], 2), 0);
89 assert_eq!(be_u16(&[], 0), 0);
91 assert_eq!(le_u32(&[1, 2, 3, 4], 100), 0);
92 }
93
94 #[test]
95 fn offset_overflow_returns_zero() {
96 assert_eq!(be_u32(&[1, 2, 3, 4], usize::MAX), 0);
98 }
99}