aboutsummaryrefslogtreecommitdiff
path: root/src/common/sized_buffer.rs
diff options
context:
space:
mode:
authorevuez <julien@mulga.net>2022-11-26 15:38:06 -0500
committerevuez <julien@mulga.net>2024-04-03 22:44:12 +0200
commit86098797034cbc7eb6db0cee54e17f8dcaedbc5d (patch)
tree29b6225ead843eb9022296a54657bbadfa1c4da0 /src/common/sized_buffer.rs
downloadblom-main.tar.gz
Initial commitHEADmain
Diffstat (limited to 'src/common/sized_buffer.rs')
-rw-r--r--src/common/sized_buffer.rs113
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(())
+ }
+}