As far as I can tell, creating closures that return values that borrow from captures and arguments is not possible in Rust today. I'm wondering if maybe it's possible to build a macro that allows something close to the conciseness of closures. But I'm thinking probably not since you can't seem to get at type inference information from a macro?
My main use-case is I'd like users of a library to be able to register async handler functions that own their captures & borrow them during their async block, and not have all the boilerplate of creating a struct + implementing a trait for each handler (not unreasonable to have hundreds of handlers in a given application).
Say we had a trait like this
pub trait BorrowFn {
type Args<'a>;
type Return<'a>;
fn call<'a>(
&'a mut self,
args: Self::Args<'a>,
) -> Self::Return<'a>;
}
And say we wanted to write a closure like this:
let x = Box::new(42); // box so it's not Copy
let foo = move |y: &isize| {
let x = &x; // Borrow x to prevent it from being moved into async block
async move {
if *x > *y {
*x + 42
} else {
*y + 42
}
}
};
We can generate code that looks something like this:
#![feature(generic_associated_types)]
#![feature(type_alias_impl_trait)]
use std::future::Future;
pub struct Foo {
x: Box<isize>,
}
impl BorrowFn for Foo {
type Args<'b> = &'b isize;
type Return<'b> = impl Future<Output = isize> + 'b;
fn call<'b>(
&'b mut self,
args: Self::Args<'b>,
) -> Self::Return<'b> {
async move {
if *self.x > *args {
*self.x + 42
} else {
*args + 42
}
}
}
}
Ideally the macro invocation would like something like this:
let x = Box::new(42isize); // box so it's not Copy
let foo = borrow_fn! {
|y: &isize| {
async move {
if *x > *y {
*x + 42
} else {
*y + 42
}
}
}
};
But then how does the the macro know what to assign as the Return<'a>
type in the trait implementation? And the type of x
in the Foo
struct? It would need type information from the compiler.
Anyone have any clever ideas for how to do this? Or if someone has already done this? Or how herculean of a task it'd be to get closures like this properly into the language? I'm probably not qualified but I'd be willing to take a stab at an RFC and implementation.