Skip to content

Commit b5c534d

Browse files
committed
support both FromRequest and FromRequestParts in Either
1 parent b7f815f commit b5c534d

File tree

3 files changed

+45
-28
lines changed

3 files changed

+45
-28
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

axum-extra/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ http = "1.0.0"
5757
http-body = "1.0.0"
5858
http-body-util = "0.1.0"
5959
mime = "0.3"
60+
paste = "1.0"
6061
pin-project-lite = "0.2"
6162
rustversion = "1.0.9"
6263
serde = "1.0"

axum-extra/src/either.rs

Lines changed: 43 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -134,13 +134,14 @@ use axum::{
134134
};
135135
use bytes::Bytes;
136136
use http::request::Parts;
137+
use paste::paste;
137138
use tower_layer::Layer;
138139
use tower_service::Service;
139140

140141
/// Combines two extractors or responses into a single type.
141142
///
142143
/// See the [module docs](self) for examples.
143-
#[derive(Debug, Clone)]
144+
#[derive(Debug, Clone, PartialEq, Eq)]
144145
#[must_use]
145146
pub enum Either<E1, E2> {
146147
#[allow(missing_docs)]
@@ -310,39 +311,41 @@ macro_rules! impl_traits_for_either {
310311
}
311312
}
312313

313-
impl<S, $($ident),*, $last> FromRequest<S> for $either<$($ident),*, $last>
314-
where
315-
S: Send + Sync,
316-
$($ident: FromRequest<S>),*,
317-
$last: FromRequest<S>,
318-
$($ident::Rejection: Send),*,
319-
$last::Rejection: IntoResponse + Send,
320-
{
321-
type Rejection = EitherRejection<$last::Rejection>;
322-
323-
async fn from_request(req: Request, state: &S) -> Result<Self, Self::Rejection> {
324-
let (parts, body) = req.into_parts();
325-
let bytes = Bytes::from_request(Request::from_parts(parts.clone(), body), state)
326-
.await
327-
.map_err(EitherRejection::Bytes)?;
314+
paste! {
315+
impl<S, $($ident),*, $last, $([< $ident Via >]),*, [<$last Via>]> FromRequest<S, ($([< $ident Via >]),*, [<$last Via>])> for $either<$($ident),*, $last>
316+
where
317+
S: Send + Sync,
318+
$($ident: FromRequest<S, [<$ident Via>]>),*,
319+
$last: FromRequest<S, [<$last Via>]>,
320+
$($ident::Rejection: Send),*,
321+
$last::Rejection: IntoResponse + Send,
322+
{
323+
type Rejection = EitherRejection<$last::Rejection>;
324+
325+
async fn from_request(req: Request, state: &S) -> Result<Self, Self::Rejection> {
326+
let (parts, body) = req.into_parts();
327+
let bytes = Bytes::from_request(Request::from_parts(parts.clone(), body), state)
328+
.await
329+
.map_err(EitherRejection::Bytes)?;
330+
331+
$(
332+
let req = Request::from_parts(
333+
parts.clone(),
334+
axum::body::Body::new(http_body_util::Full::new(bytes.clone())),
335+
);
336+
if let Ok(extracted) = $ident::from_request(req, state).await {
337+
return Ok(Self::$ident(extracted));
338+
}
339+
)*
328340

329-
$(
330341
let req = Request::from_parts(
331342
parts.clone(),
332343
axum::body::Body::new(http_body_util::Full::new(bytes.clone())),
333344
);
334-
if let Ok(extracted) = $ident::from_request(req, state).await {
335-
return Ok(Self::$ident(extracted));
345+
match $last::from_request(req, state).await {
346+
Ok(extracted) => Ok(Self::$last(extracted)),
347+
Err(error) => Err(EitherRejection::LastRejection(error)),
336348
}
337-
)*
338-
339-
let req = Request::from_parts(
340-
parts.clone(),
341-
axum::body::Body::new(http_body_util::Full::new(bytes.clone())),
342-
);
343-
match $last::from_request(req, state).await {
344-
Ok(extracted) => Ok(Self::$last(extracted)),
345-
Err(error) => Err(EitherRejection::LastRejection(error)),
346349
}
347350
}
348351
}
@@ -421,6 +424,7 @@ mod tests {
421424

422425
use super::*;
423426

427+
#[derive(Debug, PartialEq)]
424428
struct False;
425429

426430
impl<S> FromRequestParts<S> for False {
@@ -471,4 +475,15 @@ mod tests {
471475

472476
assert!(matches!(either, Either3::E3(State(()))));
473477
}
478+
479+
#[tokio::test]
480+
async fn either_from_request_or_parts() {
481+
let request = Request::new(Body::empty());
482+
483+
let either = Either::<False, Bytes>::from_request(request, &())
484+
.await
485+
.unwrap();
486+
487+
assert_eq!(either, Either::E2(Bytes::new()));
488+
}
474489
}

0 commit comments

Comments
 (0)