use memchr::memchr; use std::io; use std::io::Write; pub struct SizedBuffer { len: usize, pos: usize, pub inner: T, } #[derive(Debug)] pub enum Error { IO(io::Error), ReadPastEnd, WrongByte { expected: u8, got: u8 }, } impl SizedBuffer<[u8; N]> { pub fn new() -> Self { Self { len: 0, pos: 0, inner: [0; N], } } pub fn append(&mut self, bytes: &mut [u8]) -> Result<(), Error> { self.write_all(bytes).map_err(Error::IO) } pub fn peek(&self) -> u8 { self.inner[self.pos] } pub fn read(&mut self) -> Result { self.seek(1)?; Ok(self.inner[self.pos - 1]) } /* Reads n bytes from the buffer, and moves the cursor right after the last byte read. * * Example with n=3: * * pos = 2 * v * [0,1,2,3,4,5,6,7,8,9] * |-----|^ * read new pos */ pub fn read_count(&mut self, n: usize) -> Result<&[u8], Error> { self.seek(n)?; Ok(&self.inner[self.pos - n..self.pos]) } pub fn read_count_unchecked(&mut self, n: usize) -> &[u8] { self.seek_unchecked(n); &self.inner[self.pos - n..self.pos] } pub fn skip_byte(&mut self, byte: u8) -> Result<(), Error> { let x = self.read()?; if x != byte { return Err(Error::WrongByte { expected: byte, got: x, }); } Ok(()) } pub fn seek(&mut self, n: usize) -> Result<(), Error> { /* Allows to seek 1 past the end of the buffer. Subsequent reads will still fail but this * allows to read the last byte. Otherwise trying to read the last byte would fail after * reading it, when trying to advance the position of the cursor. */ if self.pos + n > self.len { return Err(Error::ReadPastEnd); } self.pos += n; Ok(()) } pub fn seek_unchecked(&mut self, n: usize) { self.pos += n; } pub fn find_offset(&mut self, x: u8) -> Option { memchr(x, &self.inner[self.pos..self.len]) } pub fn empty(&self) -> bool { self.len == self.pos } pub fn reset(&mut self) { self.len = 0; self.pos = 0; } } impl Write for SizedBuffer<[u8; N]> { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { let amt = (&mut self.inner[self.len..]).write(buf)?; self.len += amt; Ok(amt) } #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) } }