4

I'm trying to store these Readable instances on the Coordinator struct and have a schedule method that picks one of the readables and pushes it into a FuturesUnordered instance (also inside Coordinator) to be pulled later. Problem is: This doesn't compile due to a lifetime error

use bytes::Bytes;
use futures::prelude::stream::FuturesUnordered;
use std::future::Future;
use std::pin::Pin;

struct Readable {}

impl Readable {
    async fn read(&mut self) -> Result<Bytes, ()> {
        Err(())
    }
}

type Futures = FuturesUnordered<Pin<Box<dyn Future<Output = Result<Bytes, ()>> + Send>>>;

struct Coordinator {
    readers: Vec<Readable>,
    futures: Futures,
}

impl Coordinator {
    fn schedule(&mut self) {
        let reader = self.readers.get_mut(0).unwrap();
        let f = Box::pin(reader.read());
        self.futures.push(f);
    }
}

error

error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
  --> src/lib.rs:23:22
   |
22 |     fn schedule(&mut self) {
   |                 --------- this data with an anonymous lifetime `'_`...
23 |         let reader = self.readers.get_mut(0).unwrap();
   |                      ^^^^^^^^^^^^ ...is captured here...
24 |         let f = Box::pin(reader.read());
25 |         self.futures.push(f);
   |                           - ...and is required to live as long as `'static` here

error: aborting due to previous error

link to playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=2b69f519de1ac60b30bbbfb4a3cc3b7d

Anyone can help me understand why is this an issue? Specifically, it seems to be complaining when I try to push into FuturesUnordered but I don't see any lifetime bounds on the push method:

    /// Push a future into the set.
    ///
    /// This method adds the given future to the set. This method will not
    /// call [`poll`](core::future::Future::poll) on the submitted future. The caller must
    /// ensure that [`FuturesUnordered::poll_next`](Stream::poll_next) is called
    /// in order to receive wake-up notifications for the given future.
    pub fn push(&self, future: Fut) {...}

I thought it could also be related to this particular struct having self references (ie: Coordinator::futures is referencing Coordinator::readers) but I don't fully understand if that's related.

rcmgleite
  • 1,303
  • 1
  • 18
  • 22

1 Answers1

0

If we expand our async function it will be look like this:

fn read<'a>(&'a mut self) -> impl Future<Output = Result<Bytes, ()>> + 'a 

As you can see the lifetime 'a has captured in the returned Future type, this 'a is an anonymous lifetime since this read function can be called from any location.

This leads to our problem; from compiler perspective your schedule function creates a future with an anonymous lifetime, and tries to store it in self. It is not related with FuturesUnordered even if you would store your future like self.futures = f then the compiler would still throw the same error.

One solution can be using dedicating lifetime to tell compiler this is safe but I don't really suggest it because eventually it might lead any other problems since it forces borrowing self in a specific lifetime like in the code below.

impl<'a> Coordinator<'a> {
    fn schedule(&'a mut self) {//forced
        let reader = self.readers.get_mut(0).unwrap();
        let f = Box::pin(reader.read());
        self.futures = f;
    }
}

Playground

Other solution is much easier if your future doesn't borrow anything, you can define your async function without lifetimes as a future builder.

impl Readable {
    fn read(&mut self) -> impl Future<Output = Result<Bytes, ()>> {
        //produce bytes from self 
        futures::future::err(())
    }
}

Playground

See also :

Ömer Erden
  • 7,680
  • 5
  • 36
  • 45