diff --git a/embedded-io-async/Cargo.toml b/embedded-io-async/Cargo.toml index 3b878a825..081567bc1 100644 --- a/embedded-io-async/Cargo.toml +++ b/embedded-io-async/Cargo.toml @@ -2,7 +2,7 @@ name = "embedded-io-async" version = "0.6.1" edition = "2021" -rust-version = "1.75" +rust-version = "1.81" description = "Async embedded IO traits" repository = "https://github.com/rust-embedded/embedded-hal" readme = "README.md" diff --git a/embedded-io-async/src/impls/mod.rs b/embedded-io-async/src/impls/mod.rs index e79b9b8bf..83c0f33a0 100644 --- a/embedded-io-async/src/impls/mod.rs +++ b/embedded-io-async/src/impls/mod.rs @@ -5,3 +5,5 @@ mod slice_ref; mod boxx; #[cfg(feature = "alloc")] mod vec; +#[cfg(feature = "alloc")] +mod vec_deque; diff --git a/embedded-io-async/src/impls/vec_deque.rs b/embedded-io-async/src/impls/vec_deque.rs new file mode 100644 index 000000000..c9bbec302 --- /dev/null +++ b/embedded-io-async/src/impls/vec_deque.rs @@ -0,0 +1,83 @@ +//! Adapted from std. + +use alloc::collections::vec_deque::VecDeque; + +use crate::{BufRead, Read, ReadExactError, Write}; + +/// Read is implemented for `VecDeque` by consuming bytes from the front of the `VecDeque`. +#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] +impl Read for VecDeque { + /// Fill `buf` with the contents of the "front" slice as returned by + /// [`as_slices`][`VecDeque::as_slices`]. If the contained byte slices of the `VecDeque` are + /// discontiguous, multiple calls to `read` will be needed to read the entire content. + #[inline] + async fn read(&mut self, buf: &mut [u8]) -> Result { + let (ref mut front, _) = self.as_slices(); + let n = Read::read(front, buf).await?; + self.drain(..n); + Ok(n) + } + + #[inline] + async fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), ReadExactError> { + let (front, back) = self.as_slices(); + + // Use only the front buffer if it is big enough to fill `buf`, else use + // the back buffer too. + match buf.split_at_mut_checked(front.len()) { + None => buf.copy_from_slice(&front[..buf.len()]), + Some((buf_front, buf_back)) => match back.split_at_checked(buf_back.len()) { + Some((back, _)) => { + buf_front.copy_from_slice(front); + buf_back.copy_from_slice(back); + } + None => { + self.clear(); + return Err(ReadExactError::UnexpectedEof); + } + }, + } + + self.drain(..buf.len()); + Ok(()) + } +} + +/// BufRead is implemented for `VecDeque` by reading bytes from the front of the `VecDeque`. +#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] +impl BufRead for VecDeque { + /// Returns the contents of the "front" slice as returned by + /// [`as_slices`][`VecDeque::as_slices`]. If the contained byte slices of the `VecDeque` are + /// discontiguous, multiple calls to `fill_buf` will be needed to read the entire content. + #[inline] + async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { + let (front, _) = self.as_slices(); + Ok(front) + } + + #[inline] + fn consume(&mut self, amt: usize) { + self.drain(..amt); + } +} + +/// Write is implemented for `VecDeque` by appending to the `VecDeque`, growing it as needed. +#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] +impl Write for VecDeque { + #[inline] + async fn write(&mut self, buf: &[u8]) -> Result { + self.extend(buf); + Ok(buf.len()) + } + + #[inline] + async fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> { + self.extend(buf); + Ok(()) + } + + #[inline] + async fn flush(&mut self) -> Result<(), Self::Error> { + Ok(()) + } +} diff --git a/embedded-io/src/impls/mod.rs b/embedded-io/src/impls/mod.rs index e79b9b8bf..83c0f33a0 100644 --- a/embedded-io/src/impls/mod.rs +++ b/embedded-io/src/impls/mod.rs @@ -5,3 +5,5 @@ mod slice_ref; mod boxx; #[cfg(feature = "alloc")] mod vec; +#[cfg(feature = "alloc")] +mod vec_deque; diff --git a/embedded-io/src/impls/vec_deque.rs b/embedded-io/src/impls/vec_deque.rs new file mode 100644 index 000000000..1e0d5b323 --- /dev/null +++ b/embedded-io/src/impls/vec_deque.rs @@ -0,0 +1,106 @@ +//! Adapted from std. + +use core::convert::Infallible; + +use alloc::collections::vec_deque::VecDeque; + +use crate::{BufRead, ErrorType, Read, ReadExactError, ReadReady, Write, WriteReady}; + +#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] +impl ErrorType for VecDeque { + type Error = Infallible; +} + +/// Read is implemented for `VecDeque` by consuming bytes from the front of the `VecDeque`. +#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] +impl Read for VecDeque { + /// Fill `buf` with the contents of the "front" slice as returned by + /// [`as_slices`][`VecDeque::as_slices`]. If the contained byte slices of the `VecDeque` are + /// discontiguous, multiple calls to `read` will be needed to read the entire content. + #[inline] + fn read(&mut self, buf: &mut [u8]) -> Result { + let (ref mut front, _) = self.as_slices(); + let n = Read::read(front, buf)?; + self.drain(..n); + Ok(n) + } + + #[inline] + fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), ReadExactError> { + let (front, back) = self.as_slices(); + + // Use only the front buffer if it is big enough to fill `buf`, else use + // the back buffer too. + match buf.split_at_mut_checked(front.len()) { + None => buf.copy_from_slice(&front[..buf.len()]), + Some((buf_front, buf_back)) => match back.split_at_checked(buf_back.len()) { + Some((back, _)) => { + buf_front.copy_from_slice(front); + buf_back.copy_from_slice(back); + } + None => { + self.clear(); + return Err(ReadExactError::UnexpectedEof); + } + }, + } + + self.drain(..buf.len()); + Ok(()) + } +} + +/// BufRead is implemented for `VecDeque` by reading bytes from the front of the `VecDeque`. +#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] +impl BufRead for VecDeque { + /// Returns the contents of the "front" slice as returned by + /// [`as_slices`][`VecDeque::as_slices`]. If the contained byte slices of the `VecDeque` are + /// discontiguous, multiple calls to `fill_buf` will be needed to read the entire content. + #[inline] + fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { + let (front, _) = self.as_slices(); + Ok(front) + } + + #[inline] + fn consume(&mut self, amt: usize) { + self.drain(..amt); + } +} + +/// Write is implemented for `VecDeque` by appending to the `VecDeque`, growing it as needed. +#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] +impl Write for VecDeque { + #[inline] + fn write(&mut self, buf: &[u8]) -> Result { + self.extend(buf); + Ok(buf.len()) + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> { + self.extend(buf); + Ok(()) + } + + #[inline] + fn flush(&mut self) -> Result<(), Self::Error> { + Ok(()) + } +} + +#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] +impl ReadReady for VecDeque { + #[inline] + fn read_ready(&mut self) -> Result { + Ok(true) + } +} + +#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] +impl WriteReady for VecDeque { + #[inline] + fn write_ready(&mut self) -> Result { + Ok(true) + } +}