justcode_core/
reader.rs

1//! Reader for decoding values from bytes.
2
3use crate::config::Config;
4use crate::error::{JustcodeError, Result};
5
6/// Reader for decoding values from a byte slice.
7pub struct Reader<'a> {
8    data: &'a [u8],
9    position: usize,
10    config: Config,
11}
12
13impl<'a> Reader<'a> {
14    /// Create a new reader with the given byte slice and configuration.
15    pub fn new(data: &'a [u8], config: Config) -> Self {
16        Self {
17            data,
18            position: 0,
19            config,
20        }
21    }
22
23    /// Read a single byte.
24    pub fn read_u8(&mut self) -> Result<u8> {
25        self.check_size(1)?;
26        let value = self.data[self.position];
27        self.position += 1;
28        Ok(value)
29    }
30
31    /// Read a u16 in little-endian format.
32    pub fn read_u16(&mut self) -> Result<u16> {
33        self.check_size(2)?;
34        let bytes = &self.data[self.position..self.position + 2];
35        self.position += 2;
36        Ok(u16::from_le_bytes([bytes[0], bytes[1]]))
37    }
38
39    /// Read a u32 in little-endian format.
40    pub fn read_u32(&mut self) -> Result<u32> {
41        self.check_size(4)?;
42        let bytes = &self.data[self.position..self.position + 4];
43        self.position += 4;
44        Ok(u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
45    }
46
47    /// Read a u64 in little-endian format.
48    pub fn read_u64(&mut self) -> Result<u64> {
49        self.check_size(8)?;
50        let bytes = &self.data[self.position..self.position + 8];
51        self.position += 8;
52        Ok(u64::from_le_bytes([
53            bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
54        ]))
55    }
56
57    /// Read an i8.
58    pub fn read_i8(&mut self) -> Result<i8> {
59        Ok(self.read_u8()? as i8)
60    }
61
62    /// Read an i16 in little-endian format.
63    pub fn read_i16(&mut self) -> Result<i16> {
64        Ok(self.read_u16()? as i16)
65    }
66
67    /// Read an i32 in little-endian format.
68    pub fn read_i32(&mut self) -> Result<i32> {
69        Ok(self.read_u32()? as i32)
70    }
71
72    /// Read an i64 in little-endian format.
73    pub fn read_i64(&mut self) -> Result<i64> {
74        Ok(self.read_u64()? as i64)
75    }
76
77    /// Read an f32 in little-endian format.
78    pub fn read_f32(&mut self) -> Result<f32> {
79        let bits = self.read_u32()?;
80        Ok(f32::from_bits(bits))
81    }
82
83    /// Read an f64 in little-endian format.
84    pub fn read_f64(&mut self) -> Result<f64> {
85        let bits = self.read_u64()?;
86        Ok(f64::from_bits(bits))
87    }
88
89    /// Read a boolean (decoded from u8: 0 = false, 1 = true).
90    pub fn read_bool(&mut self) -> Result<bool> {
91        let value = self.read_u8()?;
92        Ok(value != 0)
93    }
94
95    /// Read a byte slice of the given length.
96    pub fn read_bytes(&mut self, len: usize) -> Result<&'a [u8]> {
97        self.check_size(len)?;
98        let bytes = &self.data[self.position..self.position + len];
99        self.position += len;
100        Ok(bytes)
101    }
102
103    /// Get the current configuration.
104    pub fn config(&self) -> Config {
105        self.config
106    }
107
108    /// Get the number of bytes read so far.
109    pub fn bytes_read(&self) -> usize {
110        self.position
111    }
112
113    /// Get the remaining bytes.
114    pub fn remaining(&self) -> &'a [u8] {
115        &self.data[self.position..]
116    }
117
118    /// Check if we have enough bytes remaining.
119    fn check_size(&self, needed: usize) -> Result<()> {
120        let available = self.data.len().saturating_sub(self.position);
121        if available < needed {
122            return Err(JustcodeError::UnexpectedEndOfInput {
123                expected: needed,
124                got: available,
125            });
126        }
127
128        // Check size limit if configured
129        if let Some(limit) = self.config.limit {
130            let new_size = self.position + needed;
131            if new_size > limit {
132                return Err(JustcodeError::SizeLimitExceeded {
133                    limit,
134                    requested: new_size,
135                });
136            }
137        }
138
139        Ok(())
140    }
141}
142
143#[cfg(test)]
144mod tests {
145    use super::*;
146    use crate::config;
147
148    #[test]
149    fn test_read_primitives() {
150        let config = config::standard();
151        let data = vec![
152            42u8,                    // u8
153            0xE8, 0x03,              // u16: 1000
154            0xA0, 0x86, 0x01, 0x00,  // u32: 100000
155            0x00, 0xCA, 0x9A, 0x3B, 0x00, 0x00, 0x00, 0x00, // u64: 1000000000
156            1,                       // bool: true
157            0,                       // bool: false
158        ];
159
160        let mut reader = Reader::new(&data, config);
161        assert_eq!(reader.read_u8().unwrap(), 42);
162        assert_eq!(reader.read_u16().unwrap(), 1000);
163        assert_eq!(reader.read_u32().unwrap(), 100000);
164        assert_eq!(reader.read_u64().unwrap(), 1000000000);
165        assert_eq!(reader.read_bool().unwrap(), true);
166        assert_eq!(reader.read_bool().unwrap(), false);
167    }
168
169    #[test]
170    fn test_read_floats() {
171        let config = config::standard();
172        let mut writer = crate::writer::Writer::new(config);
173        writer.write_f32(3.14).unwrap();
174        writer.write_f64(2.718).unwrap();
175        let data = writer.into_bytes();
176
177        let mut reader = Reader::new(&data, config);
178        assert!((reader.read_f32().unwrap() - 3.14).abs() < 0.01);
179        assert!((reader.read_f64().unwrap() - 2.718).abs() < 0.001);
180    }
181
182    #[test]
183    fn test_unexpected_end_of_input() {
184        let config = config::standard();
185        let data = vec![42u8];
186        let mut reader = Reader::new(&data, config);
187        assert!(reader.read_u32().is_err());
188    }
189
190    #[test]
191    fn test_size_limit() {
192        let config = config::standard().with_limit(10);
193        let data = vec![0u8; 20];
194        let mut reader = Reader::new(&data, config);
195        assert!(reader.read_bytes(15).is_err());
196    }
197
198    #[test]
199    fn test_read_signed_integers() {
200        let config = config::standard();
201        let mut writer = crate::writer::Writer::new(config);
202        writer.write_i8(-42).unwrap();
203        writer.write_i16(-1000).unwrap();
204        writer.write_i32(-100000).unwrap();
205        writer.write_i64(-1000000000).unwrap();
206        let data = writer.into_bytes();
207
208        let mut reader = Reader::new(&data, config);
209        assert_eq!(reader.read_i8().unwrap(), -42);
210        assert_eq!(reader.read_i16().unwrap(), -1000);
211        assert_eq!(reader.read_i32().unwrap(), -100000);
212        assert_eq!(reader.read_i64().unwrap(), -1000000000);
213    }
214
215    #[test]
216    fn test_read_bytes() {
217        let config = config::standard();
218        let data = vec![1, 2, 3, 4, 5, 6, 7, 8];
219        let mut reader = Reader::new(&data, config);
220        let bytes = reader.read_bytes(4).unwrap();
221        assert_eq!(bytes, &[1, 2, 3, 4]);
222        assert_eq!(reader.bytes_read(), 4);
223    }
224
225    #[test]
226    fn test_remaining() {
227        let config = config::standard();
228        let data = vec![1, 2, 3, 4, 5];
229        let mut reader = Reader::new(&data, config);
230        reader.read_u8().unwrap();
231        assert_eq!(reader.remaining(), &[2, 3, 4, 5]);
232    }
233
234    #[test]
235    fn test_config() {
236        let config = config::standard().with_limit(100);
237        let data = vec![1, 2, 3];
238        let reader = Reader::new(&data, config);
239        assert_eq!(reader.config().limit, Some(100));
240    }
241
242    #[test]
243    fn test_bytes_read() {
244        let config = config::standard();
245        let data = vec![1, 2, 3, 4, 5];
246        let mut reader = Reader::new(&data, config);
247        assert_eq!(reader.bytes_read(), 0);
248        reader.read_u8().unwrap();
249        assert_eq!(reader.bytes_read(), 1);
250        reader.read_u16().unwrap();
251        assert_eq!(reader.bytes_read(), 3);
252    }
253
254    #[test]
255    fn test_size_limit_edge_cases() {
256        let config = config::standard().with_limit(5);
257        let data = vec![0u8; 10];
258        let mut reader = Reader::new(&data, config);
259        
260        // Should succeed reading 5 bytes
261        reader.read_bytes(5).unwrap();
262        
263        // Should fail reading beyond limit
264        assert!(reader.read_bytes(1).is_err());
265    }
266
267    #[test]
268    fn test_read_bool_edge_cases() {
269        let config = config::standard();
270        let data = vec![0, 1, 2, 255];
271        let mut reader = Reader::new(&data, config);
272        assert_eq!(reader.read_bool().unwrap(), false);
273        assert_eq!(reader.read_bool().unwrap(), true);
274        assert_eq!(reader.read_bool().unwrap(), true); // 2 != 0
275        assert_eq!(reader.read_bool().unwrap(), true); // 255 != 0
276    }
277
278    #[test]
279    fn test_check_size_error_message() {
280        let config = config::standard();
281        let data = vec![1u8, 2];
282        let mut reader = Reader::new(&data, config);
283        let err = reader.read_u32().unwrap_err();
284        match err {
285            JustcodeError::UnexpectedEndOfInput { expected, got } => {
286                assert_eq!(expected, 4);
287                assert_eq!(got, 2);
288            }
289            _ => panic!("Expected UnexpectedEndOfInput error"),
290        }
291    }
292
293    #[test]
294    fn test_size_limit_exceeded_error() {
295        let config = config::standard().with_limit(5);
296        let data = vec![0u8; 10];
297        let mut reader = Reader::new(&data, config);
298        // Read 5 bytes successfully
299        reader.read_bytes(5).unwrap();
300        // Try to read 1 more byte, should exceed limit
301        let err = reader.read_bytes(1).unwrap_err();
302        match err {
303            JustcodeError::SizeLimitExceeded { limit, requested } => {
304                assert_eq!(limit, 5);
305                assert_eq!(requested, 6);
306            }
307            _ => panic!("Expected SizeLimitExceeded error"),
308        }
309    }
310
311    #[test]
312    fn test_size_limit_at_boundary() {
313        let config = config::standard().with_limit(5);
314        let data = vec![0u8; 10];
315        let mut reader = Reader::new(&data, config);
316        // Should succeed reading exactly at limit
317        reader.read_bytes(5).unwrap();
318        // Next read should fail
319        assert!(reader.read_bytes(1).is_err());
320    }
321
322    #[test]
323    fn test_check_size_with_limit_none() {
324        let config = config::standard(); // No limit
325        let data = vec![1u8, 2, 3, 4, 5];
326        let mut reader = Reader::new(&data, config);
327        // Should succeed reading all bytes when no limit
328        reader.read_bytes(5).unwrap();
329    }
330
331    #[test]
332    fn test_check_size_with_limit_success() {
333        let config = config::standard().with_limit(10);
334        let data = vec![0u8; 20];
335        let mut reader = Reader::new(&data, config);
336        // Should succeed reading within limit
337        reader.read_bytes(5).unwrap();
338        assert_eq!(reader.bytes_read(), 5);
339    }
340
341    #[test]
342    fn test_check_size_exact_error_paths() {
343        let config = config::standard();
344        // Test UnexpectedEndOfInput error path (lines 123-124)
345        let data = vec![1u8];
346        let mut reader = Reader::new(&data, config);
347        let err = reader.read_u16().unwrap_err();
348        if let JustcodeError::UnexpectedEndOfInput { expected, got } = err {
349            assert_eq!(expected, 2);
350            assert_eq!(got, 1);
351        } else {
352            panic!("Expected UnexpectedEndOfInput");
353        }
354
355        // Test SizeLimitExceeded error path (lines 133-134)
356        let config = config::standard().with_limit(3);
357        let data = vec![0u8; 10];
358        let mut reader = Reader::new(&data, config);
359        reader.read_bytes(2).unwrap(); // Read 2 bytes, position now at 2
360        let err = reader.read_bytes(2).unwrap_err(); // Try to read 2 more, would exceed limit of 3
361        if let JustcodeError::SizeLimitExceeded { limit, requested } = err {
362            assert_eq!(limit, 3);
363            assert_eq!(requested, 4);
364        } else {
365            panic!("Expected SizeLimitExceeded");
366        }
367    }
368}
369