Issue chaining Futures

Hi there,

I now there is the hole async/await thing now stabilized. However, I'm trying to adopt the concepts and framework to be used in my bare-metal no_std OS.

Therefore I'm using the Futures directly. But when chaining them I'm getting some issues compiling.
Please check the Playground

The compiler issue is about lifetime and borrows which I kinda understand why the compiler complains but I'm not able to come up with any solution.
The core of the issue is a chain like this:

pub fn initialize(&mut self) -> impl Future<Output = ()> {
        self.bar()
            .then(|_| self.baz())
            .then(|_| self.bal())
    }

where self is borrowed several times and therefore restricting the lifetime of the future returned in the then closure. Would it be safe to wrap self into an Arc and pass clones of it around? Thats the only way of doing comes into my mind. This would mean to create a clone for each then closure, right?

pub fn initialize(&mut self) -> impl Future<Output = ()> {
        let arc_self = Arc::new(self);
        let self1 = arc_self.clone();
        let self2 = arc_self.clone();
        arc_self.bar()
            .then(|_| self1.baz())
            .then(|_| self2.bal())
    }

Thanks in advance.

This is exactly what async await is meant to solve:

pub fn initialize<'a>(&'a mut self) -> impl Future<Output = ()> + 'a {
    async {
        self.bar().await;
        self.baz().await;
        self.bal().await;
    }
}

or equivalently:

pub async fn initialize(&mut self) {
    self.bar().await;
    self.baz().await;
    self.bal().await;
}

Well this is great, but how could I solve this if I do not have the ability to use async/await pattern ? Even if this mean I need to implement lots of "boilerplate" by myself...

Well your future type would be self-referential, so it involves significant pin madness. Before async await came around, everyone wrote their futures with internal reference counting to avoid futures that borrow things, because without this, combinators become a major pain.

So well, I somehow expected I will run into madness. However, as soon as async/await is not available to be useful in no_std I will need to roll my own things here... So do you know any references where I can get inspired from?

I'm pretty sure async await should work fine in no_std.

1 Like

There are some obstacles to using async/await without the alloc crate. On targets with core plus alloc it should be easier, I think. There are some relevant links in this thread:

Blockquote
I'm pretty sure async await should work fine in no_std .

Unfortunately this is not the case:

error[E0433]: failed to resolve: could not find `poll_with_tls_context` in `future`

error[E0433]: failed to resolve: could not find `from_generator` in `future`

Hey, thanks for this pointer. I'll check this. The good news, I'm already using core+alloc crate so I might find an alternative solution in there :wink:

That was just based on my quick reading, by the way. There might be more problems I'm not aware of. (Just don't wan't to get your hopes up!)

Well at the time beeing I've already written a lean executor and lean derivate of what a future is to run in my bare-metal no_std OS being single threaded but multi-core and it's running really smooth so far, but while implementing my first more complex futures I'm actually facing the limits of my implementation and try to find a way to address this - even if it take a bit more time and reading... :wink:

So, thanks for managing my expectations right :slight_smile:

1 Like