Description
I tried code similar to the following to advance an std::io::IoSlice
(playground link):
let mut buf = std::io::IoSlice::<'static>::new(b"foo");
let bytes: &[u8] = &buf;
let new_buf = std::io::IoSlice::new(&bytes[1..]);
buf = new_buf;
This does not compile, yielding the following error:
error[E0506]: cannot assign to `buf` because it is borrowed
--> src/lib.rs:7:5
|
5 | let bytes: &[u8] = &buf;
| ---- `buf` is borrowed here
6 | let new_buf = std::io::IoSlice::new(&bytes[1..]);
7 | buf = new_buf;
| ^^^^^^^^^^^^^
| |
| `buf` is assigned to here but it was already borrowed
| borrow later used here
The issue is that the Defer<Target = [u8]>
impl on IoSlice
discards the 'static
lifetime, replacing it with the lifetime of the of buf
.
However, we should be able to write such code using only safe Rust: all we are doing is effectively storing a subslice of the original buffer. For example, if we replace IoSlice
with normal slices &[u8]
it compiles:
let mut buf: &'static [u8] = b"foo";
let bytes: &[u8] = &buf;
let new_buf = &bytes[1..];
buf = new_buf;
To make IoSlice
more flexible there should be a method which returns a slice with the same lifetime of the underlying memory, something similar to the following:
impl<'a> IoSlice<'a> {
pub fn as_bytes(&self) -> &'a [u8] {
// ...
}
}
Note: this only applies to
IoSlice
, notIoSliteMut
since it would break aliasing.
Meta
rustc --version --verbose
:
rustc 1.78.0 (9b00956e5 2024-04-29)
binary: rustc
commit-hash: 9b00956e56009bab2aa15d7bff10916599e3d6d6
commit-date: 2024-04-29
host: x86_64-unknown-linux-gnu
release: 1.78.0
LLVM version: 18.1.2