Eu tenho este exemplo mínimo:
use std::{future::Future, pin::Pin, thread::JoinHandle, fmt::Debug};
use tokio::runtime::Runtime;
struct Callback<E> {
f: Box<dyn Fn() -> Pin<Box<dyn Future<Output = Result<(), E>> + Send + Sync>> + Send + Sync>,
}
trait Provider {
fn setup(&self) -> JoinHandle<()>;
}
enum Foo {
A,
B
}
trait IntoFoo {
fn into_foo(&self) -> Foo;
}
impl<E: Debug + IntoFoo> Provider for Callback<E> {
fn setup(&self) -> JoinHandle<()> {
std::thread::spawn(move || {
// Running async function sycnhronously within another thread.
let rt = Runtime::new().unwrap();
rt.block_on(handle(Box::new(move || (self.f)())))
.expect("request loop failed")
})
}
}
async fn handle<E: Debug + IntoFoo + 'static>( callback_fn: Box<dyn Fn() -> Pin<Box<dyn Future<Output = Result<(), E>> + Send + Sync>> + Send + Sync>) -> Result<(), E> {
perform(Box::new(move || (callback_fn)())).await
}
pub async fn perform<
E: Debug + IntoFoo>(
op: Box<dyn Fn() -> Pin<Box<dyn Future<Output = Result<(), E>> + Send + Sync>> + Send + Sync>,
) -> Result<(), E> {
(op)().await
}
Esta é uma versão simplificada de algum código real onde eu essencialmente tenho que passar um retorno de chamada assíncrono, dentro de uma estrutura. Esse retorno de chamada é passado por várias funções. Um deles chama a função em um thread recém-gerado.
O erro que recebo está dentro do código de geração do thread, quando handle
é chamado.
O erro é:
error: lifetime may not live long enough
--> src/indexer/callback.rs:41:41
|
27 | fn bootstrap(&self, input: StageReceiver) -> BootstrapResult {
| - let's call the lifetime of this reference `'1`
...
41 | rt.block_on(handle_event(input, Box::new(move |ev: &Event| (self.f)(ev)), &retry_policy, utils))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cast requires that `'1` must outlive `'static`
Como devo orquestrar isso? Aberto para alterar o tipo de campo struct e qualquer coisa semelhante. Devo observar, entretanto: esta função deve poder ser chamada várias vezes (pode estar dentro de um loop in handle
).
Alguns outros threads sugeriram que retornos de chamada assíncronos fossem passados em um Box, e seus resultados fossem um objeto de característica em caixa fixada. É por isso que tentei este sistema.