I am trying to pass a DB (hashmap) as a parameter of a handler's method to make a custom Warp filters.
But, I encounter an error I can't figure out, I think it's something about Arc<RwLock>'s lifetime, but it's kinda weird since it's declared in the same scope as the handler. Here is the error:
error: lifetime may not live long enough
--> src/main.rs:32:29
|
32 | .and_then(move |db| handler.method1(db))
| --------- ^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
| | |
| | return type of closure `impl Future<Output = Result<impl Reply, Rejection>>` contains a lifetime `'2`
| lifetime `'1` represents this closure's body
|
= note: closure implements `Fn`, so references to captured variables can't escape the closure
error: lifetime may not live long enough
--> src/main.rs:43:36
|
43 | .and_then(move |db, query| handler.method2(db, query))
| ---------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
| | |
| | return type of closure `impl Future<Output = Result<impl Reply, Rejection>>` contains a lifetime `'2`
| lifetime `'1` represents this closure's body
|
= note: closure implements `Fn`, so references to captured variables can't escape the closure
I wrote this sample from my actual code if you want to reproduce the error:
use serde::Deserialize;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
use warp::Filter;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let db = Arc::new(RwLock::new(HashMap::new()));
let handler = Handler::new().await?;
let routes = filter1(db.clone(), handler.clone()).or(filter2(db, handler));
warp::serve(routes).run(([127, 0, 0, 1], 8080)).await;
Ok(())
}
pub type Db = Arc<RwLock<HashMap<String, (String, String)>>>;
pub fn with_db(db: Db) -> impl Filter<Extract = (Db,), Error = std::convert::Infallible> + Clone {
warp::any().map(move || db.clone())
}
pub fn filter1(
db: Db,
handler: Handler,
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
warp::path("1")
.and(warp::get())
.and(with_db(db.clone()))
.and_then(move |db| handler.method1(db))
}
pub fn filter2(
db: Db,
handler: Handler,
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
warp::path("2")
.and(warp::get())
.and(with_db(db.clone()))
.and(warp::query::query::<Query>())
.and_then(move |db, query| handler.method2(db, query))
}
#[derive(Deserialize, Debug, Clone, PartialEq)]
pub struct Query {
pub field1: String,
pub field2: u8,
//...
}
#[derive(Clone)]
pub struct Handler {
// ...
}
impl Handler {
pub async fn new() -> Result<Self, Box<dyn std::error::Error>> {
// ...
Ok(Self {
// ...
})
}
pub async fn method1(&self, db: Db) -> Result<impl warp::Reply, warp::Rejection> {
/*
SOME CODE
*/
db.write().await.insert(
"Name1".to_string(),
("Val1".to_string(), "Val2".to_string()),
);
/*
SOME CODE
*/
let dummy_response = vec![1, 3, 7, 13];
Ok(warp::reply::with_status(
warp::reply::json(&dummy_response),
warp::http::StatusCode::OK,
))
}
/// Once the user has been redirected to the callback URL, we get access to their authorization code.
pub async fn method2(&self, db: Db, query: Query) -> Result<impl warp::Reply, warp::Rejection> {
/*
SOME CODE
*/
let val = db.write().await.remove("Name1");
/*
SOME CODE
*/
let dummy_response = vec![1, 3, 7, 13];
Ok(warp::reply::with_status(
warp::reply::json(&dummy_response),
warp::http::StatusCode::OK,
))
}
}
Thank you in advance for your help!