Passing ARC closure for Future poll_read

I want to pass a closure go be executed on the poll_read and poll_write of a struct:

use core::task::{Context, Poll};
use std::pin::Pin;
use hyper::client::connect::{Connection, Connected};
use tokio::io::{AsyncRead, AsyncWrite};
use std::sync::Arc;


pub type OnPollRead = Arc<dyn Fn(&mut Context<'_>, &mut tokio::io::ReadBuf<'_>) -> Poll<std::io::Result<()>> + Send + Sync>;
pub type OnPollWrite = Arc<dyn Fn(&mut Context<'_>, &[u8]) -> Poll<core::result::Result<usize, std::io::Error>> + Send + Sync>;


pub struct CustomResponse {
    on_poll_read: Option<OnPollRead>,
    on_poll_write: Option<OnPollWrite>,
}

impl AsyncRead for CustomResponse {
    fn poll_read(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut tokio::io::ReadBuf<'_>
    ) -> Poll<std::io::Result<()>> {
        (self.on_poll_read)(cx.waker().clone(), buf)
    }
}

impl AsyncWrite for CustomResponse {
    fn poll_write(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &[u8]
    ) -> Poll<Result<usize, std::io::Error>> {
        (self.on_poll_write)(cx.waker().clone(), buf)
    }
        fn poll_flush(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>
    ) -> Poll<Result<(), std::io::Error>> {
        Poll::Ready(Ok(()))
    }

    fn poll_shutdown(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>
    ) -> Poll<Result<(), std::io::Error>>
    {
        Poll::Ready(Ok(()))
    }
}

fn main() {
    let on_poll_read = Arc::new(|&mut Context, &mut tokio::io::ReadBuf| -> Poll<std::io::Result<()>> {
        Poll::Ready(Ok(()))
    });
    let on_poll_write = Arc::new(|&mut Context, &[u8]| -> Poll<core::result::Result<usize, std::io::Error>>{
        Poll::Ready(Ok(0))
    });
}

I get these errors:

error[E0532]: expected unit struct, unit variant or constant, found struct `tokio::io::ReadBuf`
  --> src/main.rs:47:53
   |
47 |     let on_poll_read = Arc::new(|&mut Context, &mut tokio::io::ReadBuf| -> Poll<std::io::Result<()>> {
   |                                                     ^^^^^^^^^^^^^^^^^^ help: use struct pattern syntax instead: `tokio::io::ReadBuf { buf, filled, initialized }`
   | 
  ::: /root/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.2.0/src/io/read_buf.rs:27:1
   |
27 | pub struct ReadBuf<'a> {
   | ---------------------- `tokio::io::ReadBuf` defined here

error[E0277]: the size for values of type `dyn for<'r, 's, 't0> Fn(&'r mut Context<'s>, &'t0 [u8]) -> Poll<std::result::Result<usize, std::io::Error>> + Send + Sync` cannot be known at compilation time
  --> src/main.rs:50:25
   |
50 |     let on_poll_write = Arc::new(|&mut Context, &[u8]| -> Poll<core::result::Result<usize, std::io::Error>>{
   |                         ^^^^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `Sized` is not implemented for `dyn for<'r, 's, 't0> Fn(&'r mut Context<'s>, &'t0 [u8]) -> Poll<std::result::Result<usize, std::io::Error>> + Send + Sync`
   = note: required by `Arc::<T>::new`

error[E0618]: expected function, found enum variant `(self.on_poll_read)`
  --> src/custom_transporter.rs:54:9
   |
54 |         (self.on_poll_read)(cx.waker().clone(), buf)
   |         ^^^^^^^^^^^^^^^^^^^-------------------------
   |         |
   |         call expression requires function
   |
help: `(self.on_poll_read)` is a unit variant, you need to write it without the parenthesis
   |
54 |         (self.on_poll_read)
   |

I tried help: (self.on_poll_read) is a unit variant, you need to write it without the parenthesis, but without the parenthesis, I get

error[E0599]: no method named `on_poll_write` found for struct `Pin<&mut CustomResponse>` in the current scope

which is even more strange.

Also, for expected unit struct, unit variant or constant, found structtokio::io::ReadBuf``, I have no idea of what's happening

Here's a playground with the errors: Rust Playground

You must name the parameters, even if you don't use them. For example:

|_cx: &mut Context<'_>, _buf: &mut tokio::io::ReadBuf<'_>|

You can probably even omit the type annotations entirely here.

Also, you call the functions with an owned waker (cx.waker().clone()), but this isn't necessary as the functions take a Context already. You can simply pass the context straight through (just cx).

Edit: Additionally you can't call an Option. You probably need to use an if let to check whether the function is Some before calling it.

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.