The primary use-case of write_vectored
is when you have multiple buffers that you want to write, and you don't want to copy the data into a single buffer. For example, if you are on a little-endian machine, you can actually use the memory of the Vec<Offset>
directly as the data to write, but you also want the four byte length to be written first.
Consider the following example that uses the zerocopy
crate to safely transmute a slice into the vector as a byte array. The example also uses conditional compilation to only use this strategy on little-endian machines.
use std::io;
use std::mem::size_of;
type Offset = u32;
struct Offsets(Vec<Offset>);
impl Offsets {
#[cfg(target_endian = "little")]
fn serialize(&self, mut output: impl io::Write) -> io::Result<()> {
let len = (self.0.len() as u32).to_le_bytes();
let offsets: &[u8] = zerocopy::AsBytes::as_bytes(self.0.as_slice());
let to_write = len.len() + offsets.len();
let mut written = 0;
while written < to_write {
if written < 4 {
let io_slices = [
io::IoSlice::new(&len[written..]),
io::IoSlice::new(offsets),
];
written += output.write_vectored(&io_slices)?;
} else {
written += output.write(&offsets[(written-4)..])?;
}
}
Ok(())
}
#[cfg(target_endian = "big")]
fn serialize(&self, mut output: impl io::Write) -> io::Result<()> {
let mut buffer = Vec::with_capacity(size_of::<u32>() + (size_of::<u32>() * self.0.len()));
// insert the count
buffer.extend_from_slice(&(self.0.len() as u32).to_le_bytes());
// insert the offsets
for offset in &self.0 {
buffer.extend_from_slice(&offset.to_le_bytes());
}
// dump
output.write_all(buffer.as_slice())
}
}
I believe that this is a decent example of where write_vectored
makes sense to use.
I also removed the mutable reference on the output
argument. It is not necessary, because mutable references to a Write
also implements Write
itself directly.