steam_vdf_parser/binary/
byte_reader.rs

1//! Utilities for reading little-endian values from byte slices.
2
3/// Reads a little-endian u32 from a byte slice.
4///
5/// Returns `None` if the slice doesn't have enough bytes.
6///
7/// # Examples
8/// ```
9/// use steam_vdf_parser::binary::read_u32_le;
10///
11/// let data = [0x01, 0x02, 0x03, 0x04];
12/// assert_eq!(read_u32_le(&data), Some(0x04030201));
13/// assert_eq!(read_u32_le(&[0x01, 0x02]), None);
14/// ```
15#[inline]
16pub fn read_u32_le(input: &[u8]) -> Option<u32> {
17    input.get(..4).and_then(|bytes| {
18        let arr: [u8; 4] = bytes.try_into().ok()?;
19        Some(u32::from_le_bytes(arr))
20    })
21}
22
23/// Reads a little-endian u64 from a byte slice.
24///
25/// Returns `None` if the slice doesn't have enough bytes.
26///
27/// # Examples
28/// ```
29/// use steam_vdf_parser::binary::read_u64_le;
30///
31/// let data = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
32/// assert_eq!(read_u64_le(&data), Some(0x0807060504030201));
33/// assert_eq!(read_u64_le(&[0x01, 0x02]), None);
34/// ```
35#[inline]
36pub fn read_u64_le(input: &[u8]) -> Option<u64> {
37    input.get(..8).and_then(|bytes| {
38        let arr: [u8; 8] = bytes.try_into().ok()?;
39        Some(u64::from_le_bytes(arr))
40    })
41}
42
43/// Reads a little-endian u32 from a byte slice at a specific offset.
44///
45/// Returns `None` if the slice doesn't have enough bytes from the offset.
46///
47/// # Examples
48/// ```
49/// use steam_vdf_parser::binary::read_u32_le_at;
50///
51/// let data = [0xFF, 0xFF, 0x01, 0x02, 0x03, 0x04];
52/// assert_eq!(read_u32_le_at(&data, 2), Some(0x04030201));
53/// assert_eq!(read_u32_le_at(&data, 4), None);
54/// ```
55#[inline]
56pub fn read_u32_le_at(input: &[u8], offset: usize) -> Option<u32> {
57    input.get(offset..offset + 4).and_then(|bytes| {
58        let arr: [u8; 4] = bytes.try_into().ok()?;
59        Some(u32::from_le_bytes(arr))
60    })
61}
62
63/// Reads a little-endian u64 from a byte slice at a specific offset.
64///
65/// Returns `None` if the slice doesn't have enough bytes from the offset.
66///
67/// # Examples
68/// ```
69/// use steam_vdf_parser::binary::read_u64_le_at;
70///
71/// let data = [0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
72/// assert_eq!(read_u64_le_at(&data, 4), Some(0x0807060504030201));
73/// assert_eq!(read_u64_le_at(&data, 8), None);
74/// ```
75#[inline]
76pub fn read_u64_le_at(input: &[u8], offset: usize) -> Option<u64> {
77    input.get(offset..offset + 8).and_then(|bytes| {
78        let arr: [u8; 8] = bytes.try_into().ok()?;
79        Some(u64::from_le_bytes(arr))
80    })
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86
87    #[test]
88    fn test_read_u32_le() {
89        let data = [0x01, 0x02, 0x03, 0x04];
90        assert_eq!(read_u32_le(&data), Some(0x04030201));
91    }
92
93    #[test]
94    fn test_read_u32_le_short() {
95        assert_eq!(read_u32_le(&[0x01, 0x02]), None);
96        assert_eq!(read_u32_le(&[]), None);
97    }
98
99    #[test]
100    fn test_read_u64_le() {
101        let data = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
102        assert_eq!(read_u64_le(&data), Some(0x0807060504030201));
103    }
104
105    #[test]
106    fn test_read_u64_le_short() {
107        assert_eq!(read_u64_le(&[0x01, 0x02, 0x03, 0x04]), None);
108        assert_eq!(read_u64_le(&[]), None);
109    }
110
111    #[test]
112    fn test_read_u32_le_at() {
113        let data = [0xFF, 0xFF, 0x01, 0x02, 0x03, 0x04];
114        assert_eq!(read_u32_le_at(&data, 0), Some(0x0201FFFF));
115        assert_eq!(read_u32_le_at(&data, 2), Some(0x04030201));
116    }
117
118    #[test]
119    fn test_read_u32_le_at_out_of_bounds() {
120        let data = [0x01, 0x02, 0x03, 0x04];
121        assert_eq!(read_u32_le_at(&data, 1), None);
122        assert_eq!(read_u32_le_at(&data, 4), None);
123    }
124
125    #[test]
126    fn test_read_u64_le_at() {
127        let data = [0xFF; 12];
128        assert_eq!(read_u64_le_at(&data, 0), Some(0xFFFFFFFFFFFFFFFF));
129        assert_eq!(read_u64_le_at(&data, 4), Some(0xFFFFFFFFFFFFFFFF));
130    }
131
132    #[test]
133    fn test_read_u64_le_at_out_of_bounds() {
134        let data = [0x01; 8];
135        assert_eq!(read_u64_le_at(&data, 1), None);
136        assert_eq!(read_u64_le_at(&data, 8), None);
137    }
138}