What to do when poll_read's buffer has no sufficient size for my buffer?

Rust's future uses poll_read (poll_read) to poll for available data:

fn poll_read(
    &mut self, 
    cx: &mut Context, 
    buf: &mut [u8]
) -> Result<Async<usize>, Error>

Obviously, when called, the poll_read function fills buf with data and returns Poll::Ready(n) where n is the quantity written to the buffer. If there's no data available at the moment, it returns Poll::Pending. The future caller can poll_read again, or not. In the case where it does not poll again, it is giving the poll_read function the chance to tell when it has to be polled. It does that by calling cx.waker().wake() when there is available data.

So, for example, I can implement poll_read for my struct:

fn poll_read(
    &mut self, 
    cx: &mut Context, 
    buf: &mut [u8]
) -> Result<Async<usize>, Error> {
    let my_buffer = get_buffer_from_internet();
    if my_buffer.len() <= buf.capacity() {
        buf.put_slice(my_buffer);
        return Poll::Ready(my_buffer.len());
    } else {
        //we can only fill buf partially
        buf.put_slice(my_buffer);
        //let's store the remaining in our struct
        self.remaining.store(&my_buffer[buf.len()..]);
        //How can I make the future caller know it needs to call poll_read again to read the remaining data? Can I call cx.waker().wake() while inside the poll_read?
        return Poll::Ready(buf.len());
    }
}

you see that in the case where there was no sufficient space on buf, I copied just the needed data and then stored the remaining on our struct. So we can enhance this poll_read by making it check if there is remaining data to be written, before getting new data from the internet. But as you see in my comment: How can I make the future caller know it needs to call poll_read again to read the remaining data? Can I call cx.waker().wake() while inside the poll_read?

First of all, you seem to be using futures 0.2. That is ancient and deprecated now - you should upgrade to futures 0.3's AsyncRead. Notably the signature is now:

fn poll_read(
    self: Pin<&mut Self>,
    cx: &mut Context<'_>,
    buf: &mut [u8],
) -> Poll<Result<usize, Error>>

Anyway, back to the question: when the AsyncRead implementation returns Poll::Ready(Ok(n)) where n > 0, the caller will call poll_read again if they wish to read more bytes, you can be sure of that. The caller will only stop calling poll_read when it returns Poll::Ready(Ok(0)). You only need to think about the Waker when returning Poll::Pending - in other cases you can completely ignore it.

1 Like