From fdec431fa75edc3d117c6088fed0f11e66f27197 Mon Sep 17 00:00:00 2001 From: Vivek Revankar Date: Tue, 5 Aug 2025 20:06:06 -0700 Subject: [PATCH 1/6] support writing to uninit slices --- embedded-io-async/src/impls/slice_mut.rs | 27 ++++++++++++- embedded-io/src/impls/slice_mut.rs | 50 +++++++++++++++++++++--- 2 files changed, 71 insertions(+), 6 deletions(-) diff --git a/embedded-io-async/src/impls/slice_mut.rs b/embedded-io-async/src/impls/slice_mut.rs index bd64d1320..5ff041b12 100644 --- a/embedded-io-async/src/impls/slice_mut.rs +++ b/embedded-io-async/src/impls/slice_mut.rs @@ -1,4 +1,4 @@ -use core::mem; +use core::mem::{self, MaybeUninit}; use embedded_io::SliceWriteError; use crate::Write; @@ -25,3 +25,28 @@ impl Write for &mut [u8] { Ok(amt) } } + +/// Write is implemented for `&mut [u8]` by copying into the slice, overwriting +/// its data. +/// +/// Note that writing updates the slice to point to the yet unwritten part. +/// The slice will be empty when it has been completely overwritten. +/// +/// If the number of bytes to be written exceeds the size of the slice, write operations will +/// return short writes: ultimately, `Ok(0)`; in this situation, `write_all` returns an error of +/// kind `ErrorKind::WriteZero`. +impl Write for &mut [MaybeUninit] { + #[inline] + async fn write(&mut self, buf: &[u8]) -> Result { + let amt = core::cmp::min(buf.len(), self.len()); + if !buf.is_empty() && amt == 0 { + return Err(SliceWriteError::Full); + } + let (a, b) = mem::take(self).split_at_mut(amt); + buf.split_at(amt).0.iter().enumerate().for_each(|(index,byte)| { + a[index].write(*byte); + }); + *self = b; + Ok(amt) + } +} diff --git a/embedded-io/src/impls/slice_mut.rs b/embedded-io/src/impls/slice_mut.rs index cee991ea6..0adf945a9 100644 --- a/embedded-io/src/impls/slice_mut.rs +++ b/embedded-io/src/impls/slice_mut.rs @@ -1,5 +1,5 @@ use crate::{Error, ErrorKind, ErrorType, SliceWriteError, Write, WriteReady}; -use core::mem; +use core::mem::{self, MaybeUninit}; impl Error for SliceWriteError { fn kind(&self) -> ErrorKind { @@ -9,10 +9,6 @@ impl Error for SliceWriteError { } } -impl ErrorType for &mut [u8] { - type Error = SliceWriteError; -} - impl core::fmt::Display for SliceWriteError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "{self:?}") @@ -21,6 +17,10 @@ impl core::fmt::Display for SliceWriteError { impl core::error::Error for SliceWriteError {} +impl ErrorType for &mut [u8] { + type Error = SliceWriteError; +} + /// Write is implemented for `&mut [u8]` by copying into the slice, overwriting /// its data. /// @@ -54,3 +54,43 @@ impl WriteReady for &mut [u8] { Ok(true) } } + +impl ErrorType for &mut [MaybeUninit] { + type Error = SliceWriteError; +} + +/// Write is implemented for `&mut [MaybeUninit]` by copying into the slice, overwriting +/// its data. +/// +/// Note that writing updates the slice to point to the yet unwritten part. +/// The slice will be empty when it has been completely overwritten. +/// +/// If the number of bytes to be written exceeds the size of the slice, write operations will +/// return short writes: ultimately, a `SliceWriteError::Full`. +impl Write for &mut [MaybeUninit] { + #[inline] + fn write(&mut self, buf: &[u8]) -> Result { + let amt = core::cmp::min(buf.len(), self.len()); + if !buf.is_empty() && amt == 0 { + return Err(SliceWriteError::Full); + } + let (a, b) = mem::take(self).split_at_mut(amt); + buf.split_at(amt).0.iter().enumerate().for_each(|(index,byte)| { + a[index].write(*byte); + }); + *self = b; + Ok(amt) + } + + #[inline] + fn flush(&mut self) -> Result<(), Self::Error> { + Ok(()) + } +} + +impl WriteReady for &mut [MaybeUninit] { + #[inline] + fn write_ready(&mut self) -> Result { + Ok(true) + } +} From 3478e99e8fa35b5fcb4fbfe7a6b81fd520dbc683 Mon Sep 17 00:00:00 2001 From: Vivek Revankar Date: Tue, 5 Aug 2025 20:19:21 -0700 Subject: [PATCH 2/6] use split_at consistently --- embedded-io-async/src/impls/slice_mut.rs | 2 +- embedded-io/src/impls/slice_mut.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/embedded-io-async/src/impls/slice_mut.rs b/embedded-io-async/src/impls/slice_mut.rs index 5ff041b12..2c12a3af7 100644 --- a/embedded-io-async/src/impls/slice_mut.rs +++ b/embedded-io-async/src/impls/slice_mut.rs @@ -20,7 +20,7 @@ impl Write for &mut [u8] { return Err(SliceWriteError::Full); } let (a, b) = mem::take(self).split_at_mut(amt); - a.copy_from_slice(&buf[..amt]); + a.copy_from_slice(buf.split_at(amt).0); *self = b; Ok(amt) } diff --git a/embedded-io/src/impls/slice_mut.rs b/embedded-io/src/impls/slice_mut.rs index 0adf945a9..536870180 100644 --- a/embedded-io/src/impls/slice_mut.rs +++ b/embedded-io/src/impls/slice_mut.rs @@ -37,7 +37,7 @@ impl Write for &mut [u8] { return Err(SliceWriteError::Full); } let (a, b) = mem::take(self).split_at_mut(amt); - a.copy_from_slice(&buf[..amt]); + a.copy_from_slice(buf.split_at(amt).0); *self = b; Ok(amt) } From e5d2e2de6d9b79cf2d3644cdaee9f7d996026522 Mon Sep 17 00:00:00 2001 From: Vivek Revankar Date: Tue, 5 Aug 2025 20:26:30 -0700 Subject: [PATCH 3/6] update documentation --- embedded-io-async/src/impls/slice_mut.rs | 2 +- embedded-io/src/impls/slice_mut.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/embedded-io-async/src/impls/slice_mut.rs b/embedded-io-async/src/impls/slice_mut.rs index 2c12a3af7..77b673c3a 100644 --- a/embedded-io-async/src/impls/slice_mut.rs +++ b/embedded-io-async/src/impls/slice_mut.rs @@ -26,7 +26,7 @@ impl Write for &mut [u8] { } } -/// Write is implemented for `&mut [u8]` by copying into the slice, overwriting +/// Write is implemented for `&mut [MaybeUninit]` by copying into the slice, initializing & overwriting /// its data. /// /// Note that writing updates the slice to point to the yet unwritten part. diff --git a/embedded-io/src/impls/slice_mut.rs b/embedded-io/src/impls/slice_mut.rs index 536870180..bd0e40331 100644 --- a/embedded-io/src/impls/slice_mut.rs +++ b/embedded-io/src/impls/slice_mut.rs @@ -59,7 +59,7 @@ impl ErrorType for &mut [MaybeUninit] { type Error = SliceWriteError; } -/// Write is implemented for `&mut [MaybeUninit]` by copying into the slice, overwriting +/// Write is implemented for `&mut [MaybeUninit]` by copying into the slice, initializing & overwriting /// its data. /// /// Note that writing updates the slice to point to the yet unwritten part. From ef7758baf485fe0ebcbdb264666dab9b4c612268 Mon Sep 17 00:00:00 2001 From: Vivek Revankar Date: Tue, 5 Aug 2025 20:28:52 -0700 Subject: [PATCH 4/6] doc nit --- embedded-io-async/src/impls/slice_mut.rs | 4 ++-- embedded-io/src/impls/slice_mut.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/embedded-io-async/src/impls/slice_mut.rs b/embedded-io-async/src/impls/slice_mut.rs index 77b673c3a..b2b97e33a 100644 --- a/embedded-io-async/src/impls/slice_mut.rs +++ b/embedded-io-async/src/impls/slice_mut.rs @@ -26,8 +26,8 @@ impl Write for &mut [u8] { } } -/// Write is implemented for `&mut [MaybeUninit]` by copying into the slice, initializing & overwriting -/// its data. +/// Write is implemented for `&mut [MaybeUninit]` by copying into the slice, initializing +/// & overwriting its data. /// /// Note that writing updates the slice to point to the yet unwritten part. /// The slice will be empty when it has been completely overwritten. diff --git a/embedded-io/src/impls/slice_mut.rs b/embedded-io/src/impls/slice_mut.rs index bd0e40331..ef8b1b796 100644 --- a/embedded-io/src/impls/slice_mut.rs +++ b/embedded-io/src/impls/slice_mut.rs @@ -59,8 +59,8 @@ impl ErrorType for &mut [MaybeUninit] { type Error = SliceWriteError; } -/// Write is implemented for `&mut [MaybeUninit]` by copying into the slice, initializing & overwriting -/// its data. +/// Write is implemented for `&mut [MaybeUninit]` by copying into the slice, initializing +/// & overwriting its data. /// /// Note that writing updates the slice to point to the yet unwritten part. /// The slice will be empty when it has been completely overwritten. From dd98ad62a165b905e7ef9aa8b468b01cd39a21e7 Mon Sep 17 00:00:00 2001 From: Vivek Revankar Date: Tue, 5 Aug 2025 20:32:52 -0700 Subject: [PATCH 5/6] cargo fmt --- embedded-io-async/src/impls/slice_mut.rs | 10 +++++++--- embedded-io/src/impls/slice_mut.rs | 10 +++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/embedded-io-async/src/impls/slice_mut.rs b/embedded-io-async/src/impls/slice_mut.rs index b2b97e33a..ff75f276d 100644 --- a/embedded-io-async/src/impls/slice_mut.rs +++ b/embedded-io-async/src/impls/slice_mut.rs @@ -43,9 +43,13 @@ impl Write for &mut [MaybeUninit] { return Err(SliceWriteError::Full); } let (a, b) = mem::take(self).split_at_mut(amt); - buf.split_at(amt).0.iter().enumerate().for_each(|(index,byte)| { - a[index].write(*byte); - }); + buf.split_at(amt) + .0 + .iter() + .enumerate() + .for_each(|(index, byte)| { + a[index].write(*byte); + }); *self = b; Ok(amt) } diff --git a/embedded-io/src/impls/slice_mut.rs b/embedded-io/src/impls/slice_mut.rs index ef8b1b796..1da675e2f 100644 --- a/embedded-io/src/impls/slice_mut.rs +++ b/embedded-io/src/impls/slice_mut.rs @@ -75,9 +75,13 @@ impl Write for &mut [MaybeUninit] { return Err(SliceWriteError::Full); } let (a, b) = mem::take(self).split_at_mut(amt); - buf.split_at(amt).0.iter().enumerate().for_each(|(index,byte)| { - a[index].write(*byte); - }); + buf.split_at(amt) + .0 + .iter() + .enumerate() + .for_each(|(index, byte)| { + a[index].write(*byte); + }); *self = b; Ok(amt) } From 00346c979fcd898a0a74ddb4954a464f74c8f522 Mon Sep 17 00:00:00 2001 From: Vivek Revankar Date: Wed, 6 Aug 2025 16:58:22 -0700 Subject: [PATCH 6/6] use core::ptr::copy_nonoverlapping as suggested --- embedded-io-async/src/impls/slice_mut.rs | 10 +++------- embedded-io/src/impls/slice_mut.rs | 10 +++------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/embedded-io-async/src/impls/slice_mut.rs b/embedded-io-async/src/impls/slice_mut.rs index ff75f276d..57ff41fcd 100644 --- a/embedded-io-async/src/impls/slice_mut.rs +++ b/embedded-io-async/src/impls/slice_mut.rs @@ -43,13 +43,9 @@ impl Write for &mut [MaybeUninit] { return Err(SliceWriteError::Full); } let (a, b) = mem::take(self).split_at_mut(amt); - buf.split_at(amt) - .0 - .iter() - .enumerate() - .for_each(|(index, byte)| { - a[index].write(*byte); - }); + unsafe { + core::ptr::copy_nonoverlapping(buf.as_ptr(), a.as_mut_ptr() as *mut u8, amt); + } *self = b; Ok(amt) } diff --git a/embedded-io/src/impls/slice_mut.rs b/embedded-io/src/impls/slice_mut.rs index 1da675e2f..8d27c9b76 100644 --- a/embedded-io/src/impls/slice_mut.rs +++ b/embedded-io/src/impls/slice_mut.rs @@ -75,13 +75,9 @@ impl Write for &mut [MaybeUninit] { return Err(SliceWriteError::Full); } let (a, b) = mem::take(self).split_at_mut(amt); - buf.split_at(amt) - .0 - .iter() - .enumerate() - .for_each(|(index, byte)| { - a[index].write(*byte); - }); + unsafe { + core::ptr::copy_nonoverlapping(buf.as_ptr(), a.as_mut_ptr() as *mut u8, amt); + } *self = b; Ok(amt) }