Hey all,
I have been trying to figure this out for the past week. What I am trying to do is store async functions and call them whenever I want however many times I want.
I have it working if the async fns I want to store takes the values directly.
use tokio; // 1.2.0
use futures; // 0.3.12
use futures::prelude::*;
use std::pin::Pin;
trait System: Send + Sync + 'static {
fn call<'a, 't>(&'a self, n: u8) -> Pin<Box<dyn Future<Output = u8> + Send + 't>>
where
'a: 't;
}
impl<T, F> System for T
where
T: Fn(u8) -> F + Send + Sync + 'static,
F: Future<Output = u8> + Send + 'static,
{
fn call<'a, 't>(&'a self, n: u8) -> Pin<Box<dyn Future<Output = u8> + Send + 't>>
where
'a: 't
{
Box::pin((self)(n))
}
}
async fn a(n: u8) -> u8 {
println!("executing a");
n + 1
}
async fn b(mut n: u8) -> u8 {
n = n + 1;
n + 2
}
#[tokio::main]
async fn main() {
let mut v: Vec<Box<dyn System>> = vec![];
let mut n: u8 = 2;
v.push(Box::new(a));
v.push(Box::new(b));
println!("pushed");
for i in &v {
n = i.call(n).await;
println!("{:?}", n);
}
for i in &v {
n = i.call(n).await;
println!("{:?}", n);
}
}
But when I want the async fns to take references, I am running into a few problems.
use tokio; // 1.2.0
use futures; // 0.3.12
use futures::prelude::*;
use std::pin::Pin;
trait System: Send + Sync + 'static {
fn call<'a, 't>(&'a self, n: &mut u8) -> Pin<Box<dyn Future<Output = u8> + Send + 't>>
where
'a: 't;
}
impl<T, F> System for T
where
T: Fn(&mut u8) -> F + Send + Sync + 'static,
F: Future<Output = u8> + Send + 'static,
{
fn call<'a, 't>(&'a self, n: &mut u8) -> Pin<Box<dyn Future<Output = u8> + Send + 't>>
where
'a: 't
{
Box::pin((self)(n))
}
}
async fn a(n: &mut u8) -> u8 {
println!("executing a");
*n + 1
}
async fn b(n: &mut u8) -> u8 {
*n = *n + 1;
*n + 2
}
#[tokio::main]
async fn main() {
let mut v: Vec<Box<dyn System>> = vec![];
let mut n: u8 = 2;
v.push(Box::new(a));
v.push(Box::new(b));
println!("pushed");
for i in &v {
println!("{:?}", i.call(&mut n).await);
}
for i in &v {
println!("{:?}", i.call(&mut n).await);
}
}
This gives me the following compile error:
error: implementation of `FnOnce` is not general enough
--> src/main.rs:41:12
|
41 | v.push(Box::new(a));
| ^^^^^^^^^^^ implementation of `FnOnce` is not general enough
|
= note: `FnOnce<(&'0 mut u8,)>` would have to be implemented for the type `for<'_> fn(&mut u8) -> impl futures::Future {a}`, for some specific lifetime `'0`...
= note: ...but `FnOnce<(&mut u8,)>` is actually implemented for the type `for<'_> fn(&mut u8) -> impl futures::Future {a}`
error: implementation of `FnOnce` is not general enough
--> src/main.rs:42:12
|
42 | v.push(Box::new(b));
| ^^^^^^^^^^^ implementation of `FnOnce` is not general enough
|
= note: `FnOnce<(&'0 mut u8,)>` would have to be implemented for the type `for<'_> fn(&mut u8) -> impl futures::Future {b}`, for some specific lifetime `'0`...
= note: ...but `FnOnce<(&mut u8,)>` is actually implemented for the type `for<'_> fn(&mut u8) -> impl futures::Future {b}`
Researching a bit, I get pointed to several questions on stackoverflow and to the following issues on github:
I tried to correct the above code by specifying a lifetime for the reference in the async function:
use tokio; // 1.2.0
use futures; // 0.3.12
use futures::prelude::*;
use std::pin::Pin;
trait System<'r>: Send + Sync {
fn call<'a>(&'a self, n: &'r mut u8) -> Pin<Box<dyn Future<Output = u8> + Send + 'r>>
where
'a: 'r;
}
impl<'r, T, F> System<'r> for T
where
T: Fn(&'r mut u8) -> F + Send + Sync,
F: Future<Output = u8> + Send + 'r,
{
fn call<'a>(&'a self, n: &'r mut u8) -> Pin<Box<dyn Future<Output = u8> + Send + 'r>>
where
'a: 'r,
{
Box::pin((self)(n))
}
}
async fn a(n: &mut u8) -> u8 {
println!("executing a");
*n + 1
}
async fn b(n: &mut u8) -> u8 {
*n = *n + 1;
*n + 2
}
#[tokio::main]
async fn main() {
let mut v: Vec<Box<dyn System>> = vec![];
let mut n: u8 = 2;
v.push(Box::new(a));
v.push(Box::new(b));
println!("pushed");
for i in &v {
println!("{:?}", i.call(&mut n).await);
}
for i in &v {
println!("{:?}", i.call(&mut n).await);
}
}
but it gives me the following compile error:
error[E0597]: `v` does not live long enough
--> src/main.rs:46:14
|
46 | for i in &v {
| ^^
| |
| borrowed value does not live long enough
| argument requires that `v` is borrowed for `'static`
...
53 | }
| - `v` dropped here while still borrowed
error[E0499]: cannot borrow `n` as mutable more than once at a time
--> src/main.rs:47:33
|
47 | println!("{:?}", i.call(&mut n).await);
| -------^^^^^^-
| | |
| | `n` was mutably borrowed here in the previous iteration of the loop
| argument requires that `n` is borrowed for `'static`
error[E0499]: cannot borrow `n` as mutable more than once at a time
--> src/main.rs:51:33
|
51 | println!("{:?}", i.call(&mut n).await);
| -------^^^^^^-
| | |
| | `n` was mutably borrowed here in the previous iteration of the loop
| argument requires that `n` is borrowed for `'static`
I would really appreciate if someone can help me understand what exactly I am missing and get this working or if it's not possible right now in Rust.