I am trying to write a function that returns an async closure, but running into an issue where the compiler is unable to infer lifetimes. I am able to write an equivalent sync version (included in the playground code) just fine. It is only for async that I am running into issues.
use std::{future::Future, pin::Pin};
pub struct SystemContext {
pub data: usize,
}
pub struct RequestContext<'a> {
pub data: &'a str,
}
pub async fn async_compute<'r>(
system_context: &'r SystemContext,
request_context: &RequestContext<'r>,
input: String,
) -> String {
// real code makes an async call
format!("{} {}", input.repeat(system_context.data), request_context.data)
}
type AsyncComputeFn<'r> =
Box<dyn Fn(&RequestContext<'r>, String) -> Pin<Box<dyn Future<Output = String> + 'r>> + 'r>;
pub fn async_curried_compute<'r>(system_context: &'r SystemContext) -> AsyncComputeFn<'r> {
Box::new(move |request_context: &RequestContext<'r>, input: String| {
Box::pin(async move { async_compute(system_context, request_context, input).await })
})
}
// request_context in AsyncComputeFn doesn't specify a lifetime
// so that I can write code such as the following. The computation
// depends only on the content of request_context, in any case
async fn use_async_compute(async_compute_fn: AsyncComputeFn<'_>) -> String {
let request_context = RequestContext {
data: "request data",
};
let input = "input data".to_string();
async_compute_fn(&request_context, input).await
}
#[tokio::main]
async fn main() {
let system_context = SystemContext { data: 5 };
println!(
"async {}",
use_async_compute(async_curried_compute(&system_context)).await
);
}
With this, I get the following error:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:42:29
|
42 | Box::pin(async move { async_compute(system_context, request_context, input).await })
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined here...
--> src/main.rs:41:14
|
41 | Box::new(move |request_context: &RequestContext<'r>, input: String| {
| ______________^
42 | | Box::pin(async move { async_compute(system_context, request_context, input).await })
43 | | })
| |_____^
note: ...so that the types are compatible
--> src/main.rs:42:29
|
42 | Box::pin(async move { async_compute(system_context, request_context, input).await })
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `(&SystemContext, &RequestContext<'_>, String)`
found `(&'r SystemContext, &RequestContext<'r>, String)`
note: but, the lifetime must be valid for the lifetime `'r` as defined here...
--> src/main.rs:40:30
|
40 | pub fn async_curried_compute<'r>(system_context: &'r SystemContext) -> AsyncComputeFn<'r> {
| ^^
note: ...so that the types are compatible
--> src/main.rs:42:9
|
42 | Box::pin(async move { async_compute(system_context, request_context, input).await })
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `Pin<Box<(dyn Future<Output = String> + 'r)>>`
found `Pin<Box<dyn Future<Output = String>>>`
For more information about this error, try `rustc --explain E0495`.
I am not sure what I need to change to make the compiler happy.