If I define Handler trait for async function it appears compile error

Viewed 30

I wanted to define some Handler trait for async function but it gives me an compile error as below.

#[async_trait]
trait Handler: Send + Sync + 'static {
    async fn handle(&self, req: Request<Body>) -> Result<Response<Body>, GenericError>;
}

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

the result:

future cannot be sent between threads safely
required for the cast to the object type `dyn futures::Future<Output = Result<Response<Body>, Box<(dyn std::error::Error + Sync + std::marker::Send + 'static)>>> + std::marker::Send`rustc
router.rs(21, 9): future is not `Send` as it awaits another future which is not `Send`
router.rs(18, 63): consider further restricting this bound: ` + std::marker::Send`
1 Answers

Fut may not be Send, but async_trait requires the future to be Send. You can either constrain Fut to Send futures only:

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

Or opt for async_trait to not generate a Send bound:

#[async_trait(?Send)]
trait Handler: Send + Sync + 'static {
    async fn handle(&self, req: Request<Body>) -> Result<Response<Body>, GenericError>;
}

#[async_trait(?Send)]
impl<F: Send + Sync + 'static, Fut> Handler for F
where
    F: Fn(Request<Body>) -> Fut,
    Fut: Future<Output = Result<Response<Body>, GenericError>>,
{
    async fn handle(&self, req: Request<Body>) -> Result<Response<Body>, GenericError> {
        self(req).await
    }
}
Related