error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements

Compile Code:

// [[file:../20220725095717-short_url.org::*short-url][short-url:1]]
use std::collections::HashMap;
use std::convert::Infallible;
use std::net::SocketAddr;
use std::sync::Arc;
use std::future::Future;
use async_trait::async_trait;

use hyper::{Body, Request, Response, Server, Method, StatusCode};
use hyper::service::{make_service_fn, service_fn};

use sqlx::{Pool, Database, MySql};
use sqlx::mysql::MySqlPoolOptions;
use route_recognizer::{ Router, Params };

use once_cell::sync::Lazy;
use tokio::runtime::Runtime;

static TOKIO_RT: Lazy<Runtime> = Lazy::new(|| {
		tokio::runtime::Runtime::new().unwrap()
});

#[async_trait]
trait Handler: Sync + Send {
    async fn invoke(&self, req: Request<Body>, context: Context) -> Result<Response<Body>, Infallible>;
}

#[async_trait]
impl<F: Send + Sync, Fut> Handler for F
where
    F: Fn(Request<Body>, Context) -> Fut,
    Fut: Future<Output = Result<Response<Body>, Infallible>> + Send,
{
    async fn invoke(&self, req: Request<Body>, context: Context) -> Result<Response<Body>, Infallible> {
        (self)(req, context).await
    }
}

#[tokio::main]
async fn main() {
		let mut router: Router<Box<dyn Handler>> = Router::new();

		router.add("/", Box::new(home));

		let shared_router = Arc::new(router);


		// make service for each conn
		let make_svc = make_service_fn(move |_conn| {
				let captured_router = shared_router.clone();
				async move {
						Ok::<_, Infallible>(service_fn(move |req| {
								let m = captured_router.recognize(req.uri().path()).unwrap();
								let handler = m.handler();
								handler.invoke(req, Context{ session: None})
						}))
				}
		});

		
		let addr = SocketAddr::from(([127, 0, 0, 1], 8080));

		let server = Server::bind(&addr).serve(make_svc);

		println!("Listening on http://{}", addr);
		
		server.await;
}


struct Context {
		session: Option<HashMap<String, String>>,
}

async fn home(req: Request<Body>, ctx: Context) -> Result<Response<Body>, Infallible> {
		Ok(Response::new("short url home page".into()))
}
// short-url:1 ends here

got error:

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
   --> src/main.rs:53:33
    |
53  | ...                   let m = captured_router.recognize(req.uri().path()).unwrap();
    |                                               ^^^^^^^^^
    |
note: first, the lifetime cannot outlive the lifetime `'_` as defined here...
   --> src/main.rs:52:38
    |
52  |                         Ok::<_, Infallible>(service_fn(move |req| {
    |                                                        ^^^^^^^^^^
note: ...so that closure can access `captured_router`
   --> src/main.rs:53:17
    |
53  | ...                   let m = captured_router.recognize(req.uri().path()).unwrap();
    |                               ^^^^^^^^^^^^^^^
    = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `hyper::proto::h2::server::H2Stream<Pin<Box<dyn Future<Output = Result<Response<Body>, Infallible>> + Send>>, Body>` will meet its required lifetime bounds...
   --> src/main.rs:63:36
    |
63  |         let server = Server::bind(&addr).serve(make_svc);
    |                                          ^^^^^
note: ...that is required by this bound
   --> /Users/fuchengxu/.cargo/registry/src/mirrors.sjtug.sjtu.edu.cn-4f7dbcce21e258a2/hyper-0.14.20/src/server/server.rs:546:12
    |
546 |         E: ConnStreamExec<<S::Service as HttpService<Body>>::Future, B>,
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This error confuse me a lot.
What first, the lifetime refering to? captured_router?
'_ is the lifetime of closure move |req| ?
My understanding is that captured reference must outlive the closure, so closure can access it.

Server::bind(&addr).serve(make_svc); need service/closure to be static?
If so how to make the closure static?

Haven't dug into it much. Just in case someone wants to test the snippet:

OP doesn't provide the Cargo.toml, and I tried this:

[dependencies]
tokio = { version = "1.20.1", features = ["full"] }
async-trait = "0.1.57"
hyper = { version = "0.14.20", features = ["server", "tcp", "http2"] }
sqlx = { version = "0.6.1", features = ["runtime-tokio-rustls", "mysql"] }
once_cell = "1.13.0"
route-recognizer = "0.3.1"

And I got:

error: captured variable cannot escape `FnMut` closure body
  --> src/main.rs:64:37
   |
59 |         let captured_router = shared_router.clone();
   |             --------------- variable defined here
60 |         async move {
61 |             Ok::<_, Infallible>(service_fn(move |req| {
   |                                                     - inferred to be a `FnMut` closure
62 |                                     let m = captured_router.recognize(req.uri().path()).unwrap();
   |                                             --------------- variable captured here
63 |                                     let handler = m.handler();
64 |                                     handler.invoke(req, Context { session: None })
   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returns a reference to a captured variable which escapes the closure body
   |
   = note: `FnMut` closures only have access to their captured variables while they are executing...
   = note: ...therefore, they cannot allow references to captured variables to escape

which differs from the error given by OP.

Cargo.toml

[package]
name = "zettelkasten"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
futures = "0.3.21"
tokio = { version = "1", features = ["full"] }
mini-redis = "0.4"
bytes = "1"
tokio-stream = "0.1"
hyper = { version = "0.14", features = ["full"] }
sqlx = { version = "0.5", features = [ "runtime-tokio-rustls", "mysql" ] }
route-recognizer = "0.3"
once_cell = "1.13"
async-trait = "0.1"

I posted Cargo.toml.
I also tried your Cargo.toml, but I still get same error, not the one you raised.

I don't know why show different error in your env. And handler.invoke(req, Context{ session: None}) returns Future of Result<Response<Body>, Infallible>, there is no refer to captured_router.

My env:

fuchengxu@f018981d4b4f zettelkasten % cargo --version                          
cargo 1.60.0 (d1fd9fe2c 2022-03-01)
fuchengxu@f018981d4b4f zettelkasten % rustc --version                          
rustc 1.60.0 (7737e0b5c 2022-04-04)

I removed unnecessary code to make it simpler

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.