Storing async functions in a HashMap

Hi, I want to store multiple async functions with the same signature in a HashMap, but I don't understand why this doesn't work. Here is my attempt:

use std::collections::HashMap;
use futures::Future;
use futures::prelude::*;

type Request = String;
type Response = String;

async fn foo_handler(request: Request) -> Response {
	"success".to_string()
}

async fn bar_handler(request: Request) -> Response {
	"fail".to_string()
}

#[cfg(test)]
mod tests {
	use super::*;
	
	#[async_std::test]
	async fn test_handler() {
		let mut handlers: HashMap<&str, Box<fn(Request) -> dyn Future<Output = Response>>> = HashMap::new();
		//let mut handlers: HashMap<&str, Box<dyn Fn(Request) -> dyn Future<Output = Response>>> = HashMap::new();
		
		handlers.insert("foo", Box::new(foo_handler));
		handlers.insert("bar", Box::new(bar_handler));
	}
}
error[E0308]: mismatched types
  --> src/asynctest.rs:25:35
   |
25 |         handlers.insert("foo", Box::new(foo_handler));
   |                                         ^^^^^^^^^^^ expected trait core::future::future::Future, found opaque type
   |
   = note: expected type `fn(std::string::String) -> dyn core::future::future::Future<Output = std::string::String>`
              found type `fn(std::string::String) -> impl core::future::future::Future {asynctest::foo_handler}`

error[E0308]: mismatched types
  --> src/asynctest.rs:26:35
   |
26 |         handlers.insert("bar", Box::new(bar_handler));
   |                                         ^^^^^^^^^^^ expected trait core::future::future::Future, found opaque type
   |
   = note: expected type `fn(std::string::String) -> dyn core::future::future::Future<Output = std::string::String>`
              found type `fn(std::string::String) -> impl core::future::future::Future {asynctest::bar_handler}`

Any ideas?

well brother, maybe the answer to my post last night will also solve yours.

1 Like

Every async fn creates it's own unique type of future for the return value, so the signatures are actually different. You can use boxing to avoid this:

fn foo_handler(request: Request) -> Pin<Box<dyn Future<Output=Response>>> {
    Box::pin(async move {
        "success".to_string()
    })
}

You now want to use the type

HashMap<&str, Box<fn(Request) -> Pin<Box<dyn Future<Output = Response>>>>>
1 Like