How to write the type for a boxed closure which takes a reference as an argument and returns an object which references data from the argument?

Viewed 143

I'm trying to define the following type in Rust:

type JsTaskCallback = Box<
    dyn (FnOnce(&'a mut RuntimeHandle<'a>) -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + 'a>>)
        + Send,
>;

It is intended to allow the user to pass in a closure which accepts a RuntimeHandle (a struct that I defined which lives for 'a) and returns a future which lives for at least as long as the RuntimeHandle reference (necessary in order for the code calling this function to await the returned future).

Where should I specify 'a? Specifying it on JsTaskCallback would not be correct, because the lifetime in use is defined at the call site. Specifying '_ is not correct, because there are too many lifetimes for the compiler to infer anything. And leaving out the lifetime inside the Pin<Box> is not correct, because I don't want to force the returned future to be 'static.

While researching this, I discovered the Rustnomicon page on HRTBs, but I'm not sure how to apply the information in there to trait objects.

1 Answers

You're right. You need to use HRTB. The syntax is like:

type JsTaskCallback = Box<
    dyn (for<'a> FnOnce(
            &'a mut RuntimeHandle<'a>,
        ) -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + 'a>>)
        + Send,
>;

It means "for any lifetime 'a the function will be called with, with an argument of type &'a mut RuntimeHandle<'a>, it will return a future living for 'a".

Related