implement Write for uninitialized slices#674
implement Write for uninitialized slices#674master-hax wants to merge 6 commits intorust-embedded:masterfrom
Conversation
| return Err(SliceWriteError::Full); | ||
| } | ||
| let (a, b) = mem::take(self).split_at_mut(amt); | ||
| buf.split_at(amt) |
There was a problem hiding this comment.
maybe core::ptr::copy_nonoverlapping has a better chance at getting optimized than iterator loops. Or maybe copy_from_slice but i'm not sure if it's possible to use soundly.
There was a problem hiding this comment.
also buf.split_at(amt).0 can be written more readably as buf[..amt]
There was a problem hiding this comment.
maybe core::ptr::copy_nonoverlapping has a better chance at getting optimized
agreed, but that requires unsafe code. perhaps we could add that under a feature flag in a future PR?
buf.split_at(amt).0 can be written more readably as buf[..amt]
they behave differently though - .split_at() splits the lifetime and also works in const contexts, so i think it is preferred over slicing with []
There was a problem hiding this comment.
but that requires unsafe code
that's not a problem
they behave differently though - .split_at() splits the lifetime and also works in const contexts, so i think it is preferred over slicing with []
the lifetime is not an issue with readonly &[u8] because aliasing is allowed, and slicing is also allowed in const.
There was a problem hiding this comment.
from what i can tell, slicing is not allowed in const contexts.
this example main.rs using .split_at(n).0 compiles just fine:
const HELLO_WORLD_BYTES: &[u8] = b"hello world";
const HELLO_BYTES_SPLIT_AT: &[u8] = HELLO_WORLD_BYTES.split_at(4).0;
fn main() { panic!() }
================================
PS C:\Users\vivek\git\deletme> cargo rustc -- -Awarnings
Compiling deletme v0.1.0 (C:\Users\vivek\git\deletme)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.26s
whereas this example main.rs using [..n] fails to compile:
const HELLO_WORLD_BYTES: &[u8] = b"hello world";
const HELLO_BYTES_SLICE_OPERATOR: &[u8] = &HELLO_WORLD_BYTES[..4];
fn main() { panic!() }
================================
PS C:\Users\vivek\git\deletme> cargo rustc -- -Awarnings
Compiling deletme v0.1.0 (C:\Users\vivek\git\deletme)
error[E0015]: cannot call non-const operator in constants
--> src/main.rs:2:61
|
2 | const HELLO_BYTES_SLICE_OPERATOR: &[u8] = &HELLO_WORLD_BYTES[..4];
| ^^^^^
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
For more information about this error, try `rustc --explain E0015`.
error: could not compile `deletme` (bin "deletme") due to 1 previous error
so i think because it supports const contexts, "shrinks" the lifetime, and provides a more simple API, split_at() should be preferred. fwiw i actually like the readability after getting used to it. i had to deal with const issues earlier while working in another no_std crate mmstick/numtoa#23
There was a problem hiding this comment.
updated to replace safe iterator with unsafe core::ptr::copy_nonoverlapping in 00346c9
background
similar to how we implement the
Writetraits on&mut [u8], we can also add support for&mut [MaybeUninit<u8>]without usingunsafe. could be especially useful with core::io::BorrowedBuf.changes
ErrorType,embedded_io::Write, &embedded_io_async::Writefor&mut [MaybeUninit<u8>]&buf[..amt]withbuf.split_at(amt).0for consistency (and potential const-context compatibility)