Arc<Mutex<T>> inside closure: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`

I'm trying to share an Arc<Mutex<T>> with a closure. I get the error that closure is FnOncebecause it moves the variableshared_wake_deque_ out of its environment:

use core::task::{Context, Poll, Waker};
use hyper::client::connect::{Connection, Connected};
use std::sync::{Arc, Mutex};
use std::collections::VecDeque;

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>;

#[derive(Clone)]
pub struct CustomTransporter {
    on_poll_read: Option<OnPollRead>,
    on_poll_write: Option<OnPollWrite>,
}

pub struct OVPNClient {
}

impl OVPNClient {
    pub fn send(&self, buffer: &[u8]) {
        
    }
}

unsafe impl Send for OVPNClient {}


unsafe impl Send for CustomTransporter {}

impl CustomTransporter {
    pub fn new(on_poll_read: Option<OnPollRead>, on_poll_write: Option<OnPollWrite>) -> CustomTransporter {
        CustomTransporter{
            on_poll_read: on_poll_read,
            on_poll_write: on_poll_write
        }
    }
}

fn main () {
    let openvpn_client = Arc::new(Mutex::new(OVPNClient{}));

    let shared_wake_deque = Arc::new(Mutex::new(VecDeque::<Waker>::new()));
    
    let shared_wake_deque_ = shared_wake_deque.clone();
    let on_poll_read = Arc::new(|context: &mut Context, buffer: &mut tokio::io::ReadBuf| -> Poll<std::io::Result<()>> {
        let shared_wake_deque__ = shared_wake_deque_;
        Poll::Ready(Ok(()))
    });

    let on_poll_write = Arc::new(|context: &mut Context, buffer: &[u8]| -> Poll<core::result::Result<usize, std::io::Error>>{
        openvpn_client.lock().unwrap().send(buffer);
        Poll::Ready(Ok(0))
    });

    let connector = CustomTransporter::new(Some(on_poll_read), Some(on_poll_write));
}

Error:

error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
  --> src/main.rs:44:33
   |
44 |     let on_poll_read = Arc::new(|context: &mut Context, buffer: &mut tokio::io::ReadBuf| -> Poll<std::io::Result<()>> {
   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this closure implements `FnOnce`, not `Fn`
45 |         let shared_wake_deque__ = shared_wake_deque_;
   |                                   ------------------ closure is `FnOnce` because it moves the variable `shared_wake_deque_` out of its environment
...
54 |     let connector = CustomTransporter::new(Some(on_poll_read), Some(on_poll_write));
   |                                                 ------------ the requirement to implement `Fn` derives from here

I get that moving can only occur one time. I didn't even made the closure move. As you see, I'm trying to use a clone of the Arc<Mutex<T>> so I'm not exactly moving it. You can see that I tried cloning so I move a variable that is used just on this closure and never anymore, but it didn't work.

You can move the Arc into the closure, and then clone it again inside the closure if you need a new Arc each time the closure is called:

    let on_poll_read = Arc::new(move |context: &mut Context, buffer: &mut tokio::io::ReadBuf| -> Poll<std::io::Result<()>> {
        let shared_wake_deque__ = shared_wake_deque_.clone();
        Poll::Ready(Ok(()))
    });

Playground

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.