Need help with async_fn_in_trait syntax

I want to write an HttpServer that uses the async-fn-in-trait syntax, and this is the simplified code

#![feature(async_fn_in_trait)]

use std::{convert::Infallible, future::Future, net::SocketAddr, str::FromStr};

use bytes::Bytes;
use http_body_util::Full;
use hyper::{body::Incoming, server::conn::http1, service::service_fn, Request, Response};
use tokio::net::TcpListener;

pub trait Handle {
    async fn handle(&mut self, req: Request<Incoming>)
        -> Result<Response<Full<Bytes>>, Infallible>;
}

struct HttpServer<H> {
    addr: String,
    handler: H,
}

impl<H> HttpServer<H>
where
    H: Handle,
{
    fn servr(&self) {
        tokio::runtime::Builder::new_multi_thread()
            .enable_all()
            .build()
            .unwrap()
            .block_on(async move {
                let addr = SocketAddr::from_str(self.addr.as_str()).unwrap();
                let listener = TcpListener::bind(addr).await.unwrap();
                loop {
                    let (stream, _) = listener.accept().await.unwrap();
                    tokio::task::spawn(async move {
                        let service = service_fn(move |req| self.handler.handle(req));
                        http1::Builder::new()
                            .serve_connection(stream, service)
                            .await
                            .unwrap()
                    });
                }
            })
    }
}

like Do we need Send bounds to stabilize async_fn_in_trait? says, there will be an "future is not Send" error

This issue says it can be temporarily solved with the return_position_impl_trait_in_trait syntax

#![feature(return_position_impl_trait_in_trait)]

pub trait Handle: Send + 'static {
    fn handle(
        &mut self,
        req: Request<Incoming>,
    ) -> impl Future<Output = Result<Response<Full<Bytes>>, Infallible>> + Send + '_;
}

but it still doesn't work.

What is the correct way to get this code to pass compilation?

1 Like

It can never work to write self.handler.handle(req) in a closure which must be 'static, given that server takes only a temporary reference to &self. Do you mean to write fn servr(self) { ... }? Or do you mean to take the handler out or self, or to share the handler between self and the created thread? In the last case, Handle::handle() would have to take &self, or the caller would need a locking mechanism like Mutex.