How do I call a Fn parameter for a trait function from another asynchronous function?

Viewed 68

I am using this library to implement a jsonrpc server: https://github.com/paritytech/jsonrpc. There is a way to implement a trait and use it as middleware for the server. The function in the trait looks like:

fn on_request<F, X>(&self, request: Request, meta: M, next: F) -> Either<Self::Future, X>
    where
        F: Fn(Request, M) -> X + Send + Sync,
        X: Future<Output = Option<Response>> + Send + 'static,
    {
}

In this function I can return a Future for a response immediately, or I can call the "next" Fn to move on to the next layer of the server. I would like the decision of responding in the middleware vs. sending it to the next layer to be an decided asynchronously.

I have done this (simpified for this question):

pub struct SampleMiddleware;
impl Middleware<Meta> for SampleMiddleware {
    type Future = FutureResponse;
    type CallFuture = middleware::NoopCallFuture;

    fn on_request<F, X>(&self, request: Request, meta: Meta, next: F) -> Either<Self::Future, X>
    where
        F: FnOnce(Request, Meta) -> X + Send,
        X: Future<Output = Option<Response>> + Send + 'static,
    {
        Either::Left(Box::pin(SampleMiddleware::process_async(request, meta, next)))
    }
}

impl SampleMiddleware {
    async fn process_async<F, X>(req: Request, meta: Meta, next: F) -> Option<Response>
    where
        F: FnOnce(Request, Meta) -> X + Send,
        X: Future<Output = Option<Response>> + Send + 'static,
    {
        let result = SampleMiddleware::async_fn(&req, &meta).await;
        match result {
            Some(r) => {
                Some(r)
            },
            None => {
                next(req, meta).await
            }
        }
    }

    async fn async_fn(req: &Request, meta: &Meta) -> Option<Response>
    {
        return None
    }
}

However on this line:Either::Left(Box::pin(SampleMiddleware::process_async(request, meta, next))) I get this error from the compiler:

the parameter type `F` may not live long enough
...so that the type `impl futures::Future<Output = std::option::Option<jsonrpc_core::Response>>` will meet its required lifetime bounds
consider adding an explicit lifetime bound...: `F: 'static`

I don't think I can change the lifetime bound to F because that comes from the trait I don't control.

I am pretty new to Rust and haven't quite wrapped my head around how to use lifetimes. I think this question might boil down to how I can call a FnOnce in another thread, but not sure.

0 Answers
Related