Description
Proposal
Add an as_slice
on IoSlice
to go from &IoSlice<'a>
to &'a [u8]
.
Add an into_slice
on IoSliceMut
to go from IoSliceMut<'a>
to &'a mut [u8]
.
Problem statement
Using vectored IO (eg. write_vectored
) is close to impossible to do correctly due to the difficulty of slicing/advancing IoSlice
Consider something like this:
fn test(mut out: impl Write) -> std::io::Result<()> {
let data1 = [1; 8];
let data2 = [15; 8];
let io_slice1 = IoSlice::new(&data1);
let io_slice2 = IoSlice::new(&data2);
out.write_vectored(&[io_slice1, io_slice2])?;
Ok(())
}
The issue here is that write_vectored
may only do a partial write of a slices. To ensure we write all data we need to advance the slices. Dealing with this is a little bit more annoying than ordinary writes, but we might try something like this:
fn test(mut out: impl Write) -> std::io::Result<()> {
let data1 = [1; 8];
let data2 = [15; 8];
let io_slice1 = IoSlice::new(&data1);
let io_slice2 = IoSlice::new(&data2);
let mut buf = [io_slice1, io_slice2];
let mut buf = &mut buf[..];
let mut written = 0;
while !buf.is_empty() {
if buf[0].len() < written {
written -= buf[0].len();
buf = &mut buf[1..];
} else {
buf[0] = IoSlice::new(&buf[0][written..]);
written = out.write_vectored(buf)?;
}
}
Ok(())
}
But this fails to compile! The problem is that in IoSlice::new(&buf[0][written..])
we try to slice the IoSlice
. This uses the Deref
trait implemented on the IoSlice
, but this ends up borrowing the IO slice. Thus we cannot modify buf
as we are also borrowing data stored in it. Instead, if we simply had an as_slice
as above, we could simply write that as IoSlice::new(&buf[0].as_slice()[written..])
instead.
There has been a few similar solutions to this problem, such as rust-lang/rust#62726 and rust-lang/rust#70436. These have sort of stalled, in part due to the resulting signatures ending up being sort of odd in cases where we want to advance a slice of IoSlice
s. I think the above proposal is simpler and more basic as it allows the user to construct functions like write_all_vectored
, advance
, or advance_slices
in ordinary safe Rust.
Motivation, use-cases
None found - I haven't actually been able to find any applications doing vectored IO in Rust. Only vectored IO I have found has been wrapping write_vectored
and the like: https://github.com/search?l=Rust&p=2&q=%22write_vectored%22&type=Code
Solution sketches
Already have it implemented here: https://github.com/rust-lang/rust/compare/master...mpdn:rust:master?expand=1