Lifetime Challenges: Holding References in a struct with FuturesUnordered"

I have encountered an issue in my Rust code, specifically with lifetimes. The goal is to hold a reference to VideoCreationArguments in the VideoGenerator. Initially, I attempted to do this by introducing a lifetime parameter to VideoGenerator. However, I am facing difficulties when calling the FuturesUnordered.push method , as the reference to VideoGenerator does not outlive the creation of tasks in the FuturesUnordered stream.

Here's the code in question:

pub struct VideoCreationArguments<'a> {
    // Very important data
    data : &'a usize
}

pub struct Subreddit(usize);

pub struct VideoGenerationFiles(usize);
pub struct VideoDuration(usize);

pub struct VideoGenerator<'a> {
    video_gen_files: VideoGenerationFiles,
    video_duration: VideoDuration,
    arguments: &'a VideoCreationArguments<'a>,
}

impl<'a> VideoGenerator<'a> {
    pub fn new(
        video_gen_files: VideoGenerationFiles,
        arguments: &'a VideoCreationArguments<'a>,
        video_duration: VideoDuration,
    ) -> Self {
        Self {
            video_gen_files,
            video_duration,
            arguments,
        }
    }

    pub async fn exceute(self) -> std::io::Result<String> {
        // ... 
        Ok(())
    }
}

impl Subreddit {
    pub async fn exceute(&self,add_task : impl Fn(VideoGenerationFiles,VideoDuration) + Copy) {
        // some logic ...
        add_task(VideoGenerationFiles(1),VideoDuration(5))
    }
}

And later on I have got

pub async fn exceute(args : &VideoCreationArguments<'_>) -> Result<(),()> {
    let mut tasks = futures::stream::FuturesUnordered::new();

    let subreddit = Subreddit(1);
    
    // Note : I have to call it multiple times
    subreddit.exceute(|files,video_length_limit| {
        let gen = VideoGenerator::new(files,args,video_length_limit);
        tasks.push(gen.exceute())
    }).await;

    while let Some(task_result) = tasks.next().await {
        // ... 
    }
    
    Ok(())
}

The compiler raises a lifetime-related error, specifically mentioning that the borrowed data escapes outside the method body , for these lines

let gen = VideoGenerator::new(files,args,video_length_limit);
tasks.push(gen.exceute())
error[E0521]: borrowed data escapes outside of method
  --> src\config\reddit\mod.rs:45:21
   |
30 | ...n exceute(&self,args : &VideoCreationArguments<'_>,db : &mut Data... 
   |              --        ---- `args` is a reference that is only valid in the method body
   |              |
   |              lifetime `'a` defined here
...
45 | ...     VideoGenerator::new(files,args,video_length_limit).exceute().await     
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |         |
   |         `args` escapes the method body here
   |         argument requires that `'a` must outlive `'static`

I've attempted various approaches like below , and various from online sources

let gen : VideoGenerator<'a>  = VideoGenerator::new(files,args,video_length_limit);
tasks.push(gen.exceute())
tasks.push(async move { VideoGenerator::new(files,args,video_length_limit).exceute().await })
pub async fn exceute<'a>(args : &'a VideoCreationArguments<'a>) -> Result<(),()> {
    // ...
    Ok(())
}

Despite my efforts the compiler rejects it, claiming that the struct won't live long enough. Interestingly, the let mut tasks = FuturesUnordered::new() is used up before the end of the function , hence the reference of VideoCreationArguments should be living long enough

Any insights or suggestions on how to properly manage the lifetimes in this context would be greatly appreciated.

The code you've provided compiles fine for me. Something you removed from your actual code may be causing the actual problem

Playground

1 Like

Ok, that's definitely strange. I'll take a look at it tomorrow and let you know what I find.

I examined the code further and realized that the error[E0726]: implicit elided lifetime not allowed here error was indeed related to the issue. I had added a lifetime to the struct but failed to account for it in the code that used the struct. I assumed it did not matter to my error . After fixing this, the error disappeared.