smol-rs/async-channel

combine timeout as error with RecvError ?

keepsimple1 opened this issue · 1 comments

I'm not sure if can post this as an issue, but here it goes:

I'm trying to use Receiver::recv() together with a timeout, similar like this example.

However, as Receiver::recv() returns RecvError, not std::io::Error, things got complicated. I ended up to use anyhow::Error but it really feels clumsy. (see code below).

Does RecvError itself support converting from std::io::ErrorKind? or, is there a plan to support users to create RecvError for timeouts?

Here is my function complicated by error handling:

async fn chan_recv_with_timeout(chan: &Receiver<Vec<u8>>, timeout: Option<Duration>) -> anyhow::Result<Vec<u8>> {
    let chan_f = chan.recv();
    if let Some(duration) = timeout {
        let time_f = Timer::after(duration);
        futures::pin_mut!(chan_f);
        match future::select(chan_f, time_f).await {
            Either::Left((c, _)) => match c {
                Ok(t) => Ok(t),
                Err(r) => Err(anyhow::Error::new(r)),
            },
            Either::Right(_) => Err(anyhow::Error::new::<io::Error>(io::ErrorKind::TimedOut.into())),
        }
    } else {
        match chan_f.await {
            Ok(t) => Ok(t),
            Err(r) => Err(anyhow::Error::new(r)),
        }
    }
}

You could reuse my timeout() function and do:

timeout(duration, async { io::Result::Ok(chan.recv().await.ok()) }).await;

This way the result is io::Result<Option<Vec<u8>>, where Ok(None) means the channel is closed and empty.

Or, alternatively:

timeout(duration, async {
    match chan.recv().await {
        Ok(v) => v,
        Err(err) => io::Error::new(io::ErrorKind::Other, err),
    }
})
.await;

The return type is io::Result<Vec<u8>>, and Err(_) will represent both timeouts and channel being closed and empty.