Joining fixed size arrays into a flattened slice?

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.

1 Like