Push async block to FuturesUnordered without heap allocation

I have several async blocks as below.

let fu1 = async block { /* ... */ };
let fu2 = async block { /* ... */ };
let fu3 = async block { /* ... */ };

I want to push them into futures::stream::futures_unordered::FuturesUnordered without Box<T> or heap allocation. How should I declare the T of FuturesUnordered<T> in my struct?

I tried to store futures::future::lazy, that does not compile.

pub(super) struct XXXXXXXX {
    futures : FuturesUnordered<Lazy<()>>
}


let fu1 = futures::lazy(|_| async move  { /* ... */ };
let fu2 = futures::lazy(|_| async move  { /* ... */ };
let fu3 = futures::lazy(|_| async move  { /* ... */ };
futures.push(fu1);
futures.push(fu2);
futures.push(fu3);

Do you have any idea?

thank you in advance

I don't think this is possible, unless your FuturesUnordered stream is outlived by your futures, then you can take them by &mut dyn Future<Output = ()>.

But why is allocation so forbidden? FuturesUnordered itself allocates, BTW.

The problem is that every future pushed to a FuturesUnordered must be of the same type. There are a few ways to achieve this:

  1. Define a single async fn for creating the futures and only ever push instances of that async fn.
  2. By using Either, you can combine two types into one. You can nest this combinator to get more than two.
2 Likes

yep, I understand that each future is different while pushing to FuturesUnordered. I thought I could make them the same type by lazy.

Now I am trying the first approach in your suggestion, to only have one type of future.

struct XXXXXXXX<FU> where FU : Future<Output = ()> {

    futures : FuturesUnordered<FU>
}


impl<FU> XXXXXXXX<FU>  where FU : Future<Output = ()> {

    async fn coroutinne() {

    }

    fn push(&self) {
        let fu = XXXXXXXX::coroutinne();
        self.futures.push(fu);   // <----- error here
    }
}

It fails to compile

mismatched types
expected type parameter FU
found opaque type impl futures::Future
type parameters must be constrained to match other types

I can fix the error by changing the definition of futures to

futures : FuturesUnordered<Box<dyn Future<Output = ()>>>

But really dislike Box<T> since it cause extra heap allocation. As I understand, the size of the future is known at compile time, right? can I somehow get rid of the Box?

Thank you

In this case the problem is your use of generics. With generics I might decide to construct a XXXXXXXX<std::future::Pending> and then your own async fn won't be of the right type. You can't do it if it is to be stored as a field in a struct.