remove response future impl

This commit is contained in:
Rob Ede 2021-05-09 02:56:05 +01:00
parent a1e6f10a8d
commit ce40201ab5
No known key found for this signature in database
GPG Key ID: 97C636207D3EF933
6 changed files with 65 additions and 93 deletions

View File

@ -19,6 +19,7 @@
* Stop re-exporting `http` crate's `HeaderMap` types in addition to ours. [#2171] * Stop re-exporting `http` crate's `HeaderMap` types in addition to ours. [#2171]
* Down-casting for `MessageBody` types. [#2183] * Down-casting for `MessageBody` types. [#2183]
* `error::Result` alias. [#2201] * `error::Result` alias. [#2201]
* `impl Future` for `Response`. [#2201]
[#2171]: https://github.com/actix/actix-web/pull/2171 [#2171]: https://github.com/actix/actix-web/pull/2171
[#2183]: https://github.com/actix/actix-web/pull/2183 [#2183]: https://github.com/actix/actix-web/pull/2183

View File

@ -293,14 +293,14 @@ impl ResponseHead {
} }
} }
#[inline]
/// Check if keep-alive is enabled /// Check if keep-alive is enabled
#[inline]
pub fn keep_alive(&self) -> bool { pub fn keep_alive(&self) -> bool {
self.connection_type() == ConnectionType::KeepAlive self.connection_type() == ConnectionType::KeepAlive
} }
#[inline]
/// Check upgrade status of this message /// Check upgrade status of this message
#[inline]
pub fn upgrade(&self) -> bool { pub fn upgrade(&self) -> bool {
self.connection_type() == ConnectionType::Upgrade self.connection_type() == ConnectionType::Upgrade
} }

View File

@ -19,22 +19,22 @@ use crate::{
/// An HTTP response. /// An HTTP response.
pub struct Response<B> { pub struct Response<B> {
pub(crate) head: BoxedResponseHead, pub(crate) head: BoxedResponseHead,
pub(crate) body: Option<B>, pub(crate) body: B,
pub(crate) error: Option<Error>, pub(crate) error: Option<Error>,
} }
impl Response<Body> { impl Response<Body> {
/// Constructs a response /// Constructs a new response with default body.
#[inline] #[inline]
pub fn new(status: StatusCode) -> Response<Body> { pub fn new(status: StatusCode) -> Response<Body> {
Response { Response {
head: BoxedResponseHead::new(status), head: BoxedResponseHead::new(status),
body: Some(Body::Empty), body: Body::Empty,
error: None, error: None,
} }
} }
/// Create HTTP response builder with specific status. /// Constructs a new response builder.
#[inline] #[inline]
pub fn build(status: StatusCode) -> ResponseBuilder { pub fn build(status: StatusCode) -> ResponseBuilder {
ResponseBuilder::new(status) ResponseBuilder::new(status)
@ -43,25 +43,25 @@ impl Response<Body> {
// just a couple frequently used shortcuts // just a couple frequently used shortcuts
// this list should not grow larger than a few // this list should not grow larger than a few
/// Creates a new response with status 200 OK. /// Constructs a new response with status 200 OK.
#[inline] #[inline]
pub fn ok() -> Response<Body> { pub fn ok() -> Response<Body> {
Response::new(StatusCode::OK) Response::new(StatusCode::OK)
} }
/// Creates a new response with status 400 Bad Request. /// Constructs a new response with status 400 Bad Request.
#[inline] #[inline]
pub fn bad_request() -> Response<Body> { pub fn bad_request() -> Response<Body> {
Response::new(StatusCode::BAD_REQUEST) Response::new(StatusCode::BAD_REQUEST)
} }
/// Creates a new response with status 404 Not Found. /// Constructs a new response with status 404 Not Found.
#[inline] #[inline]
pub fn not_found() -> Response<Body> { pub fn not_found() -> Response<Body> {
Response::new(StatusCode::NOT_FOUND) Response::new(StatusCode::NOT_FOUND)
} }
/// Creates a new response with status 500 Internal Server Error. /// Constructs a new response with status 500 Internal Server Error.
#[inline] #[inline]
pub fn internal_server_error() -> Response<Body> { pub fn internal_server_error() -> Response<Body> {
Response::new(StatusCode::INTERNAL_SERVER_ERROR) Response::new(StatusCode::INTERNAL_SERVER_ERROR)
@ -69,7 +69,7 @@ impl Response<Body> {
// end shortcuts // end shortcuts
/// Constructs an error response /// Constructs a new response from an error.
#[inline] #[inline]
pub fn from_error(error: Error) -> Response<Body> { pub fn from_error(error: Error) -> Response<Body> {
let mut resp = error.as_response_error().error_response(); let mut resp = error.as_response_error().error_response();
@ -82,146 +82,139 @@ impl Response<Body> {
} }
impl<B> Response<B> { impl<B> Response<B> {
/// Constructs a response with body /// Constructs a new response with given body.
#[inline] #[inline]
pub fn with_body(status: StatusCode, body: B) -> Response<B> { pub fn with_body(status: StatusCode, body: B) -> Response<B> {
Response { Response {
head: BoxedResponseHead::new(status), head: BoxedResponseHead::new(status),
body: Some(body), body: body,
error: None, error: None,
} }
} }
/// Return a reference to the head of this response.
#[inline] #[inline]
/// Http message part of the response
pub fn head(&self) -> &ResponseHead { pub fn head(&self) -> &ResponseHead {
&*self.head &*self.head
} }
/// Return a mutable reference to the head of this response.
#[inline] #[inline]
/// Mutable reference to a HTTP message part of the response
pub fn head_mut(&mut self) -> &mut ResponseHead { pub fn head_mut(&mut self) -> &mut ResponseHead {
&mut *self.head &mut *self.head
} }
/// The source `error` for this response /// Return the source `error` for this response, if one is set.
#[inline] #[inline]
pub fn error(&self) -> Option<&Error> { pub fn error(&self) -> Option<&Error> {
self.error.as_ref() self.error.as_ref()
} }
/// Get the response status code /// Return the status code of this response.
#[inline] #[inline]
pub fn status(&self) -> StatusCode { pub fn status(&self) -> StatusCode {
self.head.status self.head.status
} }
/// Set the `StatusCode` for this response /// Returns a mutable reference the status code of this response.
#[inline] #[inline]
pub fn status_mut(&mut self) -> &mut StatusCode { pub fn status_mut(&mut self) -> &mut StatusCode {
&mut self.head.status &mut self.head.status
} }
/// Get the headers from the response /// Returns a reference to response headers.
#[inline] #[inline]
pub fn headers(&self) -> &HeaderMap { pub fn headers(&self) -> &HeaderMap {
&self.head.headers &self.head.headers
} }
/// Get a mutable reference to the headers /// Returns a mutable reference to response headers.
#[inline] #[inline]
pub fn headers_mut(&mut self) -> &mut HeaderMap { pub fn headers_mut(&mut self) -> &mut HeaderMap {
&mut self.head.headers &mut self.head.headers
} }
/// Connection upgrade status /// Returns true if connection upgrade is enabled.
#[inline] #[inline]
pub fn upgrade(&self) -> bool { pub fn upgrade(&self) -> bool {
self.head.upgrade() self.head.upgrade()
} }
/// Keep-alive status for this connection /// Returns true if keep-alive is enabled.
pub fn keep_alive(&self) -> bool { pub fn keep_alive(&self) -> bool {
self.head.keep_alive() self.head.keep_alive()
} }
/// Responses extensions /// Returns a reference to the extensions of this response.
#[inline] #[inline]
pub fn extensions(&self) -> Ref<'_, Extensions> { pub fn extensions(&self) -> Ref<'_, Extensions> {
self.head.extensions.borrow() self.head.extensions.borrow()
} }
/// Mutable reference to a the response's extensions /// Returns a mutable reference to the extensions of this response.
#[inline] #[inline]
pub fn extensions_mut(&mut self) -> RefMut<'_, Extensions> { pub fn extensions_mut(&mut self) -> RefMut<'_, Extensions> {
self.head.extensions.borrow_mut() self.head.extensions.borrow_mut()
} }
/// Get body of this response /// Returns a reference to the body of this response.
#[inline] #[inline]
pub fn body(&self) -> &B { pub fn body(&self) -> &B {
self.body.as_ref().unwrap() &self.body
} }
/// Set a body /// Sets new body.
pub fn set_body<B2>(self, body: B2) -> Response<B2> { pub fn set_body<B2>(self, body: B2) -> Response<B2> {
Response { Response {
head: self.head, head: self.head,
body: Some(body), body,
error: None, error: None,
} }
} }
/// Split response and body /// Drops body and returns new response.
pub fn into_parts(self) -> (Response<()>, B) {
(
Response {
head: self.head,
body: Some(()),
error: self.error,
},
self.body.unwrap(),
)
}
/// Drop request's body
pub fn drop_body(self) -> Response<()> { pub fn drop_body(self) -> Response<()> {
Response { self.set_body(())
head: self.head,
body: Some(()),
error: None,
}
} }
/// Set a body and return previous body value /// Sets new body, returning new response and previous body value.
pub(crate) fn replace_body<B2>(self, body: B2) -> (Response<B2>, B) { pub(crate) fn replace_body<B2>(self, body: B2) -> (Response<B2>, B) {
( (
Response { Response {
head: self.head, head: self.head,
body: Some(body), body,
error: self.error, error: self.error,
}, },
self.body.unwrap(), self.body,
) )
} }
/// Set a body and return previous body value /// Returns split head and body.
///
/// # Implementation Notes
/// Due to internal performance optimisations, the first element of the returned tuple is a
/// `Response` as well but only contains the head of the response this was called on.
pub fn into_parts(self) -> (Response<()>, B) {
self.replace_body(())
}
/// Returns new response with mapped body.
pub fn map_body<F, B2>(mut self, f: F) -> Response<B2> pub fn map_body<F, B2>(mut self, f: F) -> Response<B2>
where where
F: FnOnce(&mut ResponseHead, B) -> B2, F: FnOnce(&mut ResponseHead, B) -> B2,
{ {
let body = f(&mut self.head, self.body.unwrap()); let body = f(&mut self.head, self.body);
Response { Response {
head: self.head, head: self.head,
body: Some(body), body,
error: self.error, error: self.error,
} }
} }
/// Extract response body /// Returns body, consuming this response.
pub fn into_body(self) -> B { pub fn into_body(self) -> B {
self.body.unwrap() self.body
} }
} }
@ -242,7 +235,7 @@ where
for (key, val) in self.head.headers.iter() { for (key, val) in self.head.headers.iter() {
let _ = writeln!(f, " {:?}: {:?}", key, val); let _ = writeln!(f, " {:?}: {:?}", key, val);
} }
let _ = writeln!(f, " body: {:?}", self.body.as_ref().unwrap().size()); let _ = writeln!(f, " body: {:?}", self.body.size());
res res
} }
} }
@ -254,31 +247,6 @@ impl<B: Default> Default for Response<B> {
} }
} }
mod fut {
use std::{
convert::Infallible,
future::Future,
pin::Pin,
task::{Context, Poll},
};
use super::*;
// TODO: document why this is needed
impl<B: Unpin> Future for Response<B> {
type Output = Result<Response<B>, Infallible>;
fn poll(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> {
Poll::Ready(Ok(Response {
head: self.head.take(),
body: self.body.take(),
error: self.error.take(),
}))
}
}
}
/// Helper converters
impl<I: Into<Response<Body>>, E: Into<Error>> From<Result<I, E>> for Response<Body> { impl<I: Into<Response<Body>>, E: Into<Error>> From<Result<I, E>> for Response<Body> {
fn from(res: Result<I, E>) -> Self { fn from(res: Result<I, E>) -> Self {
match res { match res {

View File

@ -254,7 +254,7 @@ impl ResponseBuilder {
Ok(Response { Ok(Response {
head: response, head: response,
body: Some(body), body,
error: None, error: None,
}) })
} }

View File

@ -2,6 +2,7 @@ use std::{
cell::{Ref, RefMut}, cell::{Ref, RefMut},
fmt, fmt,
future::Future, future::Future,
mem,
pin::Pin, pin::Pin,
task::{Context, Poll}, task::{Context, Poll},
}; };
@ -11,7 +12,6 @@ use actix_http::{
http::{header::HeaderMap, StatusCode}, http::{header::HeaderMap, StatusCode},
Extensions, Response, ResponseHead, Extensions, Response, ResponseHead,
}; };
use futures_core::ready;
#[cfg(feature = "cookies")] #[cfg(feature = "cookies")]
use { use {
@ -278,21 +278,24 @@ impl<B> From<HttpResponse<B>> for Response<B> {
} }
} }
impl<B: Unpin> Future for HttpResponse<B> { // Future is only implemented for Body payload type because it's the most useful for making simple
type Output = Result<Response<B>, Error>; // handlers without async blocks. Making it generic over all MessageBody types requires a future
// impl on Response which would cause it's body field to be, undesirably, Option<B>.
//
// This impl is not particularly efficient due to the Response construction and should probably
// not be invoked if performance is important. Prefer an async fn/block in such cases.
impl Future for HttpResponse<Body> {
type Output = Result<Response<Body>, Error>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { fn poll(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> {
if let Some(err) = self.error.take() { if let Some(err) = self.error.take() {
return Poll::Ready(Err(err)); return Poll::Ready(Err(err));
} }
let res = &mut self.res; Poll::Ready(Ok(mem::replace(
actix_rt::pin!(res); &mut self.res,
Response::new(StatusCode::default()),
match ready!(res.poll(cx)) { )))
Ok(val) => Poll::Ready(Ok(val)),
Err(err) => Poll::Ready(Err(err.into())),
}
} }
} }

View File

@ -901,7 +901,7 @@ async fn test_normalize() {
let srv = actix_test::start_with(actix_test::config().h1(), || { let srv = actix_test::start_with(actix_test::config().h1(), || {
App::new() App::new()
.wrap(NormalizePath::new(TrailingSlash::Trim)) .wrap(NormalizePath::new(TrailingSlash::Trim))
.service(web::resource("/one").route(web::to(|| HttpResponse::Ok().finish()))) .service(web::resource("/one").route(web::to(|| HttpResponse::Ok())))
}); });
let response = srv.get("/one/").send().await.unwrap(); let response = srv.get("/one/").send().await.unwrap();