diff --git a/CHANGES.md b/CHANGES.md index 805030dfb..a82d0eddc 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,11 +7,14 @@ ### Changed - `HttpResponse` can now be used as a `Responder` with any body type. [#2567] +- `Result` extractor wrapper can now convert error types. [#2581] +- Associated types in `FromRequest` impl for `Option` and `Result` has changed. [#2581] - Maximim number of extractors has changed from 10 to 12. [#2582] [#1988]: https://github.com/actix/actix-web/pull/1988 [#2567]: https://github.com/actix/actix-web/pull/2567 [#2569]: https://github.com/actix/actix-web/pull/2569 +[#2581]: https://github.com/actix/actix-web/pull/2581 [#2582]: https://github.com/actix/actix-web/pull/2582 diff --git a/src/extract.rs b/src/extract.rs index de1cdde0c..f16c29ca5 100644 --- a/src/extract.rs +++ b/src/extract.rs @@ -3,6 +3,7 @@ use std::{ convert::Infallible, future::Future, + marker::PhantomData, pin::Pin, task::{Context, Poll}, }; @@ -124,12 +125,11 @@ pub trait FromRequest: Sized { /// ); /// } /// ``` -impl FromRequest for Option +impl FromRequest for Option where T: FromRequest, - T::Future: 'static, { - type Error = Error; + type Error = Infallible; type Future = FromRequestOptFuture; #[inline] @@ -152,7 +152,7 @@ where Fut: Future>, E: Into, { - type Output = Result, Error>; + type Output = Result, Infallible>; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let this = self.project(); @@ -211,40 +211,42 @@ where /// ); /// } /// ``` -impl FromRequest for Result +impl FromRequest for Result where - T: FromRequest + 'static, - T::Error: 'static, - T::Future: 'static, + T: FromRequest, + T::Error: Into, { - type Error = Error; - type Future = FromRequestResFuture; + type Error = Infallible; + type Future = FromRequestResFuture; #[inline] fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future { FromRequestResFuture { fut: T::from_request(req, payload), + _phantom: PhantomData, } } } pin_project! { - pub struct FromRequestResFuture { + pub struct FromRequestResFuture { #[pin] fut: Fut, + _phantom: PhantomData, } } -impl Future for FromRequestResFuture +impl Future for FromRequestResFuture where - Fut: Future>, + Fut: Future>, + Ei: Into, { - type Output = Result, Error>; + type Output = Result, Infallible>; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let this = self.project(); let res = ready!(this.fut.poll(cx)); - Poll::Ready(Ok(res)) + Poll::Ready(Ok(res.map_err(Into::into))) } } @@ -481,7 +483,14 @@ mod tests { .set_payload(Bytes::from_static(b"bye=world")) .to_http_parts(); - let r = Result::, Error>::from_request(&req, &mut pl) + struct MyError; + impl From for MyError { + fn from(_: Error) -> Self { + Self + } + } + + let r = Result::, MyError>::from_request(&req, &mut pl) .await .unwrap(); assert!(r.is_err());