From 74c4e55238c3d4f91c781c9d723b1ba5274eab44 Mon Sep 17 00:00:00 2001 From: Dane Slattery Date: Fri, 30 Aug 2024 11:55:42 +0200 Subject: [PATCH 1/2] Add BufReader impl --- embedded-io/src/lib.rs | 143 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) diff --git a/embedded-io/src/lib.rs b/embedded-io/src/lib.rs index 9f95e636a..59679ab5a 100644 --- a/embedded-io/src/lib.rs +++ b/embedded-io/src/lib.rs @@ -339,6 +339,107 @@ pub trait Read: ErrorType { } } +/// The [BufReader] adds buffering to any reader, analogous to [`std::io::BufReader`] +/// +/// This [BufReader] allocates it's own internal buffer of size [N]. +/// +/// # Examples +/// +/// ``` +/// use embedded_io::BufReader; +/// +/// fn main()-> Result<(),> +/// { +/// let reader = [0,1,2,3]; +/// let mut buf_reader: BufReader<4,&[u8]> = BufReader::new(&reader); +/// +/// let current_buff = buf_reader.fill_buff()?; +/// +/// buf_reader.consume(4); +/// +/// } +/// +/// ``` +pub struct BufReader { + buff: [u8; N], + pos: usize, + inner: R, +} + +impl BufReader { + /// Gets a reference to the underlying reader. + pub fn get_ref(&self) -> &R { + &self.inner + } + + pub fn get_mut(&mut self) -> &mut R { + &mut self.inner + } + + pub fn buffer(&self) -> &[u8] { + &self.buff + } + + pub fn capacity(&self) -> usize { + N + } + + pub fn into_inner(self) -> R + where + R: Sized, + { + self.inner + } + + pub fn discard_buffer(&mut self) { + self.pos = 0; + } +} + +impl BufReader { + /// Creates a new [BufReader] with a buffer capacity of `N`. + pub fn new(reader: R) -> Self { + Self { + buff: [0u8; N], + pos: 0, + inner: reader, + } + } +} + +impl ErrorType for BufReader { + type Error = R::Error; +} + +impl BufRead for BufReader { + fn consume(&mut self, amt: usize) { + // remove amt bytes from the front of the buffer + // imagine the buffer is [0,1,2,3,4] + // consume(2) + // the buffer is now [2,3,4] + self.buff.copy_within(amt..self.pos, 0); + self.pos -= amt; + } + + fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { + // fill the inner buffer + let read_count = self.inner.read(&mut self.buff[self.pos..])?; + self.pos += read_count; + + Ok(&self.buff[..self.pos]) + } +} + +impl Read for BufReader { + fn read(&mut self, buf: &mut [u8]) -> Result { + let mut rem = self.fill_buf()?; + let nread = rem.read(buf).unwrap(); // infallible + + self.consume(nread); + Ok(nread) + } +} + /// Blocking buffered reader. /// /// This trait is the `embedded-io` equivalent of [`std::io::BufRead`]. @@ -551,3 +652,45 @@ impl WriteReady for &mut T { T::write_ready(self) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn bufread_consume_removes_bytes() { + let reader = [0, 1, 2, 3]; + + let mut buf_read: BufReader<4, &[u8]> = BufReader::new(&reader); + + // read bytes + let current_buff = buf_read.fill_buf().unwrap(); + + assert_eq!(current_buff, [0, 1, 2, 3]); + + // consume bytes + buf_read.consume(2); + + assert_eq!(buf_read.fill_buf().unwrap(), [2, 3]); + } + + #[test] + #[should_panic] + fn bufread_panics_if_consume_more_than_n_bytes() { + let reader = [0, 1, 2, 3]; + + let mut buf_read: BufReader<4, &[u8]> = BufReader::new(&reader); + + buf_read.consume(5); + } + + #[test] + #[should_panic] + fn bufread_panics_if_consume_more_bytes_than_filled() { + let reader = [0, 1, 2, 3]; + + let mut buf_read: BufReader<4, &[u8]> = BufReader::new(&reader); + + buf_read.consume(4); + } +} From f2349699f498c0fa54ae57bd08e26bfd8deb97c3 Mon Sep 17 00:00:00 2001 From: Dane Slattery Date: Fri, 30 Aug 2024 12:17:40 +0200 Subject: [PATCH 2/2] Appease clippy --- embedded-io/src/lib.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/embedded-io/src/lib.rs b/embedded-io/src/lib.rs index 59679ab5a..937c088eb 100644 --- a/embedded-io/src/lib.rs +++ b/embedded-io/src/lib.rs @@ -372,28 +372,30 @@ impl BufReader { &self.inner } + /// Gets a mutable reference to the underlying reader. pub fn get_mut(&mut self) -> &mut R { &mut self.inner } + /// Returns a reference to the internally buffered data. + /// + /// Unlike `fill_buff` this will not attempt to fill the buffer it if is empty. pub fn buffer(&self) -> &[u8] { &self.buff } + /// Returns the number of bytes the internal buffer can hold at once. pub fn capacity(&self) -> usize { N } + /// Unwraps this [BufReader], returning the underlying reader. pub fn into_inner(self) -> R where R: Sized, { self.inner } - - pub fn discard_buffer(&mut self) { - self.pos = 0; - } } impl BufReader {