picori/helper/
parser.rs

1use std::borrow::Borrow;
2use std::panic::Location;
3
4use super::endian::{BigEndian, EndianAgnostic, LittleEndian, NativeEndian};
5use super::Reader;
6use crate::Result;
7
8/// A helper trait for types that can interpret bytes.
9pub trait Parser: Reader {
10    /// Read a single u8.
11    #[track_caller]
12    #[inline]
13    fn u8(&mut self) -> Result<u8> {
14        let mut buffer = [0u8; 1];
15        self.read_into_tracked(&mut buffer, Location::caller())?;
16        Ok(buffer[0])
17    }
18
19    /// Read a single endian agnostic u16.
20    fn eu16<E: EndianAgnostic>(&mut self, caller: &'static Location) -> Result<u16> {
21        let mut buffer = [0u8; 2];
22        self.read_into_tracked(&mut buffer, caller)?;
23        Ok(E::u16_from_bytes(&buffer))
24    }
25
26    /// Read a single endian agnostic u32.
27    fn eu32<E: EndianAgnostic>(&mut self, caller: &'static Location) -> Result<u32> {
28        let mut buffer = [0u8; 4];
29        self.read_into_tracked(&mut buffer, caller)?;
30        Ok(E::u32_from_bytes(&buffer))
31    }
32
33    /// Read a single u16 in native endian.
34    #[track_caller]
35    #[inline]
36    fn u16(&mut self) -> Result<u16> {
37        self.eu16::<NativeEndian>(Location::caller())
38    }
39
40    /// Read a single u32 in native endian.
41    #[track_caller]
42    #[inline]
43    fn u32(&mut self) -> Result<u32> {
44        self.eu32::<NativeEndian>(Location::caller())
45    }
46
47    /// Read a single u16 in big endian.
48    #[track_caller]
49    #[inline]
50    fn bu16(&mut self) -> Result<u16> {
51        self.eu16::<BigEndian>(Location::caller())
52    }
53
54    /// Read a single u32 in big endian.
55    #[track_caller]
56    #[inline]
57    fn bu32(&mut self) -> Result<u32> {
58        self.eu32::<BigEndian>(Location::caller())
59    }
60
61    /// Read a single u16 in little endian.
62    #[track_caller]
63    #[inline]
64    fn lu16(&mut self) -> Result<u16> {
65        self.eu16::<LittleEndian>(Location::caller())
66    }
67
68    /// Read a single u32 in little endian.
69    #[track_caller]
70    #[inline]
71    fn lu32(&mut self) -> Result<u32> {
72        self.eu32::<LittleEndian>(Location::caller())
73    }
74
75    /// Read string with the given encoding until the NUL character is
76    /// encountered or `L` bytes have been read.
77    #[track_caller]
78    fn str<const L: usize, E: ParseStringEncoding>(&mut self) -> Result<String> {
79        let mut buffer = [0u8; L];
80        self.read_into_tracked(&mut buffer, Location::caller())?;
81        E::parse_str(buffer)
82    }
83
84    /// Read array of u8 with the given length `L`.
85    #[track_caller]
86    #[inline]
87    fn u8_array<const L: usize>(&mut self) -> Result<[u8; L]> {
88        self.read_buffer_of_tracked::<u8, L>(Location::caller())
89    }
90
91    /// Read array of endian agnostic u16 with the given length `L`.
92    #[inline]
93    fn eu16_array<E: EndianAgnostic, const L: usize>(
94        &mut self,
95        caller: &'static Location,
96    ) -> Result<[u16; L]> {
97        let mut buf = self.read_buffer_of_tracked::<u16, L>(caller)?;
98        for value in buf.iter_mut().take(L) {
99            *value = E::u16_from_native(*value);
100        }
101        Ok(buf)
102    }
103
104    /// Read array of big endian u16 with the given length `L`.
105    #[track_caller]
106    #[inline]
107    fn bu16_array<const L: usize>(&mut self) -> Result<[u16; L]> {
108        self.eu16_array::<BigEndian, L>(Location::caller())
109    }
110
111    /// Read array of little endian u16 with the given length `L`.
112    #[track_caller]
113    #[inline]
114    fn lu16_array<const L: usize>(&mut self) -> Result<[u16; L]> {
115        self.eu16_array::<LittleEndian, L>(Location::caller())
116    }
117
118    /// Read array of endian agnostic u32 with the given length `L`.
119    #[inline]
120    fn eu32_array<E: EndianAgnostic, const L: usize>(
121        &mut self,
122        caller: &'static Location,
123    ) -> Result<[u32; L]> {
124        let mut buf = self.read_buffer_of_tracked::<u32, L>(caller)?;
125        for value in buf.iter_mut().take(L) {
126            *value = E::u32_from_native(*value);
127        }
128        Ok(buf)
129    }
130
131    /// Read array of big endian u32 with the given length `L`.
132    #[track_caller]
133    #[inline]
134    fn bu32_array<const L: usize>(&mut self) -> Result<[u32; L]> {
135        self.eu32_array::<BigEndian, L>(Location::caller())
136    }
137
138    /// Read array of little endian u32 with the given length `L`.
139    #[track_caller]
140    #[inline]
141    fn lu32_array<const L: usize>(&mut self) -> Result<[u32; L]> {
142        self.eu32_array::<LittleEndian, L>(Location::caller())
143    }
144}
145
146/// Implementation of [`Parser`] for all [`Reader`].
147impl<Base: Reader> Parser for Base {}
148
149pub trait ParseStringEncoding {
150    fn parse_str<I>(data: I) -> Result<String>
151    where
152        I: IntoIterator,
153        I::Item: Borrow<u8> + Sized;
154}
155
156// -------------------------------------------------------------------------------
157// Tests
158// -------------------------------------------------------------------------------
159
160#[cfg(test)]
161mod tests {
162    use super::*;
163
164    #[test]
165    fn u8() {
166        let mut data: &[u8] = &[0x01, 0x02, 0x03, 0x04];
167        assert_eq!(data.u8().unwrap(), 0x01);
168        assert_eq!(data.u8().unwrap(), 0x02);
169        assert_eq!(data.u8().unwrap(), 0x03);
170        assert_eq!(data.u8().unwrap(), 0x04);
171    }
172
173    #[test]
174    fn u16() {
175        let mut data: &[u8] = &[0x01, 0x02, 0x01, 0x02];
176        assert_eq!(data.bu16().unwrap(), 0x0102);
177        assert_eq!(data.lu16().unwrap(), 0x0201);
178    }
179
180    #[test]
181    fn u32() {
182        let mut data: &[u8] = &[0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04];
183        assert_eq!(data.bu32().unwrap(), 0x01020304);
184        assert_eq!(data.lu32().unwrap(), 0x04030201);
185    }
186
187    #[test]
188    fn u8_array() {
189        let mut data: &[u8] = &[0x01, 0x02, 0x03, 0x04];
190        assert_eq!(data.u8_array::<4>().unwrap(), [
191            0x01, 0x02, 0x03, 0x04
192        ]);
193    }
194
195    #[test]
196    fn u16_array() {
197        let mut data: &[u8] = &[0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04];
198        assert_eq!(data.bu16_array::<2>().unwrap(), [
199            0x0102, 0x0304,
200        ]);
201        assert_eq!(data.lu16_array::<2>().unwrap(), [
202            0x0201, 0x0403,
203        ]);
204    }
205
206    #[test]
207    fn u32_array() {
208        let mut data: &[u8] = &[
209            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
210            0x07, 0x08,
211        ];
212        assert_eq!(data.bu32_array::<2>().unwrap(), [
213            0x01020304, 0x05060708
214        ]);
215        assert_eq!(data.lu32_array::<2>().unwrap(), [
216            0x04030201, 0x08070605
217        ]);
218    }
219}