Using an async function in a trait

I have tired to use an async function inside of an AsyncRead trait, but unfortunately, poll_read function isn't an async function.

impl AsyncRead for UdpStream {
    fn poll_read(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut [u8],
    ) -> Poll<io::Result<usize>> {
        let mut buf: Vec<u8> = Vec::new();
        let mut socket = (&self.inner).lock().unwrap(); // self.inner is tokio::net::udp::UdpSocket

        socket.recv_from(&mut buf).await.unwrap().0 // I know its type is mismatched.
    }
}
error[E0728]: `await` is only allowed inside `async` functions and blocks
  --> agent/src/udp_stream.rs:33:9
   |
25 | /     fn poll_read(
26 | |         self: Pin<&mut Self>,
27 | |         cx: &mut Context<'_>,
28 | |         buf: &mut [u8],
...  |
33 | |         socket.recv_from(&mut buf).await.unwrap().0
   | |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks
34 | |     }
   | |_____- this is not `async`

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b692ace19af226c3667b61a3dee33163

The AsyncRead trait effectively provides a future that does reading, and poll_read is this a specialised poll method. You probably want to call poll on the Future resulting from recv_from, passing in the given Context cx, instead of awaiting it.

1 Like

Something like this:

use ::std::{
    future::Future,
    pin::Pin,
    sync::{
        Arc,
        Mutex,
    },
    task::{
        Context,
        Poll,
    },
};

use ::tokio::{ // 0.2.0-alpha.6
    io::AsyncRead,
    net::UdpSocket,
};
use ::pin_utils::{ // 0.1.0-alpha.3
    pin_mut,
};

pub
struct UdpStream {
    inner: Arc<Mutex<UdpSocket>>,
}

impl AsyncRead for UdpStream {
    fn poll_read (
        self: Pin<&'_ mut Self>,
        cx: &'_ mut Context<'_>,
        buf: &'_ mut [u8],
    ) -> Poll<::std::io::Result<usize>>
    {
        let mut socket = (&self.inner).lock().unwrap(); // self.inner is tokio::net::udp::UdpSocket
        let future = socket.recv_from(buf);
        pin_mut!(future);
        future
            .poll(cx) // Poll<Result<(usize, SocketAddr)>>
            .map(|res| res.map(|(count, _address)| count))
    }
}

Although I am not sure that this behaves correctly when the input buf is not big enough.

2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.