Tokio: share dyn Future between threads safely

How can I share (dyn Fn(String) -> Pin<Box<(dyn Future<Output = i32> + 'static)>> + 'static) between threads

I'm getting this error:

    |
37  |         tokio::spawn(async {
    |         ^^^^^^^^^^^^ `(dyn Fn(String) -> Pin<Box<(dyn Future<Output = i32> + 'static)>> + 'static)` cannot be sent between threads safely

code :

use tokio;
use tokio::sync::Mutex;
use std::sync::Arc;
use std::collections::HashMap;
use std::future::Future;
use std::pin::Pin;

type CalcFn = Box<dyn Fn(String) -> Pin<Box<dyn Future<Output = i32>>>>;
type Route = Arc<Mutex<HashMap<String, CalcFn>>>;

#[tokio::main]
async fn main() {
    let async_func = |s: String| {
        async move {
            s.parse().unwrap()
        }
    };
    let mut routes: Route = Arc::new(Mutex::new(HashMap::new()));
    
    // insert values in map
    {
        let routes = Arc::clone(&routes);
        let _path = "/";
                
        routes.lock().await
            // insert method
            .entry(format!("GET_{}", _path))
            .or_insert(Box::new(move |x: String| Box::pin(async_func(x))));
    }
    
    loop {
        let routes = routes.clone();
        tokio::spawn(async {
            for (key, value) in routes.lock().await.iter() {
                value("10".to_string()).await;
            }
        });   
    }
    
}

example on play.rust-lang.org

use this, compiles correctly,


type CalcFn = Box<dyn Fn(String) -> Pin<Box<dyn Future<Output = i32>  + Send + 'static >> + Send + Sync + 'static >;

also need change :

tokio::spawn(async {
            for (key, value) in routes.lock().await.iter() {
                value("10".to_string()).await;
            }
        });   

to

tokio::spawn(async move {
            for (_key, value) in routes.lock().await.iter() {
                value("10".to_string()).await;
            }
        });   

2 Likes

I usually recommend using the BoxFuture alias from the futures crate because it takes care of all of the + Send and Pin stuff for you.

1 Like