diff options
author | evuez <julien@mulga.net> | 2022-11-26 15:38:06 -0500 |
---|---|---|
committer | evuez <julien@mulga.net> | 2024-04-03 22:44:12 +0200 |
commit | 86098797034cbc7eb6db0cee54e17f8dcaedbc5d (patch) | |
tree | 29b6225ead843eb9022296a54657bbadfa1c4da0 /src/common/sized_buffer.rs | |
download | blom-main.tar.gz |
Diffstat (limited to 'src/common/sized_buffer.rs')
-rw-r--r-- | src/common/sized_buffer.rs | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/src/common/sized_buffer.rs b/src/common/sized_buffer.rs new file mode 100644 index 0000000..ebfcab5 --- /dev/null +++ b/src/common/sized_buffer.rs @@ -0,0 +1,113 @@ +use memchr::memchr; +use std::io; +use std::io::Write; + +pub struct SizedBuffer<T> { + len: usize, + pos: usize, + pub inner: T, +} + +#[derive(Debug)] +pub enum Error { + IO(io::Error), + ReadPastEnd, + WrongByte { expected: u8, got: u8 }, +} + +impl<const N: usize> 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<u8, Error> { + 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<usize> { + 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<const N: usize> Write for SizedBuffer<[u8; N]> { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + let amt = (&mut self.inner[self.len..]).write(buf)?; + self.len += amt; + Ok(amt) + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} |