Skip to main content

rustbac_core/encoding/
reader.rs

1use crate::DecodeError;
2
3/// A zero-copy reader that advances through a byte slice.
4///
5/// `Reader` borrows the input buffer and tracks the current position,
6/// returning sub-slices on reads so no allocation is needed.
7#[derive(Debug, Clone, Copy)]
8pub struct Reader<'a> {
9    buf: &'a [u8],
10    pos: usize,
11}
12
13impl<'a> Reader<'a> {
14    pub const fn new(buf: &'a [u8]) -> Self {
15        Self { buf, pos: 0 }
16    }
17
18    pub const fn position(&self) -> usize {
19        self.pos
20    }
21
22    pub fn remaining(&self) -> usize {
23        self.buf.len().saturating_sub(self.pos)
24    }
25
26    pub fn is_empty(&self) -> bool {
27        self.remaining() == 0
28    }
29
30    pub fn peek_u8(&self) -> Result<u8, DecodeError> {
31        self.buf
32            .get(self.pos)
33            .copied()
34            .ok_or(DecodeError::UnexpectedEof)
35    }
36
37    pub fn read_u8(&mut self) -> Result<u8, DecodeError> {
38        let byte = self.peek_u8()?;
39        self.pos += 1;
40        Ok(byte)
41    }
42
43    pub fn read_exact(&mut self, len: usize) -> Result<&'a [u8], DecodeError> {
44        if self.remaining() < len {
45            return Err(DecodeError::UnexpectedEof);
46        }
47        let start = self.pos;
48        self.pos += len;
49        Ok(&self.buf[start..start + len])
50    }
51
52    pub fn read_be_u16(&mut self) -> Result<u16, DecodeError> {
53        let bytes = self.read_exact(2)?;
54        Ok(u16::from_be_bytes([bytes[0], bytes[1]]))
55    }
56
57    pub fn read_be_u32(&mut self) -> Result<u32, DecodeError> {
58        let bytes = self.read_exact(4)?;
59        Ok(u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
60    }
61}
62
63#[cfg(test)]
64mod tests {
65    use super::Reader;
66    use crate::DecodeError;
67
68    #[test]
69    fn reader_reads_values() {
70        let mut r = Reader::new(&[1, 2, 3, 4, 5]);
71        assert_eq!(r.read_u8().unwrap(), 1);
72        assert_eq!(r.read_exact(2).unwrap(), &[2, 3]);
73        assert_eq!(r.remaining(), 2);
74    }
75
76    #[test]
77    fn reader_bounds() {
78        let mut r = Reader::new(&[1]);
79        assert_eq!(r.read_u8().unwrap(), 1);
80        assert_eq!(r.read_u8().unwrap_err(), DecodeError::UnexpectedEof);
81    }
82}