From 51d16ad55caf10968b85343ec11af95f3434a13f Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Fri, 19 Aug 2022 22:57:48 +0200 Subject: [PATCH] Port most things in axum-extra --- axum-extra/src/either.rs | 4 +- axum-extra/src/extract/cached.rs | 5 +- axum-extra/src/extract/cookie/mod.rs | 2 +- axum-extra/src/extract/form.rs | 2 +- axum-extra/src/extract/query.rs | 2 +- axum-extra/src/extract/with_rejection.rs | 6 +- axum-extra/src/handler/mod.rs | 408 ++++++++++++----------- axum-extra/src/handler/or.rs | 306 ++++++++--------- axum-extra/src/json_lines.rs | 2 +- axum-extra/src/protobuf.rs | 2 +- 10 files changed, 370 insertions(+), 369 deletions(-) diff --git a/axum-extra/src/either.rs b/axum-extra/src/either.rs index 2aba1cb46e..93c945f9ec 100755 --- a/axum-extra/src/either.rs +++ b/axum-extra/src/either.rs @@ -195,7 +195,7 @@ macro_rules! impl_traits_for_either { where $($ident: FromRequestParts),*, $last: FromRequest, - B: Send, + B: Send + 'static, S: Send + Sync, { type Rejection = $last::Rejection; @@ -225,7 +225,7 @@ macro_rules! impl_traits_for_either { async fn from_request_parts(parts: &mut Parts, state: &S) -> Result { $( - if let Ok(value) = FromRequestParts::from_request_parts(&mut parts, state).await { + if let Ok(value) = FromRequestParts::from_request_parts(parts, state).await { return Ok(Self::$ident(value)); } )* diff --git a/axum-extra/src/extract/cached.rs b/axum-extra/src/extract/cached.rs index 73600a4f85..b0680248cb 100644 --- a/axum-extra/src/extract/cached.rs +++ b/axum-extra/src/extract/cached.rs @@ -100,13 +100,12 @@ where type Rejection = T::Rejection; async fn from_request(req: Request, state: &S) -> Result { - let (mut parts, body) = req.into_parts(); + let (mut parts, _) = req.into_parts(); match Extension::>::from_request_parts(&mut parts, state).await { Ok(Extension(CachedEntry(value))) => Ok(Self(value)), Err(_) => { - let req = Request::from_parts(parts, body); - let value = T::from_request(req, state).await?; + let value = T::from_request_parts(&mut parts, state).await?; parts.extensions.insert(CachedEntry(value.clone())); Ok(Self(value)) } diff --git a/axum-extra/src/extract/cookie/mod.rs b/axum-extra/src/extract/cookie/mod.rs index c7eceb58cd..eefe659eb1 100644 --- a/axum-extra/src/extract/cookie/mod.rs +++ b/axum-extra/src/extract/cookie/mod.rs @@ -95,7 +95,7 @@ where { type Rejection = Infallible; - async fn from_request_parts(parts: &mut Parts, state: &S) -> Result { + async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result { Ok(Self::from_headers(&parts.headers)) } } diff --git a/axum-extra/src/extract/form.rs b/axum-extra/src/extract/form.rs index afc5a7c266..254c7cce41 100644 --- a/axum-extra/src/extract/form.rs +++ b/axum-extra/src/extract/form.rs @@ -58,7 +58,7 @@ impl Deref for Form { impl FromRequest for Form where T: DeserializeOwned, - B: HttpBody + Send, + B: HttpBody + Send + 'static, B::Data: Send, B::Error: Into, S: Send + Sync, diff --git a/axum-extra/src/extract/query.rs b/axum-extra/src/extract/query.rs index 8600efc798..4a8d6f8676 100644 --- a/axum-extra/src/extract/query.rs +++ b/axum-extra/src/extract/query.rs @@ -66,7 +66,7 @@ where { type Rejection = QueryRejection; - async fn from_request_parts(parts: &mut Parts, state: &S) -> Result { + async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result { let query = parts.uri.query().unwrap_or_default(); let value = serde_html_form::from_str(query) .map_err(FailedToDeserializeQueryString::__private_new)?; diff --git a/axum-extra/src/extract/with_rejection.rs b/axum-extra/src/extract/with_rejection.rs index ba12da3333..f3a0f04e87 100644 --- a/axum-extra/src/extract/with_rejection.rs +++ b/axum-extra/src/extract/with_rejection.rs @@ -111,7 +111,7 @@ impl DerefMut for WithRejection { #[async_trait] impl FromRequest for WithRejection where - B: Send, + B: Send + 'static, S: Send + Sync, E: FromRequest, R: From + IntoResponse, @@ -161,8 +161,8 @@ mod tests { type Rejection = (); async fn from_request_parts( - parts: &mut Parts, - state: &S, + _parts: &mut Parts, + _state: &S, ) -> Result { Err(()) } diff --git a/axum-extra/src/handler/mod.rs b/axum-extra/src/handler/mod.rs index ef12f896e9..b5130ae466 100644 --- a/axum-extra/src/handler/mod.rs +++ b/axum-extra/src/handler/mod.rs @@ -1,206 +1,208 @@ //! Additional handler utilities. -use axum::{ - extract::{FromRequest, RequestParts}, - handler::Handler, - response::{IntoResponse, Response}, -}; -use futures_util::future::{BoxFuture, FutureExt, Map}; -use std::{future::Future, marker::PhantomData, sync::Arc}; +// NOTE: bringing this back requires fixing `axum-core/src/extract/tuple.rs` -mod or; - -pub use self::or::Or; - -/// Trait for async functions that can be used to handle requests. -/// -/// This trait is similar to [`Handler`] but rather than taking the request it takes the extracted -/// inputs. -/// -/// The drawbacks of this trait is that you cannot apply middleware to individual handlers like you -/// can with [`Handler::layer`]. -pub trait HandlerCallWithExtractors: Sized { - /// The type of future calling this handler returns. - type Future: Future + Send + 'static; - - /// Call the handler with the extracted inputs. - fn call( - self, - state: Arc, - extractors: T, - ) -> >::Future; - - /// Conver this `HandlerCallWithExtractors` into [`Handler`]. - fn into_handler(self) -> IntoHandler { - IntoHandler { - handler: self, - _marker: PhantomData, - } - } - - /// Chain two handlers together, running the second one if the first one rejects. - /// - /// Note that this only moves to the next handler if an extractor fails. The response from - /// handlers are not considered. - /// - /// # Example - /// - /// ``` - /// use axum_extra::handler::HandlerCallWithExtractors; - /// use axum::{ - /// Router, - /// async_trait, - /// routing::get, - /// extract::FromRequest, - /// }; - /// - /// // handlers for varying levels of access - /// async fn admin(admin: AdminPermissions) { - /// // request came from an admin - /// } - /// - /// async fn user(user: User) { - /// // we have a `User` - /// } - /// - /// async fn guest() { - /// // `AdminPermissions` and `User` failed, so we're just a guest - /// } - /// - /// // extractors for checking permissions - /// struct AdminPermissions {} - /// - /// #[async_trait] - /// impl FromRequest for AdminPermissions - /// where - /// B: Send, - /// S: Send + Sync, - /// { - /// // check for admin permissions... - /// # type Rejection = (); - /// # async fn from_request(req: &mut axum::extract::RequestParts) -> Result { - /// # todo!() - /// # } - /// } - /// - /// struct User {} - /// - /// #[async_trait] - /// impl FromRequest for User - /// where - /// B: Send, - /// S: Send + Sync, - /// { - /// // check for a logged in user... - /// # type Rejection = (); - /// # async fn from_request(req: &mut axum::extract::RequestParts) -> Result { - /// # todo!() - /// # } - /// } - /// - /// let app = Router::new().route( - /// "/users/:id", - /// get( - /// // first try `admin`, if that rejects run `user`, finally falling back - /// // to `guest` - /// admin.or(user).or(guest) - /// ) - /// ); - /// # let _: Router = app; - /// ``` - fn or(self, rhs: R) -> Or - where - R: HandlerCallWithExtractors, - { - Or { - lhs: self, - rhs, - _marker: PhantomData, - } - } -} - -macro_rules! impl_handler_call_with { - ( $($ty:ident),* $(,)? ) => { - #[allow(non_snake_case)] - impl HandlerCallWithExtractors<($($ty,)*), S, B> for F - where - F: FnOnce($($ty,)*) -> Fut, - Fut: Future + Send + 'static, - Fut::Output: IntoResponse, - { - // this puts `futures_util` in our public API but thats fine in axum-extra - type Future = Map Response>; - - fn call( - self, - _state: Arc, - ($($ty,)*): ($($ty,)*), - ) -> >::Future { - self($($ty,)*).map(IntoResponse::into_response) - } - } - }; -} - -impl_handler_call_with!(); -impl_handler_call_with!(T1); -impl_handler_call_with!(T1, T2); -impl_handler_call_with!(T1, T2, T3); -impl_handler_call_with!(T1, T2, T3, T4); -impl_handler_call_with!(T1, T2, T3, T4, T5); -impl_handler_call_with!(T1, T2, T3, T4, T5, T6); -impl_handler_call_with!(T1, T2, T3, T4, T5, T6, T7); -impl_handler_call_with!(T1, T2, T3, T4, T5, T6, T7, T8); -impl_handler_call_with!(T1, T2, T3, T4, T5, T6, T7, T8, T9); -impl_handler_call_with!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10); -impl_handler_call_with!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11); -impl_handler_call_with!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12); -impl_handler_call_with!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13); -impl_handler_call_with!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14); -impl_handler_call_with!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15); -impl_handler_call_with!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16); - -/// A [`Handler`] created from a [`HandlerCallWithExtractors`]. -/// -/// Created with [`HandlerCallWithExtractors::into_handler`]. -#[allow(missing_debug_implementations)] -pub struct IntoHandler { - handler: H, - _marker: PhantomData (T, S, B)>, -} - -impl Handler for IntoHandler -where - H: HandlerCallWithExtractors + Clone + Send + 'static, - T: FromRequest + Send + 'static, - T::Rejection: Send, - B: Send + 'static, - S: Send + Sync + 'static, -{ - type Future = BoxFuture<'static, Response>; - - fn call(self, state: Arc, req: http::Request) -> Self::Future { - Box::pin(async move { - let mut req = RequestParts::with_state_arc(Arc::clone(&state), req); - match req.extract::().await { - Ok(t) => self.handler.call(state, t).await, - Err(rejection) => rejection.into_response(), - } - }) - } -} - -impl Copy for IntoHandler where H: Copy {} - -impl Clone for IntoHandler -where - H: Clone, -{ - fn clone(&self) -> Self { - Self { - handler: self.handler.clone(), - _marker: self._marker, - } - } -} +// use axum::{ +// extract::{FromRequest, RequestParts}, +// handler::Handler, +// response::{IntoResponse, Response}, +// }; +// use futures_util::future::{BoxFuture, FutureExt, Map}; +// use std::{future::Future, marker::PhantomData, sync::Arc}; +// +// mod or; +// +// pub use self::or::Or; +// +// /// Trait for async functions that can be used to handle requests. +// /// +// /// This trait is similar to [`Handler`] but rather than taking the request it takes the extracted +// /// inputs. +// /// +// /// The drawbacks of this trait is that you cannot apply middleware to individual handlers like you +// /// can with [`Handler::layer`]. +// pub trait HandlerCallWithExtractors: Sized { +// /// The type of future calling this handler returns. +// type Future: Future + Send + 'static; +// +// /// Call the handler with the extracted inputs. +// fn call( +// self, +// state: Arc, +// extractors: T, +// ) -> >::Future; +// +// /// Conver this `HandlerCallWithExtractors` into [`Handler`]. +// fn into_handler(self) -> IntoHandler { +// IntoHandler { +// handler: self, +// _marker: PhantomData, +// } +// } +// +// /// Chain two handlers together, running the second one if the first one rejects. +// /// +// /// Note that this only moves to the next handler if an extractor fails. The response from +// /// handlers are not considered. +// /// +// /// # Example +// /// +// /// ``` +// /// use axum_extra::handler::HandlerCallWithExtractors; +// /// use axum::{ +// /// Router, +// /// async_trait, +// /// routing::get, +// /// extract::FromRequest, +// /// }; +// /// +// /// // handlers for varying levels of access +// /// async fn admin(admin: AdminPermissions) { +// /// // request came from an admin +// /// } +// /// +// /// async fn user(user: User) { +// /// // we have a `User` +// /// } +// /// +// /// async fn guest() { +// /// // `AdminPermissions` and `User` failed, so we're just a guest +// /// } +// /// +// /// // extractors for checking permissions +// /// struct AdminPermissions {} +// /// +// /// #[async_trait] +// /// impl FromRequest for AdminPermissions +// /// where +// /// B: Send, +// /// S: Send + Sync, +// /// { +// /// // check for admin permissions... +// /// # type Rejection = (); +// /// # async fn from_request(req: &mut axum::extract::RequestParts) -> Result { +// /// # todo!() +// /// # } +// /// } +// /// +// /// struct User {} +// /// +// /// #[async_trait] +// /// impl FromRequest for User +// /// where +// /// B: Send, +// /// S: Send + Sync, +// /// { +// /// // check for a logged in user... +// /// # type Rejection = (); +// /// # async fn from_request(req: &mut axum::extract::RequestParts) -> Result { +// /// # todo!() +// /// # } +// /// } +// /// +// /// let app = Router::new().route( +// /// "/users/:id", +// /// get( +// /// // first try `admin`, if that rejects run `user`, finally falling back +// /// // to `guest` +// /// admin.or(user).or(guest) +// /// ) +// /// ); +// /// # let _: Router = app; +// /// ``` +// fn or(self, rhs: R) -> Or +// where +// R: HandlerCallWithExtractors, +// { +// Or { +// lhs: self, +// rhs, +// _marker: PhantomData, +// } +// } +// } +// +// macro_rules! impl_handler_call_with { +// ( $($ty:ident),* $(,)? ) => { +// #[allow(non_snake_case)] +// impl HandlerCallWithExtractors<($($ty,)*), S, B> for F +// where +// F: FnOnce($($ty,)*) -> Fut, +// Fut: Future + Send + 'static, +// Fut::Output: IntoResponse, +// { +// // this puts `futures_util` in our public API but thats fine in axum-extra +// type Future = Map Response>; +// +// fn call( +// self, +// _state: Arc, +// ($($ty,)*): ($($ty,)*), +// ) -> >::Future { +// self($($ty,)*).map(IntoResponse::into_response) +// } +// } +// }; +// } +// +// impl_handler_call_with!(); +// impl_handler_call_with!(T1); +// impl_handler_call_with!(T1, T2); +// impl_handler_call_with!(T1, T2, T3); +// impl_handler_call_with!(T1, T2, T3, T4); +// impl_handler_call_with!(T1, T2, T3, T4, T5); +// impl_handler_call_with!(T1, T2, T3, T4, T5, T6); +// impl_handler_call_with!(T1, T2, T3, T4, T5, T6, T7); +// impl_handler_call_with!(T1, T2, T3, T4, T5, T6, T7, T8); +// impl_handler_call_with!(T1, T2, T3, T4, T5, T6, T7, T8, T9); +// impl_handler_call_with!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10); +// impl_handler_call_with!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11); +// impl_handler_call_with!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12); +// impl_handler_call_with!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13); +// impl_handler_call_with!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14); +// impl_handler_call_with!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15); +// impl_handler_call_with!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16); +// +// /// A [`Handler`] created from a [`HandlerCallWithExtractors`]. +// /// +// /// Created with [`HandlerCallWithExtractors::into_handler`]. +// #[allow(missing_debug_implementations)] +// pub struct IntoHandler { +// handler: H, +// _marker: PhantomData (T, S, B)>, +// } +// +// impl Handler for IntoHandler +// where +// H: HandlerCallWithExtractors + Clone + Send + 'static, +// T: FromRequest + Send + 'static, +// T::Rejection: Send, +// B: Send + 'static, +// S: Send + Sync + 'static, +// { +// type Future = BoxFuture<'static, Response>; +// +// fn call(self, state: Arc, req: http::Request) -> Self::Future { +// Box::pin(async move { +// let mut req = RequestParts::with_state_arc(Arc::clone(&state), req); +// match req.extract::().await { +// Ok(t) => self.handler.call(state, t).await, +// Err(rejection) => rejection.into_response(), +// } +// }) +// } +// } +// +// impl Copy for IntoHandler where H: Copy {} +// +// impl Clone for IntoHandler +// where +// H: Clone, +// { +// fn clone(&self) -> Self { +// Self { +// handler: self.handler.clone(), +// _marker: self._marker, +// } +// } +// } diff --git a/axum-extra/src/handler/or.rs b/axum-extra/src/handler/or.rs index fb307ccf7a..e8dffa5af1 100644 --- a/axum-extra/src/handler/or.rs +++ b/axum-extra/src/handler/or.rs @@ -1,153 +1,153 @@ -use super::HandlerCallWithExtractors; -use crate::either::Either; -use axum::{ - extract::{FromRequest, RequestParts}, - handler::Handler, - http::Request, - response::{IntoResponse, Response}, -}; -use futures_util::future::{BoxFuture, Either as EitherFuture, FutureExt, Map}; -use http::StatusCode; -use std::{future::Future, marker::PhantomData, sync::Arc}; - -/// [`Handler`] that runs one [`Handler`] and if that rejects it'll fallback to another -/// [`Handler`]. -/// -/// Created with [`HandlerCallWithExtractors::or`](super::HandlerCallWithExtractors::or). -#[allow(missing_debug_implementations)] -pub struct Or { - pub(super) lhs: L, - pub(super) rhs: R, - pub(super) _marker: PhantomData (Lt, Rt, S, B)>, -} - -impl HandlerCallWithExtractors, S, B> for Or -where - L: HandlerCallWithExtractors + Send + 'static, - R: HandlerCallWithExtractors + Send + 'static, - Rt: Send + 'static, - Lt: Send + 'static, - B: Send + 'static, -{ - // this puts `futures_util` in our public API but thats fine in axum-extra - type Future = EitherFuture< - Map::Output) -> Response>, - Map::Output) -> Response>, - >; - - fn call( - self, - state: Arc, - extractors: Either, - ) -> , S, B>>::Future { - match extractors { - Either::E1(lt) => self - .lhs - .call(state, lt) - .map(IntoResponse::into_response as _) - .left_future(), - Either::E2(rt) => self - .rhs - .call(state, rt) - .map(IntoResponse::into_response as _) - .right_future(), - } - } -} - -impl Handler<(Lt, Rt), S, B> for Or -where - L: HandlerCallWithExtractors + Clone + Send + 'static, - R: HandlerCallWithExtractors + Clone + Send + 'static, - Lt: FromRequest + Send + 'static, - Rt: FromRequest + Send + 'static, - Lt::Rejection: Send, - Rt::Rejection: Send, - B: Send + 'static, - S: Send + Sync + 'static, -{ - // this puts `futures_util` in our public API but thats fine in axum-extra - type Future = BoxFuture<'static, Response>; - - fn call(self, state: Arc, req: Request) -> Self::Future { - Box::pin(async move { - let mut req = RequestParts::with_state_arc(Arc::clone(&state), req); - - if let Ok(lt) = req.extract::().await { - return self.lhs.call(state, lt).await; - } - - if let Ok(rt) = req.extract::().await { - return self.rhs.call(state, rt).await; - } - - StatusCode::NOT_FOUND.into_response() - }) - } -} - -impl Copy for Or -where - L: Copy, - R: Copy, -{ -} - -impl Clone for Or -where - L: Clone, - R: Clone, -{ - fn clone(&self) -> Self { - Self { - lhs: self.lhs.clone(), - rhs: self.rhs.clone(), - _marker: self._marker, - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::test_helpers::*; - use axum::{ - extract::{Path, Query}, - routing::get, - Router, - }; - use serde::Deserialize; - - #[tokio::test] - async fn works() { - #[derive(Deserialize)] - struct Params { - a: String, - } - - async fn one(Path(id): Path) -> String { - id.to_string() - } - - async fn two(Query(params): Query) -> String { - params.a - } - - async fn three() -> &'static str { - "fallback" - } - - let app = Router::new().route("/:id", get(one.or(two).or(three))); - - let client = TestClient::new(app); - - let res = client.get("/123").send().await; - assert_eq!(res.text().await, "123"); - - let res = client.get("/foo?a=bar").send().await; - assert_eq!(res.text().await, "bar"); - - let res = client.get("/foo").send().await; - assert_eq!(res.text().await, "fallback"); - } -} +// use super::HandlerCallWithExtractors; +// use crate::either::Either; +// use axum::{ +// extract::{FromRequest, RequestParts}, +// handler::Handler, +// http::Request, +// response::{IntoResponse, Response}, +// }; +// use futures_util::future::{BoxFuture, Either as EitherFuture, FutureExt, Map}; +// use http::StatusCode; +// use std::{future::Future, marker::PhantomData, sync::Arc}; +// +// /// [`Handler`] that runs one [`Handler`] and if that rejects it'll fallback to another +// /// [`Handler`]. +// /// +// /// Created with [`HandlerCallWithExtractors::or`](super::HandlerCallWithExtractors::or). +// #[allow(missing_debug_implementations)] +// pub struct Or { +// pub(super) lhs: L, +// pub(super) rhs: R, +// pub(super) _marker: PhantomData (Lt, Rt, S, B)>, +// } +// +// impl HandlerCallWithExtractors, S, B> for Or +// where +// L: HandlerCallWithExtractors + Send + 'static, +// R: HandlerCallWithExtractors + Send + 'static, +// Rt: Send + 'static, +// Lt: Send + 'static, +// B: Send + 'static, +// { +// // this puts `futures_util` in our public API but thats fine in axum-extra +// type Future = EitherFuture< +// Map::Output) -> Response>, +// Map::Output) -> Response>, +// >; +// +// fn call( +// self, +// state: Arc, +// extractors: Either, +// ) -> , S, B>>::Future { +// match extractors { +// Either::E1(lt) => self +// .lhs +// .call(state, lt) +// .map(IntoResponse::into_response as _) +// .left_future(), +// Either::E2(rt) => self +// .rhs +// .call(state, rt) +// .map(IntoResponse::into_response as _) +// .right_future(), +// } +// } +// } +// +// impl Handler<(Lt, Rt), S, B> for Or +// where +// L: HandlerCallWithExtractors + Clone + Send + 'static, +// R: HandlerCallWithExtractors + Clone + Send + 'static, +// Lt: FromRequest + Send + 'static, +// Rt: FromRequest + Send + 'static, +// Lt::Rejection: Send, +// Rt::Rejection: Send, +// B: Send + 'static, +// S: Send + Sync + 'static, +// { +// // this puts `futures_util` in our public API but thats fine in axum-extra +// type Future = BoxFuture<'static, Response>; +// +// fn call(self, state: Arc, req: Request) -> Self::Future { +// Box::pin(async move { +// let mut req = RequestParts::with_state_arc(Arc::clone(&state), req); +// +// if let Ok(lt) = req.extract::().await { +// return self.lhs.call(state, lt).await; +// } +// +// if let Ok(rt) = req.extract::().await { +// return self.rhs.call(state, rt).await; +// } +// +// StatusCode::NOT_FOUND.into_response() +// }) +// } +// } +// +// impl Copy for Or +// where +// L: Copy, +// R: Copy, +// { +// } +// +// impl Clone for Or +// where +// L: Clone, +// R: Clone, +// { +// fn clone(&self) -> Self { +// Self { +// lhs: self.lhs.clone(), +// rhs: self.rhs.clone(), +// _marker: self._marker, +// } +// } +// } +// +// #[cfg(test)] +// mod tests { +// use super::*; +// use crate::test_helpers::*; +// use axum::{ +// extract::{Path, Query}, +// routing::get, +// Router, +// }; +// use serde::Deserialize; +// +// #[tokio::test] +// async fn works() { +// #[derive(Deserialize)] +// struct Params { +// a: String, +// } +// +// async fn one(Path(id): Path) -> String { +// id.to_string() +// } +// +// async fn two(Query(params): Query) -> String { +// params.a +// } +// +// async fn three() -> &'static str { +// "fallback" +// } +// +// let app = Router::new().route("/:id", get(one.or(two).or(three))); +// +// let client = TestClient::new(app); +// +// let res = client.get("/123").send().await; +// assert_eq!(res.text().await, "123"); +// +// let res = client.get("/foo?a=bar").send().await; +// assert_eq!(res.text().await, "bar"); +// +// let res = client.get("/foo").send().await; +// assert_eq!(res.text().await, "fallback"); +// } +// } diff --git a/axum-extra/src/json_lines.rs b/axum-extra/src/json_lines.rs index b130fecb74..83336311ca 100644 --- a/axum-extra/src/json_lines.rs +++ b/axum-extra/src/json_lines.rs @@ -110,7 +110,7 @@ where { type Rejection = Infallible; - async fn from_request(req: Request, state: &S) -> Result { + async fn from_request(req: Request, _state: &S) -> Result { // `Stream::lines` isn't a thing so we have to convert it into an `AsyncRead` // so we can call `AsyncRead::lines` and then convert it back to a `Stream` let body = BodyStream { diff --git a/axum-extra/src/protobuf.rs b/axum-extra/src/protobuf.rs index 31705983cf..f64eae3687 100644 --- a/axum-extra/src/protobuf.rs +++ b/axum-extra/src/protobuf.rs @@ -100,7 +100,7 @@ pub struct ProtoBuf(pub T); impl FromRequest for ProtoBuf where T: Message + Default, - B: HttpBody + Send, + B: HttpBody + Send + 'static, B::Data: Send, B::Error: Into, S: Send + Sync,