How to async read into &mut [mem::MaybeUninit<u8>] with Tokio?

I have a reference to an uninitialized memory buffer in form of &mut [mem::MaybeUninit<u8>] and an AsyncRead implementation. I want to asynchronously read some data and write them to the buffer.
How to do that with Tokio?

async fn read_into(src: impl AsyncRead, dest: &mut [mem::MaybeUninit<u8>]) -> usize {
   /// how to asynchronously copy available data from `src` to `dest` and return the number of bytes copied?
}

I found the read_buf method in AsyncReadExt which looks like something I should probably use, however, that method does not accept my uninit buffer, but a BufMut implementation.

I have the following ideas:

  1. wrap my buffer into a custom struct and implement BufMut for it by hand.
  2. maybe Tokio or some other crate already provides such implementation? Looked at BufRead for a while, which can be initialized with my buffer, but it does not implement BufMut :frowning:

I don't have control over the creation of the uninitialized buffer, I get it from another crate, and I want to avoid additional copying (sure I could read into a temporary buffer and then copy, but this is a performance critical path). Therefore I don't think I can use bytes::BytesMut, because it looks like it maintains its own buffer and cannot wrap an existing one.

Thanks for help

This is easiest to do by calling poll_read. To do a single read, you can do this:

let mut read_buf = tokio::io::ReadBuf::uninit(dest);
poll_fn(|cx| src.poll_read(cx, &mut read_buf)).await?;

The number of bytes read will be available as read_buf.filled().len(), and the bytes themselves as read_buf.filled(). To read until the entire slice is filled, do this:

let len = dest.len();
let mut read_buf = tokio::io::ReadBuf::uninit(dest);
while read_buf.filled().len() < len {
    poll_fn(|cx| src.poll_read(cx, &mut read_buf)).await?;
}

This uses futures::future::poll_fn to do the reading.

Your idea with the wrapper struct that implements BufMut would also work.

2 Likes

Your idea with the wrapper struct that implements BufMut would also work.

Yeah, but why do this, when one can avoid it?
Big, big, thank you! I wasn't aware of poll_fn. Good that I asked.