-1

I’m building a small HTTP library with both sync and async runtimes (Tokio,async-std or smol).

I'm using Rust edition 2024, and for this crate I' trying to keep dependencies as few and as stable/basic as possible.

I want users to register handlers by passing plain functions—sync or async—without wrappers:

  • Sync: fn(&Request) -> Response
  • Async: async fn(&Request) -> Response

Call site I want to keep:

server.add_route("/", Rt::GET, demo_get); // no wrappers

Minimal example

// main.rs (Tokio)
#[tokio::main]
async fn main() {
  let mut server = Server::new("127.0.0.1:7878", None).await.unwrap();
  server.add_route("/", Rt::GET, demo_get); // ← keep this as-is
  server.run().await;
}

async fn demo_get(_req: &Request) -> Response {
  tokio::time::sleep(std::time::Duration::from_millis(100)).await;
  Response { status: "200 OK".into(), content_type: "".into(), content: b"OK".to_vec() }
}

What I tried (many variants, none fully solved it)

A) async-trait + Arc<dyn Handler>: mixed sync/async modes got complicated (lifetimes, for<'a>, cfg).

B) for<'a> + boxed future closure type: for<'a> Fn(&'a Request) -> Pin<Box<dyn Future<Output = Response> + Send + 'a>> Still hit “expected impl for<'a> Future, found impl Future” (opaque impl Trait mismatch).

C) Wrapper at call site (works but I want to avoid it): server.add_route("/", Rt::GET, |r| Box::pin(demo_get(r)));

D) futures::future::BoxFuture<'a, Response> as the handler return type: Store Arc<dyn for<'a> Fn(&'a Request) -> BoxFuture<'a, Response> + Send + Sync> and Box::pin(f(req)) inside add_route. This keeps the call site clean and compiles.

Current error

error[E0308]: mismatched types
  --> src/main.rs:62:3
   |
62 |   server.add_route("/", Rt::GET, demo_get);
   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
   |
   = note: expected opaque type `impl for<'a> Future<Output = Response>`
              found opaque type `impl Future<Output = Response>`
   = note: distinct uses of `impl Trait` result in different opaque types
note: the lifetime requirement is introduced here
  --> .../http-server/src/runtime/async/tokio.rs:43:35
   |
43 |     F: for<'a> Fn(&'a Request) -> Fut + Send + Sync + 'static,
   |                                   ^^^

Any tip for solving this would be very appreciated, since I have been looping on AI suggested solutions for a while now.

1
  • Why don't you take a look at existing HTTP runtimes? Commented Sep 15 at 0:54

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.