Could this be done by extending the Read
trait with a new method like this?
pub trait Read {
fn read(&mut self, buf: &mut [u8]) -> Result<usize>;
// Name subject to bikeshedding. Let's ignore that unimportant detail.
fn read_uninit<'a>(&mut self, buf: &'a mut [MaybeUninit<u8>]) -> Result<&'a mut [u8]> {
let ptr = MaybeUninit::first_ptr_mut(buf);
let init_buf;
unsafe {
core::ptr::write_bytes(ptr, 0u8, buf.len());
init_buf = MaybeUninit::slice_get_mut(buf);
}
let len = self.read(init_buf)?;
return Ok(&mut init_buf[0..len]);
}
}
The default implementation is suboptimal because it has to initialize the whole buffer, particularly since only a portion of the buffer may be filled. But implementations that explicitly implement read_uninit
could be optimal.
I know this is more or less what the Dropbox paper proposes and then discards. I'm not sure I fully understand Dropbox's concerns with the API. I think the read_uninit
method could also return Result<(&'a mut [u8], &' mut [MaybeUninit<u8>])>
, which is basically buf.split_at_mut(...)
.
As for the vectored API: I've never used vectored I/O APIs. I'm sure they're useful, but I don't think this should be abandoned just because the vectored API doesn't have an obvious solution. There are plenty of people like me that would benefit from a non-vectored API.