How can I define struct that holds futures of function which functions will return a future

error[E0308]: mismatched types
  --> src/main.rs:19:5
   |
19 |     async { println!("World") }
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: consider using a semicolon here: `;`
   |     |
   |     expected `()`, found opaque type
   |
   = note: expected unit type `()`
            found opaque type `impl futures::Future<Output = [async output]>`

To make this compile, the correct return type would be impl Future<Output = ()>, but I do not think that it is what you want because the async keyword on the function would then expand it to the following, with a "double future".

fn fn_name() -> impl Future<Output = impl Future<Output = ()>> {
    async {
        println!("Hello");
        async { println!("World") }
    }
}

error[E0618]: expected function, found `Pin<Box<dyn futures::Future<Output = (bool, Option<Box<(dyn Fn() + 'static)>>)>>>`
  --> src/main.rs:24:31
   |
23 |     for func in f.func {
   |         ---- `func` has type `Pin<Box<dyn futures::Future<Output = (bool, Option<Box<(dyn Fn() + 'static)>>)>>>`
24 |         let return_callback = func().await;
   |                               ^^^^--
   |                               |
   |                               call expression requires function

The type of func is a kind of future, which is a different thing from a function. You can only .await a future — you can't call it with (). That would then be func.await. Additionally, return_callback is also not a function. You would need to unpack the boolean/function tuple before you can access it. (And the function does not return a future, so you wouldn't be able to .await it even if you did that.)


error[E0277]: `fn() -> dyn futures::Future<Output = (bool, Option<Box<(dyn Fn() + 'static)>>)>` is not a future
  --> src/main.rs:13:24
   |
13 |         self.func.push(Box::pin(callback));
   |                        ^^^^^^^^^^^^^^^^^^ `fn() -> dyn futures::Future<Output = (bool, Option<Box<(dyn Fn() + 'static)>>)>` is not a future
   |
   = help: the trait `futures::Future` is not implemented for `fn() -> dyn futures::Future<Output = (bool, Option<Box<(dyn Fn() + 'static)>>)>`
   = note: required for the cast to the object type `dyn futures::Future<Output = (bool, Option<Box<(dyn Fn() + 'static)>>)>`

As the error said, functions and futures are different things. You cannot convert a function into a future. Additionally, a return value of dyn Future<...> will never be possible, because a dyn Trait can only ever exist inside a Box (or another reference type), which it doesn't here. You should probably wrap it in Pin<Box<...>>.

2 Likes

1

fn fn_name() -> impl Future<Output = impl Future<Output = ()>> {
    async {
        println!("Hello");
        async { println!("World") }
    }
}

2

async fn fn_name() -> impl Future<Output = ()> {
    println!("Hello");
    async {
        async { println!("World") }
    }
}

ohh so you mean 2 is not possible without any third party library like tokio or async-std ?

No, that's not what I meant. I just meant you should remove the async block inside the function.

ohh alright

@alice
Hi I created a even smaller rust play here:

This is even smaller & straight to the point what problem I am actually facing.
Error: doesn't have a size known at compile-time

1 Like

Thanks, that makes it easier to help you.

dyn Future must be wrapped in a Pin<Box<..>>.

@alice Still the same error

The error comes from fn add, and it is not wrapped in Pin<Box<...>> there. You can fix that like this:

impl Store {
    fn add(&mut self, name: impl Future<Output = ()> + 'static) -> () {
        self.fns.push(Box::pin(name));
    }
}

@alice
sorry but now we have another error.
impl futures::Future<Output = ()> {name} is not a future`

That's not exactly what the error is telling you. The message is:

error[E0277]: `fn() -> impl futures::Future<Output = ()> {name}` is not a future

which is telling you that fn() -> impl futures::Future<Output = ()> {name} is not a future. Note the fn() -> at the beginning. In words, this is: “A function returning a future is not a future.”

The compiler then goes on to suggest calling the function, to get the future that it returns, which is the right solution, or at least makes the code compile successfully:

    let mut s = Store {fns:Vec::new()};
    s.add(name());

Hi @kpreid

Even tho its compile it is not I am looking for. I wants to call this function later in loop with join.

You can tell us what you want to achieve not how you want to achieve it ? It'll probably be faster.

For example, returning a closure in Rust is often hard to do, a better approach is often to return a struct with associated functions.

Hi @erelde
What I wants to achieve is get all async fn & store it into struct & then merge it into vector to run all of those functions in parallel with join_all

if you visit the link above you will understand, it is very simple.

Then you need to store the functions, not the futures, and you'll need to box them too. Here's a working version:

use futures::executor::block_on;
use futures::future::{join_all, Future, BoxFuture};

struct Store {
    fns: Vec<Box<dyn Fn() -> BoxFuture<'static, ()>>>,
}

impl Store {
    fn add<F, Fut>(&mut self, func_ptr: F)
    where
        F: Fn() -> Fut + 'static,
        Fut: Future<Output = ()> + Send + Sync + 'static,
    {
        self.fns.push(Box::new(move || Box::pin(func_ptr())));
    }

    async fn run(&self) {
        let mut futures = Vec::new();
        for f in &self.fns {
            futures.push(f());
        }
        join_all(futures).await;
    }
}

async fn f1() -> () {
    println!("Hello");
}
async fn f2() -> () {
    println!("Goodbye");
}

fn main() {
    let mut s = Store { fns: Vec::new() };
    s.add(f1);
    s.add(f2);
    block_on(s.run());
}
3 Likes

@kpreid
Thank you so much. This is what I was looking for.
Thank you everyone who has join this topic. I can not thank all of you enough.
:heart:

1 Like

Hi @alice @bradleyharden @erelde @kpreid

This is the open source project repo. If you wants to contribute, you can. Very small LOC so would not take more than 5 minutes to understand.

https://github.com/oxidy-rs/oxidy/tree/experiments

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.