2

I have 3 filters, if I combine them in order a,c,b, the code compiles. But if I switch their orders like a,b,c, the code won't compile. The filter seems the same to me. Why?

use reqwest::Method;
use serde_json::Value;
use warp::http::{HeaderMap, StatusCode};
use warp::path::FullPath;
use warp::reply::Response;
use std::convert::Infallible;
use warp::{Filter, Reply};

async fn fn_with_params_no_body(method: Method, path: FullPath, headers: HeaderMap, query: String) -> Result<Response, Infallible> {
    Ok(StatusCode::OK.into_response())
}

async fn fn_no_params_no_body(method: Method, path: FullPath, headers: HeaderMap) -> Result<Response, Infallible> {
    Ok(StatusCode::OK.into_response())
}

async fn fn_no_params_with_body(method: Method, path: FullPath, headers: HeaderMap, body: Value) -> Result<Response, Infallible> {
    Ok(StatusCode::OK.into_response())
}

#[tokio::main]
async fn main() {
    let ep0 = warp::any()
        .and(warp::method())
        .and(warp::path::full())
        .and(warp::header::headers_cloned())
        .and(warp::query::raw())
        .and_then(fn_with_params_no_body);

    let ep1 = warp::any()
        .and(warp::method())
        .and(warp::path::full())
        .and(warp::header::headers_cloned())
        .and_then(fn_no_params_no_body);

    let ep2 = warp::any()
        .and(warp::method())
        .and(warp::path::full())
        .and(warp::header::headers_cloned())
        .and(warp::body::json())
        .and_then(fn_no_params_with_body);

    let routes = ep0.or(ep2).or(ep1); // this would compile
    // let routes = ep0.or(ep1).or(ep2); // this won't
    warp::serve(routes)
        .run(([0, 0, 0, 0], 8080))
        .await
}

It says expected struct Rejection, found enum Infallible and or requires Self: Filter<Error = Rejection> + Sized, then why can I compile it after swithcing orders, none of the handle functions returns Result<Response, Reject>

   --> exproxy/src/main.rs:43:30
    |
43  |     let routes = ep0.or(ep1).or(ep2);
    |                              
    |
note: required by a bound in `or`
   --> /Users/ynx/.cargo/registry/src/github.com-1ecc6299db9ec823/warp-0.3.2/src/filter/mod.rs:140:22
    |
140 |         Self: Filter<Error = Rejection> + Sized,
    |                      ^^^^^^^^^^^^^^^^^ required by this bound in `or`
YNX
  • 511
  • 6
  • 17

1 Answers1

0

The error message says it all. When ep1 is called, it ends with fn_with_params_no_body so it returns either Infalliable or Response. In the order that works, first the ep0 is checked, and if the route has parameters, it succeeds and doesn't keep going down the or chain. This means that the numbers after it will be sure that the route has no parameters. When ep2 is reached, it can be sure that the input will have no routes, so it only bothers to check for the body. If it has a body, then it will succeed and stop the chain. Only if it's certain that the route has no route or body, ep1 is run. Since it's the last one, and it's already known that there is no body or route (or else the previous functions would have worked) ep1 is guaranteed to return a Infalliable. Any other order runs the risk of not returning an Infalliable, or as your error happened, passing a value that is already Infalilliable to one of the filters

Esdeseserdt
  • 181
  • 10