AsyncReadExt cancel safe?

I intended to use a function like read_u64 in my tokio select, but I'm uncertain if it is actually cancel safe.

It's not cancel safe.

Any idea on an alternative to solve this issue?

It depends on the situation in which the select! is used. Do you need to do this in a loop?

Yea

You can use the following utility:

use tokio::io::{AsyncRead, AsyncReadExt};

struct U64Reader {
    data: [u8; 8],
    len: usize,
}

impl U64Reader {
    async fn next<R>(&mut self, io: &mut R) -> std::io::Result<u64>
    where
        R: AsyncRead + Unpin,
    {
        loop {
            let num_bytes_read = io.read(&mut self.data[self.len..]).await?;
            self.len += num_bytes_read;
            if self.len == 8 {
                self.len = 0;
                return Ok(u64::from_be_bytes(self.data));
            }
        }
    }
}

You can use it in the loop like this:

let mut reader = ...;
loop {
   tokio::select! {
       my_u64 = reader.next(&mut io_resource) => { ... },
       ...
    }
}

This works because even if next gets cancelled during the .await, it will have remembered the number of bytes that have been read into the data field, so in the next tokio::select! iteration, it will keep going from where it got to.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.