1#[must_use]
10pub fn le_u16(data: &[u8], off: usize) -> u16 {
11 match data.get(off..off + 2) {
12 Some(s) => u16::from_le_bytes([s[0], s[1]]),
13 None => 0,
14 }
15}
16
17#[must_use]
19pub fn le_u32(data: &[u8], off: usize) -> u32 {
20 match data.get(off..off + 4) {
21 Some(s) => u32::from_le_bytes([s[0], s[1], s[2], s[3]]),
22 None => 0,
23 }
24}
25
26#[must_use]
28pub fn le_u64(data: &[u8], off: usize) -> u64 {
29 match data.get(off..off + 8) {
30 Some(s) => u64::from_le_bytes([s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7]]),
31 None => 0,
32 }
33}
34
35#[must_use]
39pub fn le_u48(data: &[u8], off: usize) -> u64 {
40 match data.get(off..off + 6) {
41 Some(s) => {
42 u64::from(s[0])
43 | (u64::from(s[1]) << 8)
44 | (u64::from(s[2]) << 16)
45 | (u64::from(s[3]) << 24)
46 | (u64::from(s[4]) << 32)
47 | (u64::from(s[5]) << 40)
48 }
49 None => 0,
50 }
51}
52
53#[must_use]
56pub fn bytes16(data: &[u8], off: usize) -> [u8; 16] {
57 let mut out = [0u8; 16];
58 if let Some(s) = data.get(off..off + 16) {
59 out.copy_from_slice(s);
60 }
61 out
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67
68 #[test]
69 fn le_readers_decode_in_range() {
70 let d = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
71 assert_eq!(le_u16(&d, 0), 0x0201);
72 assert_eq!(le_u32(&d, 0), 0x0403_0201);
73 assert_eq!(le_u64(&d, 0), 0x0807_0605_0403_0201);
74 assert_eq!(le_u48(&d, 0), 0x0605_0403_0201);
75 }
76
77 #[test]
78 fn le_readers_return_zero_out_of_range() {
79 let d = [0xffu8; 3];
80 assert_eq!(le_u16(&d, 2), 0);
81 assert_eq!(le_u32(&d, 0), 0);
82 assert_eq!(le_u64(&d, 0), 0);
83 assert_eq!(le_u48(&d, 0), 0);
84 assert_eq!(le_u16(&[], 0), 0);
85 }
86
87 #[test]
88 fn bytes16_copies_or_zero_fills() {
89 let mut d = [0u8; 20];
90 for (i, b) in d.iter_mut().enumerate() {
91 *b = i as u8;
92 }
93 assert_eq!(bytes16(&d, 0)[15], 15);
94 assert_eq!(bytes16(&d, 4)[0], 4);
95 assert_eq!(bytes16(&d, 10), [0u8; 16]);
97 assert_eq!(bytes16(&[], 0), [0u8; 16]);
98 }
99}