Solution to Rust errors of kinds:
- implementation of
Fn
is not general enough (works with FnMut and FnOnce as well) - lifetime may not live long enough
use std::future::Future;
trait Callback<Arg, Res> {
type Output: Future<Output = Res>;
fn call(&self, arg: Arg) -> Self::Output;
}
impl<Arg, Res, F, Fut> Callback<Arg, Res> for F
where
F: Fn(Arg) -> Fut,
Fut: Future<Output = Res>,
{
type Output = Fut;
fn call(&self, arg: Arg) -> Fut {
self(arg)
}
}
async fn run_callback<F>(callback: F)
where
for<'a> F: Callback<&'a mut i32, i32>,
{
for mut i in 0..10 {
let res = callback.call(&mut i).await;
println!("{}", res);
}
}
async fn test() {
async fn callback(x: &mut i32) -> i32 {
*x += 10;
println!("{}", x);
*x + 100
}
run_callback(callback).await;
// Does not work:
// run_callback(|x: &mut i32| async move {
// *x += 10;
// println!("{}", x);
// *x + 100
// }).await;
}
trait CallbackWithState<State, Arg, Res> {
type Output: Future<Output = Res>;
fn call(&self, state: State, arg: Arg) -> Self::Output;
}
impl<State, Arg, Res, F, Fut> CallbackWithState<State, Arg, Res> for F
where
F: Fn(State, Arg) -> Fut,
Fut: Future<Output = Res>,
{
type Output = Fut;
fn call(&self, state: State, arg: Arg) -> Fut {
self(state, arg)
}
}
async fn run_callback_with_state<State, F>(state: &mut State, callback: F)
where
for<'state, 'arg> F: CallbackWithState<&'state mut State, &'arg mut i32, i32>,
{
for mut i in 0..10 {
let res = callback.call(state, &mut i).await;
println!("{}", res);
}
}
async fn test_with_state() {
async fn callback(state: &mut String, x: &mut i32) -> i32 {
*x += 10;
state.push_str(&x.to_string());
println!("{}", x);
*x + 100
}
run_callback_with_state(&mut String::new(), callback).await;
// Does not work:
// run_callback_with_state(&mut String::new(), |state: &mut String, x: &mut i32| async move {
// *x += 10;
// state.push_str(&x.to_string());
// println!("{}", x);
// let res = *x + 100;
// });
}
If you want to restrict the Callback trait to take references only you have to use explicit lifetimes like so:
use std::future::Future;
trait Callback<'arg, Arg: 'arg, Res> {
type Output: Future<Output = Res>;
fn call(&self, arg: &'arg mut Arg) -> Self::Output;
}
impl<'arg, Arg: 'arg, Res, F, Fut> Callback<'arg, Arg, Res> for F
where
F: Fn(&'arg mut Arg) -> Fut,
Fut: Future<Output = Res>,
{
type Output = Fut;
fn call(&self, arg: &'arg mut Arg) -> Fut {
self(arg)
}
}
async fn run_callback<F>(callback: F)
where
for<'a> F: Callback<'a, i32, i32>,
{
for mut i in 0..10 {
let res = callback.call(&mut i).await;
println!("{}", res);
}
}
async fn test() {
async fn callback(x: &mut i32) -> i32 {
*x += 10;
println!("{}", x);
*x + 100
}
run_callback(callback).await;
// Does not work:
// run_callback(|x: &mut i32| async move {
// *x += 10;
// println!("{}", x);
// *x + 100
// }).await;
}
trait CallbackWithState<'state, 'arg, State: 'state, Arg: 'arg, Res> {
type Output: Future<Output = Res>;
fn call(&self, state: &'state mut State, arg: &'arg mut Arg) -> Self::Output;
}
impl<'state, 'arg, State: 'state, Arg: 'arg, Res, F, Fut>
CallbackWithState<'state, 'arg, State, Arg, Res> for F
where
F: Fn(&'state mut State, &'arg mut Arg) -> Fut,
Fut: Future<Output = Res>,
{
type Output = Fut;
fn call(&self, state: &'state mut State, arg: &'arg mut Arg) -> Fut {
self(state, arg)
}
}
async fn run_callback_with_state<State, F>(state: &mut State, callback: F)
where
for<'state, 'arg> F: CallbackWithState<'state, 'arg, State, i32, i32>,
{
for mut i in 0..10 {
let res = callback.call(state, &mut i).await;
println!("{}", res);
}
}
async fn test_with_state() {
async fn callback(state: &mut String, x: &mut i32) -> i32 {
*x += 10;
state.push_str(&x.to_string());
println!("{}", x);
*x + 100
}
run_callback_with_state(&mut String::new(), callback).await;
// Does not work:
// run_callback_with_state(&mut String::new(), |state: &mut String, x: &mut i32| async move {
// *x += 10;
// state.push_str(&x.to_string());
// println!("{}", x);
// let res = *x + 100;
// });
}