Zero-copy using Bytes

I have a producer that pushes a bunch of bytes::Bytes (of variable sizes) onto a VecDeque. On the other end I want to take out, say, exactly 64K data (if available) at a time.

struct Queue {
  q: VecDeque<Bytes>
}
impl Queue {
  pub fn push(&mut self, buf: Bytes) { /* ... */ }

  /// Returns up to 64K data, if available.
  pub fn pull(&mut self) -> Option<Bytes> { /* ... */ }
}

Is it possible to take a bunch of Bytes buffers and merge them into a single Bytes, without copying the actual data? (I.e. chain the internal rope buffers).

I know I can simply return a Vec<Bytes>, but the end-goal is to use chunks_vectored() and then do a vectored write, so it would be convenient if all of this could be done in one pass.

You're not going to be able to vectorize reads/writes if you have discontiguous slices.

The Bytes type doesn't use ropes internally. It's essentially a smarter Arc<[u8]> where all the bytes are stored contiguously.

You'll probably want to make Queue::pull() return a custom wrapper that contains a Vec<Bytes> internally and give it a method to write to an impl std::io::Write using Write::write_vectored().

2 Likes

Interesting -- I don't know where I got the idea that it uses rope buffers internally, but I have believed it does for years.

I probably thought Bytes was akin to Apache's bucket brigades.

I'm genuinely confused by this -- I know that you know about IoSlice and write_vectored(), so I know I'm missing something here. Am I using "vectorized write" improperly?

Maybe they were thinking about how SIMD lets you vectorise operations, rather than write_vectored() and friends from std::io.

1 Like

I think you're right, a quick google of "vectorized write" seems to yield virtually exclusively SIMD related stuff.

I need to keep up. :slight_smile: