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?


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>
        R: AsyncRead + Unpin,
        loop {
            let num_bytes_read =[self.len..]).await?;
            self.len += num_bytes_read;
            if self.len == 8 {
                self.len = 0;
                return Ok(u64::from_be_bytes(;

You can use it in the loop like this:

let mut reader = ...;
loop {
   tokio::select! {
       my_u64 = 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