Reputation: 463
I've got the following code:
use actix_service::Service;
use actix_web::{web, App, HttpServer, Responder};
use actix_router::{Path, Url};
use actix_web::dev::{ServiceRequest, ServiceResponse};
use actix_web::error::ResponseError;
use actix_web::{http, http::StatusCode, Error, HttpRequest, HttpResponse};
async fn greet(req: HttpRequest) -> impl Responder {
let name = req.match_info().get("name").unwrap_or("World");
format!("Hello {}!", &name)
}
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
let app = App::new()
.wrap_fn(|req, srv| {
let passed: bool;
// change to false to simulate a failed check
let check = true;
if *&req.path().contains("/item/") {
passed = check;
} else {
passed = true;
}
let fresh_result = match passed {
true => {
let fut = srv.call(req);
Box::pin(async {
let result = fut.await?;
Ok(result)
})
}
false => Box::pin(async {
let result = req.into_response(
HttpResponse::Found()
.header(http::header::LOCATION, "/login")
.finish()
.into_body(),
);
Ok(result)
}),
};
async {
let last_outcome = fresh_result.await?;
Ok(last_outcome)
}
})
.route("/", web::get().to(greet));
return app;
})
.bind("127.0.0.1:8000")?
.run()
.await
}
However, I get the following error:
110 | let fresh_result = match passed {
| ________________________________________-
111 | | true => {
112 | | let fut = srv.call(req);
113 | | Box::pin(
| _|_____________________________-
114 | | | async {
115 | | | let result = fut.await?;
116 | | | Ok(result)
117 | | | }
118 | | | )
| |_|_____________________________- this is found to be of type `std::pin::Pin<std::boxed::Box<impl core::future::future::Future>>`
... |
121 | / | Box::pin(
122 | | | async {
123 | | | let result = req.into_response(
124 | | | HttpResponse::Found()
... | |
129 | | | }
130 | | | )
| |_|_____________________________^ expected generator, found a different generator
131 | | }
132 | | };
| |_____________________- `match` arms have incompatible types
|
::: /Users/maxwellflitton/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/src/libcore/future/mod.rs:55:43
|
55 | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
| ------------------------------- the found opaque type
|
= note: expected type `std::pin::Pin<std::boxed::Box<impl core::future::future::Future>>` (generator)
found struct `std::pin::Pin<std::boxed::Box<impl core::future::future::Future>>` (generator)
I am completely stuck on this. I don't know how to ensure it's a type. If there is no match statement and there is just one async block then it all runs fine. This is for middleware in an Actix-web server. I am trying to redirect the viewer if credentials are not working.
Upvotes: 0
Views: 1535
Reputation: 2618
You use Box::pin
to create the boxed futures,
but Rust still thinks you want the impl Future<...>
version (meaning the future is boxed to the heap, but doesn't use dynamic dispatch).
This is why the type in the error is Pin<Box<impl Future<...>>>
, and because any two impl Future<...>
s are of different types, you get the expected/found
error.
You need to tell Rust you are interested in dynamic dispatch (because you have two different futures that can be stored in the Box
, and which one really is stored there can only be known at runtime), for example by explicitly specifying the return type like this:
use std::pin::Pin;
use std::future::Future;
let fresh_result: Pin<Box<dyn Future<Output=_>>> = match passed {
// ...
}
Now you will get a new error about cannot infer type for type parameter E
which can be resolved by specifying the Output
of the future as well,
so the new line should be:
let fresh_result: Pin<Box<dyn Future<Output=Result<ServiceResponse, Error>>>> = match passed {
// ...
}
which will compile successfully!
Upvotes: 1