From f828cf7365d91129bc843e7330abce8e31c21a6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Thu, 4 Sep 2025 11:15:01 +0200 Subject: [PATCH 1/3] feat: raise embedded-io-async's MSRV to 1.81 This is the same MSRV as embedded-io, which embedded-io-async depends on. --- embedded-io-async/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embedded-io-async/Cargo.toml b/embedded-io-async/Cargo.toml index 3b878a82..081567bc 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" From e72721f935b6d8fbe3c6859c42ff71f28625fc50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Thu, 4 Sep 2025 11:09:17 +0200 Subject: [PATCH 2/3] feat: implement `Read`, `BufRead`, and `Write` for `VecDeque` --- embedded-io-async/src/impls/mod.rs | 2 + embedded-io-async/src/impls/vec_deque.rs | 83 ++++++++++++++++++++++ embedded-io/src/impls/mod.rs | 2 + embedded-io/src/impls/vec_deque.rs | 90 ++++++++++++++++++++++++ 4 files changed, 177 insertions(+) create mode 100644 embedded-io-async/src/impls/vec_deque.rs create mode 100644 embedded-io/src/impls/vec_deque.rs diff --git a/embedded-io-async/src/impls/mod.rs b/embedded-io-async/src/impls/mod.rs index e79b9b8b..83c0f33a 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 00000000..c9bbec30 --- /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 e79b9b8b..83c0f33a 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 00000000..8af5a252 --- /dev/null +++ b/embedded-io/src/impls/vec_deque.rs @@ -0,0 +1,90 @@ +//! Adapted from std. + +use core::convert::Infallible; + +use alloc::collections::vec_deque::VecDeque; + +use crate::{BufRead, ErrorType, Read, ReadExactError, Write}; + +#[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(()) + } +} From ad6a7d184999b7094039035975c563f2dd9412a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Thu, 4 Sep 2025 12:17:57 +0200 Subject: [PATCH 3/3] feat: implement `ReadRead`, `WriteReady` for `VecDeque` --- embedded-io/src/impls/vec_deque.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/embedded-io/src/impls/vec_deque.rs b/embedded-io/src/impls/vec_deque.rs index 8af5a252..1e0d5b32 100644 --- a/embedded-io/src/impls/vec_deque.rs +++ b/embedded-io/src/impls/vec_deque.rs @@ -4,7 +4,7 @@ use core::convert::Infallible; use alloc::collections::vec_deque::VecDeque; -use crate::{BufRead, ErrorType, Read, ReadExactError, Write}; +use crate::{BufRead, ErrorType, Read, ReadExactError, ReadReady, Write, WriteReady}; #[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))] impl ErrorType for VecDeque { @@ -88,3 +88,19 @@ impl Write for VecDeque { 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) + } +}