Hi,
I have this small project Cargo.toml:
[package]
name = "example"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
anyhow = "1.0.28"
thiserror = "1.0.15"
warp = { version = "0.2.2", features = ["tls"] }
tokio = { version = "0.2.18", features = ["full"]}
serde_derive = "1.0.106"
serde = { version = "1.0.106", features = ["derive"] }
and this main.rs
:
use std::{collections::HashMap, convert::From, convert::Infallible, fmt::Display};
use anyhow::Result;
use serde::Serialize;
use thiserror::Error;
use tokio;
use warp::{http::StatusCode, reject::Reject, Filter, Rejection, Reply};
#[derive(Clone)]
struct Config {}
#[tokio::main]
async fn main() -> Result<()> {
let cfg = Arc::new(Config {});
let (get_cfg, post_cfg) = (cfg.clone(), cfg.clone());
let get_fct1 = warp::path("fct1").and(warp::query()).and_then(
|params: HashMap<String, String>| async move {
let cfg = get_cfg.clone();
fct1(&cfg, params)
.and_then(|response| Ok(response))
.or_else(|e| Err(warp::reject::custom::<ServerError>(e.into())))
},
);
let post_fct1 = warp::path("fct1")
.and(warp::path::end())
.and(warp::body::form())
.and_then(|params: HashMap<String, String>| async move {
let cfg = post_cfg.clone();
fct1(&cfg, params)
.and_then(|response| Ok(response))
.or_else(|e| Err(warp::reject::custom::<ServerError>(e.into())))
});
let get_routes = warp::get().and(get_fct1);
let post_routes = warp::post().and(post_fct1);
let routes = get_routes.or(post_routes).recover(customize_error);
warp::serve(routes).run(([127, 0, 0, 1], 4321)).await;
Ok(())
}
fn fct1(cfg: &Config, p: HashMap<String, String>) -> Result<impl Reply> {
Ok(warp::reply())
}
async fn customize_error(err: Rejection) -> Result<impl Reply, Infallible> {
let code;
let message;
if let Some(server_error) = err.find::<ServerError>() {
code = StatusCode::INTERNAL_SERVER_ERROR;
message = server_error.msg.to_owned();
} else {
code = StatusCode::INTERNAL_SERVER_ERROR;
message = "UNHANDLED_REJECTION".to_string();
}
Ok(warp::reply::with_status(message, code))
}
#[derive(Debug, Clone, Error, Serialize, PartialEq)]
pub struct ServerError {
#[serde(skip)]
pub status: StatusCode,
pub msg: String,
}
impl Reject for ServerError {}
impl Display for ServerError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{} ({})", self.msg, self.status)
}
}
impl ServerError {
pub fn new(status: StatusCode, msg: &str) -> Self {
ServerError {
status,
msg: msg.to_owned(),
}
}
}
impl From<anyhow::Error> for ServerError {
fn from(err: anyhow::Error) -> Self {
let e = match err.downcast::<ServerError>() {
Ok(e) => return e,
Err(e) => e,
};
ServerError::new(
StatusCode::INTERNAL_SERVER_ERROR,
&format!("Unhandled error type: {:#?}", e),
)
}
}
I'm trying to do is to pass my Config
object to fct1
but it gives me these errors:
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
--> src\main.rs:19:9
|
18 | let get_fct1 = warp::path("fct1").and(warp::query()).and_then(
| -------- the requirement to implement `Fn` derives from here
19 | |params: HashMap<String, String>| async move {
| _________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^_-
| | |
| | this closure implements `FnOnce`, not `Fn`
20 | | let cfg = get_cfg.clone();
21 | | fct1(&cfg, params)
22 | | .and_then(|response| Ok(response))
23 | | .or_else(|e| Err(warp::reject::custom::<ServerError>(e.into())))
24 | | },
| |_________- closure is `FnOnce` because it moves the variable `get_cfg` out of its environment
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
--> src\main.rs:30:19
|
30 | .and_then(|params: HashMap<String, String>| async move {
| __________--------_^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^_-
| | | |
| | | this closure implements `FnOnce`, not `Fn`
| | the requirement to implement `Fn` derives from here
31 | | let cfg = post_cfg.clone();
32 | | fct1(&cfg, params)
33 | | .and_then(|response| Ok(response))
34 | | .or_else(|e| Err(warp::reject::custom::<ServerError>(e.into())))
35 | | });
| |_________- closure is `FnOnce` because it moves the variable `post_cfg` out of its environment
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
--> src\main.rs:19:9
|
19 | |params: HashMap<String, String>| async move {
| _________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^_-
| | |
| | this closure implements `FnOnce`, not `Fn`
20 | | let cfg = get_cfg.clone();
21 | | fct1(&cfg, params)
22 | | .and_then(|response| Ok(response))
23 | | .or_else(|e| Err(warp::reject::custom::<ServerError>(e.into())))
24 | | },
| |_________- closure is `FnOnce` because it moves the variable `get_cfg` out of its environment
...
37 | let get_routes = warp::get().and(get_fct1);
| --- the requirement to implement `Fn` derives from here
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
--> src\main.rs:30:19
|
30 | .and_then(|params: HashMap<String, String>| async move {
| ___________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^_-
| | |
| | this closure implements `FnOnce`, not `Fn`
31 | | let cfg = post_cfg.clone();
32 | | fct1(&cfg, params)
33 | | .and_then(|response| Ok(response))
34 | | .or_else(|e| Err(warp::reject::custom::<ServerError>(e.into())))
35 | | });
| |_________- closure is `FnOnce` because it moves the variable `post_cfg` out of its environment
...
38 | let post_routes = warp::post().and(post_fct1);
| --- the requirement to implement `Fn` derives from here
error: aborting due to 4 previous errors
How am I suppose to pass Config
to the endpoints' function?
(question also posted on reddit)