From 8dd607057473ab3b43dd5077f0e703dcf4ab5824 Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Fri, 29 Apr 2022 22:08:47 +0200 Subject: [PATCH] Implement `IntoResponse for (Parts | Request<()>, $(impl IntoResponseParts)+, impl IntoResponse)` (#980) * Implement `IntoResponse for (Parts | Request<()>, $(impl IntoResponseParts)+, impl IntoResponse)` Fixes #979 * changelog * docs * changelog ref --- axum-core/CHANGELOG.md | 2 ++ axum-core/src/response/into_response.rs | 41 +++++++++++++++++++++++-- axum/src/docs/response.md | 4 +++ 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/axum-core/CHANGELOG.md b/axum-core/CHANGELOG.md index 268c504d..c4bd4adf 100644 --- a/axum-core/CHANGELOG.md +++ b/axum-core/CHANGELOG.md @@ -10,9 +10,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **added:** Implement `IntoResponse` and `IntoResponseParts` for `http::Extensions` ([#975]) - **added:** Implement `IntoResponse` for `(http::response::Parts, impl IntoResponse)` ([#950]) - **added:** Implement `IntoResponse` for `(http::response::Response<()>, impl IntoResponse)` ([#950]) +- **added:** Implement `IntoResponse for (Parts | Request<()>, $(impl IntoResponseParts)+, impl IntoResponse)` ([#980]) [#950]: https://github.com/tokio-rs/axum/pull/950 [#975]: https://github.com/tokio-rs/axum/pull/975 +[#980]: https://github.com/tokio-rs/axum/pull/980 # 0.2.3 (25. April, 2022) diff --git a/axum-core/src/response/into_response.rs b/axum-core/src/response/into_response.rs index 23beaa5f..336f2adb 100644 --- a/axum-core/src/response/into_response.rs +++ b/axum-core/src/response/into_response.rs @@ -473,9 +473,44 @@ macro_rules! impl_into_response { }; )* - let mut res = parts.res; - *res.status_mut() = status; - res + (status, parts.res).into_response() + } + } + + #[allow(non_snake_case)] + impl IntoResponse for (http::response::Parts, $($ty),*, R) + where + $( $ty: IntoResponseParts, )* + R: IntoResponse, + { + fn into_response(self) -> Response { + let (outer_parts, $($ty),*, res) = self; + + let res = res.into_response(); + let parts = ResponseParts { res }; + $( + let parts = match $ty.into_response_parts(parts) { + Ok(parts) => parts, + Err(err) => { + return err.into_response(); + } + }; + )* + + (outer_parts, parts.res).into_response() + } + } + + #[allow(non_snake_case)] + impl IntoResponse for (http::response::Response<()>, $($ty),*, R) + where + $( $ty: IntoResponseParts, )* + R: IntoResponse, + { + fn into_response(self) -> Response { + let (template, $($ty),*, res) = self; + let (parts, ()) = template.into_parts(); + (parts, $($ty),*, res).into_response() } } } diff --git a/axum/src/docs/response.md b/axum/src/docs/response.md index 8cf5fb01..270ba7bd 100644 --- a/axum/src/docs/response.md +++ b/axum/src/docs/response.md @@ -149,8 +149,12 @@ async fn all_the_things(uri: Uri) -> impl IntoResponse { In general you can return tuples like: - `(StatusCode, impl IntoResponse)` +- `(Parts, impl IntoResponse)` +- `(Response<()>, impl IntoResponse)` - `(T1, .., Tn, impl IntoResponse)` where `T1` to `Tn` all implement [`IntoResponseParts`]. - `(StatusCode, T1, .., Tn, impl IntoResponse)` where `T1` to `Tn` all implement [`IntoResponseParts`]. +- `(Parts, T1, .., Tn, impl IntoResponse)` where `T1` to `Tn` all implement [`IntoResponseParts`]. +- `(Response<()>, T1, .., Tn, impl IntoResponse)` where `T1` to `Tn` all implement [`IntoResponseParts`]. This means you cannot accidentally override the status or body as [`IntoResponseParts`] only allows setting headers and extensions.