How to deal with static lifetime when implementing Future?

I'm trying to implement Future, but it fails:

use std::{
    future::Future,
    pin::Pin,
    sync::{Arc, Mutex},
    task::{Context, Poll},
    time::Duration,
};
use tokio::time::sleep;

async fn send(url: &str) {
    println!("Sending to URL {}", url);
    // Simulate the sending process
    sleep(Duration::from_millis(500)).await;
}

type Request = Pin<Box<dyn Future<Output = ()>>>;

struct Proxy {
    this: Option<Pin<Box<dyn Future<Output = ()>>>>,
    requests: Arc<Mutex<Vec<Request>>>,
}

impl Proxy {
    fn new() -> Self {
        Self {
            this: None,
            requests: Arc::new(Mutex::new(vec![])),
        }
    }

    fn push(&self, request: Request) {
        let requests = self.requests.try_lock().expect("Cannot lock");
        requests.push(request);
    }

    async fn execute_requests(&self) {
        let mut requests = self.requests.try_lock().expect("Cannot lock");
        while let Some(request) = requests.pop() {
            request.await;
        }
    }
}

impl Future for Proxy {
    type Output = ();

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        self.this
            .get_or_insert_with(|| Box::pin(self.execute_requests()))
            .as_mut()
            .poll(cx)
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let request_1 = async {
        send("url 1").await;
    };
    let request_2 = async {
        send("url 2").await;
    };

    let mut proxy = Proxy::new();
    proxy.push(Box::pin(request_2));
    proxy.push(Box::pin(request_1));

    Ok(proxy.await)
}

The error:

error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
  --> snippet.rs:49:50
   |
47 |     fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
   |                   -------------- this data with an anonymous lifetime `'_`...
48 |         self.this
49 |             .get_or_insert_with(|| Box::pin(self.execute_requests()))
   |                                                  ^^^^^^^^^^^^^^^^ ...is captured here, requiring it to live as long as `'static`

Your struct would be self-referential, since the future you are trying to assign to this holds a reference to the struct. You can't do that.

Thanks, @alice. I think that now I understand the problem a little more.

Do you have any workaround or suggestion about how can I bypass that limitation?

If you gave the future that you are storing a clone of the Arc<Mutex<Vec<Request>>>, then it wouldn't need to have any references to anything outside of the future.

Thank you, @alice. I didn't though about something as simple as that.

These are the changes:

impl Proxy {
    // ...

    async fn execute_requests(mut requests: Arc<Mutex<Vec<Request>>>) {
        let mut requests = requests.try_lock().expect("Cannot lock");
        while let Some(request) = requests.pop() {
            request.await;
        }
    }
}

impl Future for Proxy {
    type Output = ();

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let mut requests = Arc::clone(&self.requests);
        self.this
            .get_or_insert_with(|| Box::pin(Self::execute_requests(requests)))
            .as_mut()
            .poll(cx)
    }
}

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.