Lifetime problems when borrowing in async stream

Hello,

I'm developing a website status monitor in Rust, but came across a problem with lifetimes. It's reproduced in this Rust Playground:

use reqwest::r#async::Client;
use serde::Deserialize;
use tokio::prelude::*;

fn main() {
    let input = r#"{"sites":["http://rust-lang.org/"]}"#.to_owned();
    let config: RequestConfig = serde_json::from_str(&input).unwrap();
    let fetch = future::join_all(
        config
            .sites
            .into_iter()
            .map(|website| Client::new().get(website).send()),
    )
    .map(|r| println!("Success {}", r.len()))
    .map_err(|err| println!("Error {}", err));
    tokio::run(fetch);
}

#[derive(Debug, PartialEq, Deserialize)]
struct RequestConfig<'a> {
    #[serde(borrow)]
    sites: Vec<&'a str>,
}

To deserialize &'a str, I followed the guide at Deserializer lifetimes · Serde. And tokio::run() requires the future to be 'static (/tokio/issues/431). It seems to me that lifetime of input propagates to config and fetch, because it's borrowed in the async stream.

Error:

   Compiling playground v0.0.1 (/playground)
error[E0597]: `input` does not live long enough
  --> src/main.rs:7:54
   |
7  |     let config: RequestConfig = serde_json::from_str(&input).unwrap();
   |                                 ---------------------^^^^^^-
   |                                 |                    |
   |                                 |                    borrowed value does not live long enough
   |                                 argument requires that `input` is borrowed for `'static`
...
17 | }
   | - `input` dropped here while still borrowed

How should I change my code to satisfy rustc?

1 Like

See the section of that page about Transient, borrowed, and owned data. You have the choice of borrowing the data from input, or creating an owned copy that will live as long as you need.

If you ask serde to fill in some Strings, you get owned data which you can move into the 'static closures that tokio requires.

#[derive(Debug, PartialEq, Deserialize)]
struct RequestConfig {
    sites: Vec<String>,
}

(Note that now &website must be used for reqwest)

I don't think a zero-copy approach is possible in this case, but I'd like to be proven wrong!

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.