diff --git a/axum-core/Cargo.toml b/axum-core/Cargo.toml index dbe5346c..2897ce38 100644 --- a/axum-core/Cargo.toml +++ b/axum-core/Cargo.toml @@ -12,7 +12,6 @@ repository = "https://github.com/tokio-rs/axum" version = "0.3.0-rc.3" # remember to also bump the version that axum depends on [dependencies] -async-trait = "0.1" bytes = "1.0" futures-util = { version = "0.3", default-features = false, features = ["alloc"] } http = "0.2.7" diff --git a/axum-core/src/ext_traits/mod.rs b/axum-core/src/ext_traits/mod.rs index 02595fbe..16549c02 100644 --- a/axum-core/src/ext_traits/mod.rs +++ b/axum-core/src/ext_traits/mod.rs @@ -6,16 +6,14 @@ mod tests { use std::convert::Infallible; use crate::extract::{FromRef, FromRequestParts}; - use async_trait::async_trait; use http::request::Parts; #[derive(Debug, Default, Clone, Copy)] pub(crate) struct State<S>(pub(crate) S); - #[async_trait] impl<OuterState, InnerState> FromRequestParts<OuterState> for State<InnerState> where - InnerState: FromRef<OuterState>, + InnerState: FromRef<OuterState> + 'static, OuterState: Send + Sync, { type Rejection = Infallible; @@ -32,7 +30,6 @@ mod tests { // some extractor that requires the state, such as `SignedCookieJar` pub(crate) struct RequiresState(pub(crate) String); - #[async_trait] impl<S> FromRequestParts<S> for RequiresState where S: Send + Sync, diff --git a/axum-core/src/ext_traits/request.rs b/axum-core/src/ext_traits/request.rs index 05ca77ea..aa7f4047 100644 --- a/axum-core/src/ext_traits/request.rs +++ b/axum-core/src/ext_traits/request.rs @@ -1,7 +1,7 @@ use crate::extract::{DefaultBodyLimitKind, FromRequest, FromRequestParts}; -use futures_util::future::BoxFuture; use http::Request; use http_body::Limited; +use std::future::Future; mod sealed { pub trait Sealed<B> {} @@ -16,10 +16,9 @@ pub trait RequestExt<B>: sealed::Sealed<B> + Sized { /// /// Note this consumes the request. Use [`RequestExt::extract_parts`] if you're not extracting /// the body and don't want to consume the request. - fn extract<E, M>(self) -> BoxFuture<'static, Result<E, E::Rejection>> + fn extract<E, M>(self) -> impl Future<Output = Result<E, E::Rejection>> + 'static where - E: FromRequest<(), B, M> + 'static, - M: 'static; + E: FromRequest<(), B, M>; /// Apply an extractor that requires some state to this `Request`. /// @@ -27,17 +26,20 @@ pub trait RequestExt<B>: sealed::Sealed<B> + Sized { /// /// Note this consumes the request. Use [`RequestExt::extract_parts_with_state`] if you're not /// extracting the body and don't want to consume the request. - fn extract_with_state<E, S, M>(self, state: &S) -> BoxFuture<'_, Result<E, E::Rejection>> + fn extract_with_state<E, S, M>( + self, + state: &S, + ) -> impl Future<Output = Result<E, E::Rejection>> + '_ where - E: FromRequest<S, B, M> + 'static, + E: FromRequest<S, B, M>, S: Send + Sync; /// Apply a parts extractor to this `Request`. /// /// This is just a convenience for `E::from_request_parts(parts, state)`. - fn extract_parts<E>(&mut self) -> BoxFuture<'_, Result<E, E::Rejection>> + fn extract_parts<E>(&mut self) -> impl Future<Output = Result<E, E::Rejection>> + '_ where - E: FromRequestParts<()> + 'static; + E: FromRequestParts<()>; /// Apply a parts extractor that requires some state to this `Request`. /// @@ -45,9 +47,9 @@ pub trait RequestExt<B>: sealed::Sealed<B> + Sized { fn extract_parts_with_state<'a, E, S>( &'a mut self, state: &'a S, - ) -> BoxFuture<'a, Result<E, E::Rejection>> + ) -> impl Future<Output = Result<E, E::Rejection>> + 'a where - E: FromRequestParts<S> + 'static, + E: FromRequestParts<S>, S: Send + Sync; /// Apply the [default body limit](crate::extract::DefaultBodyLimit). @@ -63,27 +65,29 @@ pub trait RequestExt<B>: sealed::Sealed<B> + Sized { impl<B> RequestExt<B> for Request<B> where - B: Send + 'static, + B: Send, { - fn extract<E, M>(self) -> BoxFuture<'static, Result<E, E::Rejection>> + fn extract<E, M>(self) -> impl Future<Output = Result<E, E::Rejection>> + 'static where - E: FromRequest<(), B, M> + 'static, - M: 'static, + E: FromRequest<(), B, M>, { self.extract_with_state(&()) } - fn extract_with_state<E, S, M>(self, state: &S) -> BoxFuture<'_, Result<E, E::Rejection>> + fn extract_with_state<E, S, M>( + self, + state: &S, + ) -> impl Future<Output = Result<E, E::Rejection>> + '_ where - E: FromRequest<S, B, M> + 'static, + E: FromRequest<S, B, M>, S: Send + Sync, { E::from_request(self, state) } - fn extract_parts<E>(&mut self) -> BoxFuture<'_, Result<E, E::Rejection>> + fn extract_parts<E>(&mut self) -> impl Future<Output = Result<E, E::Rejection>> + '_ where - E: FromRequestParts<()> + 'static, + E: FromRequestParts<()>, { self.extract_parts_with_state(&()) } @@ -91,9 +95,9 @@ where fn extract_parts_with_state<'a, E, S>( &'a mut self, state: &'a S, - ) -> BoxFuture<'a, Result<E, E::Rejection>> + ) -> impl Future<Output = Result<E, E::Rejection>> + 'a where - E: FromRequestParts<S> + 'static, + E: FromRequestParts<S>, S: Send + Sync, { let mut req = Request::new(()); @@ -145,7 +149,6 @@ mod tests { ext_traits::tests::{RequiresState, State}, extract::FromRef, }; - use async_trait::async_trait; use http::Method; use hyper::Body; @@ -209,7 +212,6 @@ mod tests { body: String, } - #[async_trait] impl<S, B> FromRequest<S, B> for WorksForCustomExtractor where S: Send + Sync, diff --git a/axum-core/src/ext_traits/request_parts.rs b/axum-core/src/ext_traits/request_parts.rs index 7e136d58..d9eb35f0 100644 --- a/axum-core/src/ext_traits/request_parts.rs +++ b/axum-core/src/ext_traits/request_parts.rs @@ -1,6 +1,6 @@ use crate::extract::FromRequestParts; -use futures_util::future::BoxFuture; use http::request::Parts; +use std::future::Future; mod sealed { pub trait Sealed {} @@ -12,7 +12,7 @@ pub trait RequestPartsExt: sealed::Sealed + Sized { /// Apply an extractor to this `Parts`. /// /// This is just a convenience for `E::from_request_parts(parts, &())`. - fn extract<E>(&mut self) -> BoxFuture<'_, Result<E, E::Rejection>> + fn extract<E>(&mut self) -> impl Future<Output = Result<E, E::Rejection>> + '_ where E: FromRequestParts<()> + 'static; @@ -22,14 +22,14 @@ pub trait RequestPartsExt: sealed::Sealed + Sized { fn extract_with_state<'a, E, S>( &'a mut self, state: &'a S, - ) -> BoxFuture<'a, Result<E, E::Rejection>> + ) -> impl Future<Output = Result<E, E::Rejection>> + 'a where - E: FromRequestParts<S> + 'static, + E: FromRequestParts<S>, S: Send + Sync; } impl RequestPartsExt for Parts { - fn extract<E>(&mut self) -> BoxFuture<'_, Result<E, E::Rejection>> + fn extract<E>(&mut self) -> impl Future<Output = Result<E, E::Rejection>> + '_ where E: FromRequestParts<()> + 'static, { @@ -39,9 +39,9 @@ impl RequestPartsExt for Parts { fn extract_with_state<'a, E, S>( &'a mut self, state: &'a S, - ) -> BoxFuture<'a, Result<E, E::Rejection>> + ) -> impl Future<Output = Result<E, E::Rejection>> + 'a where - E: FromRequestParts<S> + 'static, + E: FromRequestParts<S>, S: Send + Sync, { E::from_request_parts(self, state) @@ -57,7 +57,6 @@ mod tests { ext_traits::tests::{RequiresState, State}, extract::FromRef, }; - use async_trait::async_trait; use http::{Method, Request}; #[tokio::test] @@ -90,7 +89,6 @@ mod tests { from_state: String, } - #[async_trait] impl<S> FromRequestParts<S> for WorksForCustomExtractor where S: Send + Sync, diff --git a/axum-core/src/extract/mod.rs b/axum-core/src/extract/mod.rs index 2eb37ea4..57e013e6 100644 --- a/axum-core/src/extract/mod.rs +++ b/axum-core/src/extract/mod.rs @@ -5,9 +5,9 @@ //! [`axum::extract`]: https://docs.rs/axum/latest/axum/extract/index.html use crate::response::IntoResponse; -use async_trait::async_trait; use http::{request::Parts, Request}; use std::convert::Infallible; +use std::future::Future; pub mod rejection; @@ -38,20 +38,22 @@ mod private { /// See [`axum::extract`] for more general docs about extraxtors. /// /// [`axum::extract`]: https://docs.rs/axum/0.6.0-rc.2/axum/extract/index.html -#[async_trait] #[cfg_attr( nightly_error_messages, rustc_on_unimplemented( note = "Function argument is not a valid axum extractor. \nSee `https://docs.rs/axum/latest/axum/extract/index.html` for details", ) )] -pub trait FromRequestParts<S>: Sized { +pub trait FromRequestParts<S>: Sized + 'static { /// If the extractor fails it'll use this "rejection" type. A rejection is /// a kind of error that can be converted into a response. - type Rejection: IntoResponse; + type Rejection: IntoResponse + 'static; /// Perform the extraction. - async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection>; + fn from_request_parts<'a>( + parts: &'a mut Parts, + state: &'a S, + ) -> impl Future<Output = Result<Self, Self::Rejection>> + Send + 'a; } /// Types that can be created from requests. @@ -87,7 +89,6 @@ pub trait FromRequestParts<S>: Sized { /// /// struct MyExtractor; /// -/// #[async_trait] /// impl<S, B> FromRequest<S, B> for MyExtractor /// where /// // these bounds are required by `async_trait` @@ -107,38 +108,41 @@ pub trait FromRequestParts<S>: Sized { /// /// [`http::Request<B>`]: http::Request /// [`axum::extract`]: https://docs.rs/axum/0.6.0-rc.2/axum/extract/index.html -#[async_trait] #[cfg_attr( nightly_error_messages, rustc_on_unimplemented( note = "Function argument is not a valid axum extractor. \nSee `https://docs.rs/axum/latest/axum/extract/index.html` for details", ) )] -pub trait FromRequest<S, B, M = private::ViaRequest>: Sized { +pub trait FromRequest<S, B, M = private::ViaRequest>: Sized + 'static { /// If the extractor fails it'll use this "rejection" type. A rejection is /// a kind of error that can be converted into a response. - type Rejection: IntoResponse; + type Rejection: IntoResponse + 'static; /// Perform the extraction. - async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection>; + fn from_request( + req: Request<B>, + state: &S, + ) -> impl Future<Output = Result<Self, Self::Rejection>> + Send + '_; } -#[async_trait] impl<S, B, T> FromRequest<S, B, private::ViaParts> for T where - B: Send + 'static, + B: Send, S: Send + Sync, T: FromRequestParts<S>, { type Rejection = <Self as FromRequestParts<S>>::Rejection; - async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> { + fn from_request( + req: Request<B>, + state: &S, + ) -> impl Future<Output = Result<Self, Self::Rejection>> + '_ { let (mut parts, _) = req.into_parts(); - Self::from_request_parts(&mut parts, state).await + async move { Self::from_request_parts(&mut parts, state).await } } } -#[async_trait] impl<S, T> FromRequestParts<S> for Option<T> where T: FromRequestParts<S>, @@ -154,7 +158,6 @@ where } } -#[async_trait] impl<S, T, B> FromRequest<S, B> for Option<T> where T: FromRequest<S, B>, @@ -168,7 +171,6 @@ where } } -#[async_trait] impl<S, T> FromRequestParts<S> for Result<T, T::Rejection> where T: FromRequestParts<S>, @@ -181,16 +183,19 @@ where } } -#[async_trait] impl<S, T, B> FromRequest<S, B> for Result<T, T::Rejection> where T: FromRequest<S, B>, - B: Send + 'static, + B: Send, S: Send + Sync, { type Rejection = Infallible; - async fn from_request(req: Request<B>, state: &S) -> Result<Self, Self::Rejection> { - Ok(T::from_request(req, state).await) + fn from_request( + req: Request<B>, + state: &S, + ) -> impl Future<Output = Result<Self, Self::Rejection>> + '_ { + let fut = T::from_request(req, state); + async move { Ok(fut.await) } } } diff --git a/axum-core/src/extract/request_parts.rs b/axum-core/src/extract/request_parts.rs index 05d7d727..6254caae 100644 --- a/axum-core/src/extract/request_parts.rs +++ b/axum-core/src/extract/request_parts.rs @@ -1,14 +1,12 @@ use super::{rejection::*, FromRequest, FromRequestParts}; use crate::{BoxError, RequestExt}; -use async_trait::async_trait; use bytes::Bytes; use http::{request::Parts, HeaderMap, Method, Request, Uri, Version}; use std::convert::Infallible; -#[async_trait] impl<S, B> FromRequest<S, B> for Request<B> where - B: Send, + B: Send + 'static, S: Send + Sync, { type Rejection = Infallible; @@ -18,7 +16,6 @@ where } } -#[async_trait] impl<S> FromRequestParts<S> for Method where S: Send + Sync, @@ -30,7 +27,6 @@ where } } -#[async_trait] impl<S> FromRequestParts<S> for Uri where S: Send + Sync, @@ -42,7 +38,6 @@ where } } -#[async_trait] impl<S> FromRequestParts<S> for Version where S: Send + Sync, @@ -59,7 +54,6 @@ where /// Prefer using [`TypedHeader`] to extract only the headers you need. /// /// [`TypedHeader`]: https://docs.rs/axum/latest/axum/extract/struct.TypedHeader.html -#[async_trait] impl<S> FromRequestParts<S> for HeaderMap where S: Send + Sync, @@ -71,7 +65,6 @@ where } } -#[async_trait] impl<S, B> FromRequest<S, B> for Bytes where B: http_body::Body + Send + 'static, @@ -95,7 +88,6 @@ where } } -#[async_trait] impl<S, B> FromRequest<S, B> for String where B: http_body::Body + Send + 'static, @@ -122,7 +114,6 @@ where } } -#[async_trait] impl<S, B> FromRequest<S, B> for Parts where B: Send + 'static, diff --git a/axum-core/src/extract/tuple.rs b/axum-core/src/extract/tuple.rs index 728135b2..d48ae264 100644 --- a/axum-core/src/extract/tuple.rs +++ b/axum-core/src/extract/tuple.rs @@ -1,10 +1,8 @@ use super::{FromRequest, FromRequestParts}; use crate::response::{IntoResponse, Response}; -use async_trait::async_trait; use http::request::{Parts, Request}; use std::convert::Infallible; -#[async_trait] impl<S> FromRequestParts<S> for () where S: Send + Sync, @@ -20,7 +18,6 @@ macro_rules! impl_from_request { ( [$($ty:ident),*], $last:ident ) => { - #[async_trait] #[allow(non_snake_case, unused_mut, unused_variables)] impl<S, $($ty,)* $last> FromRequestParts<S> for ($($ty,)* $last,) where @@ -46,7 +43,6 @@ macro_rules! impl_from_request { // This impl must not be generic over M, otherwise it would conflict with the blanket // implementation of `FromRequest<S, B, Mut>` for `T: FromRequestParts<S>`. - #[async_trait] #[allow(non_snake_case, unused_mut, unused_variables)] impl<S, B, $($ty,)* $last> FromRequest<S, B> for ($($ty,)* $last,) where diff --git a/axum-core/src/lib.rs b/axum-core/src/lib.rs index 974e5e18..6aa90c03 100644 --- a/axum-core/src/lib.rs +++ b/axum-core/src/lib.rs @@ -9,6 +9,7 @@ //! [`axum`]: https://crates.io/crates/axum //! [`axum-core`]: http://crates.io/crates/axum-core +#![feature(async_fn_in_trait, return_position_impl_trait_in_trait)] #![warn( clippy::all, clippy::dbg_macro, @@ -45,7 +46,11 @@ missing_docs )] #![deny(unreachable_pub, private_in_public)] -#![allow(elided_lifetimes_in_paths, clippy::type_complexity)] +#![allow( + elided_lifetimes_in_paths, + incomplete_features, + clippy::type_complexity +)] #![forbid(unsafe_code)] #![cfg_attr(test, allow(clippy::float_cmp))] diff --git a/axum-extra/src/either.rs b/axum-extra/src/either.rs index 2e3af8b8..7c19947c 100755 --- a/axum-extra/src/either.rs +++ b/axum-extra/src/either.rs @@ -15,8 +15,7 @@ //! // extractors for checking permissions //! struct AdminPermissions {} //! -//! #[async_trait] -//! impl<S> FromRequestParts<S> for AdminPermissions +//! //! impl<S> FromRequestParts<S> for AdminPermissions //! where //! S: Send + Sync, //! { @@ -29,8 +28,7 @@ //! //! struct User {} //! -//! #[async_trait] -//! impl<S> FromRequestParts<S> for User +//! //! impl<S> FromRequestParts<S> for User //! where //! S: Send + Sync, //! { @@ -94,7 +92,6 @@ //! [`IntoResponse::into_response`]: https://docs.rs/axum/0.5/axum/response/index.html#returning-different-response-types use axum::{ - async_trait, extract::FromRequestParts, response::{IntoResponse, Response}, }; @@ -225,7 +222,6 @@ macro_rules! impl_traits_for_either { [$($ident:ident),* $(,)?], $last:ident $(,)? ) => { - #[async_trait] impl<S, $($ident),*, $last> FromRequestParts<S> for $either<$($ident),*, $last> where $($ident: FromRequestParts<S>),*, @@ -236,12 +232,14 @@ macro_rules! impl_traits_for_either { async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> { $( - if let Ok(value) = FromRequestParts::from_request_parts(parts, state).await { + if let Ok(value) = + <$ident as FromRequestParts<_>>::from_request_parts(parts, state).await + { return Ok(Self::$ident(value)); } )* - FromRequestParts::from_request_parts(parts, state).await.map(Self::$last) + <$last as FromRequestParts<_>>::from_request_parts(parts, state).await.map(Self::$last) } } diff --git a/axum-extra/src/extract/cached.rs b/axum-extra/src/extract/cached.rs index 03565c77..1ba02324 100644 --- a/axum-extra/src/extract/cached.rs +++ b/axum-extra/src/extract/cached.rs @@ -1,7 +1,4 @@ -use axum::{ - async_trait, - extract::{Extension, FromRequestParts}, -}; +use axum::extract::{Extension, FromRequestParts}; use http::request::Parts; use std::ops::{Deref, DerefMut}; @@ -30,7 +27,6 @@ use std::ops::{Deref, DerefMut}; /// #[derive(Clone)] /// struct Session { /* ... */ } /// -/// #[async_trait] /// impl<S> FromRequestParts<S> for Session /// where /// S: Send + Sync, @@ -45,7 +41,6 @@ use std::ops::{Deref, DerefMut}; /// /// struct CurrentUser { /* ... */ } /// -/// #[async_trait] /// impl<S> FromRequestParts<S> for CurrentUser /// where /// S: Send + Sync, @@ -88,7 +83,6 @@ pub struct Cached<T>(pub T); #[derive(Clone)] struct CachedEntry<T>(T); -#[async_trait] impl<S, T> FromRequestParts<S> for Cached<T> where S: Send + Sync, @@ -140,7 +134,6 @@ mod tests { #[derive(Clone, Debug, PartialEq, Eq)] struct Extractor(Instant); - #[async_trait] impl<S> FromRequestParts<S> for Extractor where S: Send + Sync, diff --git a/axum-extra/src/extract/cookie/mod.rs b/axum-extra/src/extract/cookie/mod.rs index 0c6bcc4c..d866e1fc 100644 --- a/axum-extra/src/extract/cookie/mod.rs +++ b/axum-extra/src/extract/cookie/mod.rs @@ -3,7 +3,6 @@ //! See [`CookieJar`], [`SignedCookieJar`], and [`PrivateCookieJar`] for more details. use axum::{ - async_trait, extract::FromRequestParts, response::{IntoResponse, IntoResponseParts, Response, ResponseParts}, }; @@ -88,7 +87,6 @@ pub struct CookieJar { jar: cookie::CookieJar, } -#[async_trait] impl<S> FromRequestParts<S> for CookieJar where S: Send + Sync, diff --git a/axum-extra/src/extract/cookie/private.rs b/axum-extra/src/extract/cookie/private.rs index cceea95e..48a514b9 100644 --- a/axum-extra/src/extract/cookie/private.rs +++ b/axum-extra/src/extract/cookie/private.rs @@ -1,6 +1,5 @@ use super::{cookies_from_request, set_cookies, Cookie, Key}; use axum::{ - async_trait, extract::{FromRef, FromRequestParts}, response::{IntoResponse, IntoResponseParts, Response, ResponseParts}, }; @@ -87,11 +86,10 @@ impl<K> fmt::Debug for PrivateCookieJar<K> { } } -#[async_trait] impl<S, K> FromRequestParts<S> for PrivateCookieJar<K> where S: Send + Sync, - K: FromRef<S> + Into<Key>, + K: FromRef<S> + Into<Key> + 'static, { type Rejection = Infallible; diff --git a/axum-extra/src/extract/cookie/signed.rs b/axum-extra/src/extract/cookie/signed.rs index 1ef837a2..4d215f82 100644 --- a/axum-extra/src/extract/cookie/signed.rs +++ b/axum-extra/src/extract/cookie/signed.rs @@ -1,6 +1,5 @@ use super::{cookies_from_request, set_cookies}; use axum::{ - async_trait, extract::{FromRef, FromRequestParts}, response::{IntoResponse, IntoResponseParts, Response, ResponseParts}, }; @@ -105,11 +104,10 @@ impl<K> fmt::Debug for SignedCookieJar<K> { } } -#[async_trait] impl<S, K> FromRequestParts<S> for SignedCookieJar<K> where S: Send + Sync, - K: FromRef<S> + Into<Key>, + K: FromRef<S> + Into<Key> + 'static, { type Rejection = Infallible; diff --git a/axum-extra/src/extract/form.rs b/axum-extra/src/extract/form.rs index df33e5ca..c6422311 100644 --- a/axum-extra/src/extract/form.rs +++ b/axum-extra/src/extract/form.rs @@ -1,5 +1,4 @@ use axum::{ - async_trait, body::HttpBody, extract::{rejection::RawFormRejection, FromRequest, RawForm}, response::{IntoResponse, Response}, @@ -51,10 +50,9 @@ impl<T> Deref for Form<T> { } } -#[async_trait] impl<T, S, B> FromRequest<S, B> for Form<T> where - T: DeserializeOwned, + T: DeserializeOwned + 'static, B: HttpBody + Send + 'static, B::Data: Send, B::Error: Into<BoxError>, diff --git a/axum-extra/src/extract/query.rs b/axum-extra/src/extract/query.rs index 8c829dd5..99c77c43 100644 --- a/axum-extra/src/extract/query.rs +++ b/axum-extra/src/extract/query.rs @@ -1,5 +1,4 @@ use axum::{ - async_trait, extract::FromRequestParts, response::{IntoResponse, Response}, Error, @@ -57,10 +56,9 @@ use std::{fmt, ops::Deref}; #[derive(Debug, Clone, Copy, Default)] pub struct Query<T>(pub T); -#[async_trait] impl<T, S> FromRequestParts<S> for Query<T> where - T: DeserializeOwned, + T: DeserializeOwned + 'static, S: Send + Sync, { type Rejection = QueryRejection; diff --git a/axum-extra/src/extract/with_rejection.rs b/axum-extra/src/extract/with_rejection.rs index f3a0f04e..eafa0a06 100644 --- a/axum-extra/src/extract/with_rejection.rs +++ b/axum-extra/src/extract/with_rejection.rs @@ -1,4 +1,3 @@ -use axum::async_trait; use axum::extract::{FromRequest, FromRequestParts}; use axum::response::IntoResponse; use http::request::Parts; @@ -108,13 +107,12 @@ impl<E, R> DerefMut for WithRejection<E, R> { } } -#[async_trait] impl<B, E, R, S> FromRequest<S, B> for WithRejection<E, R> where B: Send + 'static, S: Send + Sync, - E: FromRequest<S, B>, - R: From<E::Rejection> + IntoResponse, + E: FromRequest<S, B> + 'static, + R: From<E::Rejection> + IntoResponse + 'static, { type Rejection = R; @@ -124,12 +122,11 @@ where } } -#[async_trait] impl<E, R, S> FromRequestParts<S> for WithRejection<E, R> where S: Send + Sync, E: FromRequestParts<S>, - R: From<E::Rejection> + IntoResponse, + R: From<E::Rejection> + IntoResponse + 'static, { type Rejection = R; @@ -153,7 +150,6 @@ mod tests { struct TestExtractor; struct TestRejection; - #[async_trait] impl<S> FromRequestParts<S> for TestExtractor where S: Send + Sync, diff --git a/axum-extra/src/handler/mod.rs b/axum-extra/src/handler/mod.rs index 305c9c8c..33680bc4 100644 --- a/axum-extra/src/handler/mod.rs +++ b/axum-extra/src/handler/mod.rs @@ -66,8 +66,7 @@ pub trait HandlerCallWithExtractors<T, S, B>: Sized { /// // extractors for checking permissions /// struct AdminPermissions {} /// - /// #[async_trait] - /// impl<S> FromRequestParts<S> for AdminPermissions + /// /// impl<S> FromRequestParts<S> for AdminPermissions /// where /// S: Send + Sync, /// { @@ -80,8 +79,7 @@ pub trait HandlerCallWithExtractors<T, S, B>: Sized { /// /// struct User {} /// - /// #[async_trait] - /// impl<S> FromRequestParts<S> for User + /// /// impl<S> FromRequestParts<S> for User /// where /// S: Send + Sync, /// { diff --git a/axum-extra/src/json_lines.rs b/axum-extra/src/json_lines.rs index 83336311..f4028eaf 100644 --- a/axum-extra/src/json_lines.rs +++ b/axum-extra/src/json_lines.rs @@ -1,7 +1,6 @@ //! Newline delimited JSON extractor and response. use axum::{ - async_trait, body::{HttpBody, StreamBody}, extract::FromRequest, response::{IntoResponse, Response}, @@ -99,13 +98,12 @@ impl<S> JsonLines<S, AsResponse> { } } -#[async_trait] impl<S, B, T> FromRequest<S, B> for JsonLines<T, AsExtractor> where B: HttpBody + Send + 'static, B::Data: Into<Bytes>, B::Error: Into<BoxError>, - T: DeserializeOwned, + T: DeserializeOwned + 'static, S: Send + Sync, { type Rejection = Infallible; diff --git a/axum-extra/src/lib.rs b/axum-extra/src/lib.rs index f7c23682..56cf1c3b 100644 --- a/axum-extra/src/lib.rs +++ b/axum-extra/src/lib.rs @@ -23,6 +23,7 @@ //! //! [`axum`]: https://crates.io/crates/axum +#![feature(async_fn_in_trait)] #![warn( clippy::all, clippy::dbg_macro, @@ -59,7 +60,11 @@ missing_docs )] #![deny(unreachable_pub, private_in_public)] -#![allow(elided_lifetimes_in_paths, clippy::type_complexity)] +#![allow( + elided_lifetimes_in_paths, + incomplete_features, + clippy::type_complexity +)] #![forbid(unsafe_code)] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![cfg_attr(test, allow(clippy::float_cmp))] diff --git a/axum-extra/src/protobuf.rs b/axum-extra/src/protobuf.rs index ddb70122..860a4682 100644 --- a/axum-extra/src/protobuf.rs +++ b/axum-extra/src/protobuf.rs @@ -1,7 +1,6 @@ //! Protocol Buffer extractor and response. use axum::{ - async_trait, body::{Bytes, HttpBody}, extract::{rejection::BytesRejection, FromRequest}, response::{IntoResponse, Response}, @@ -96,10 +95,9 @@ use std::ops::{Deref, DerefMut}; #[cfg_attr(docsrs, doc(cfg(feature = "protobuf")))] pub struct ProtoBuf<T>(pub T); -#[async_trait] impl<T, S, B> FromRequest<S, B> for ProtoBuf<T> where - T: Message + Default, + T: Message + Default + 'static, B: HttpBody + Send + 'static, B::Data: Send, B::Error: Into<BoxError>, diff --git a/axum-macros/src/from_request.rs b/axum-macros/src/from_request.rs index 7f6e76c9..15f92f1f 100644 --- a/axum-macros/src/from_request.rs +++ b/axum-macros/src/from_request.rs @@ -384,7 +384,6 @@ fn impl_struct_by_extracting_each_field( Ok(match tr { Trait::FromRequest => quote! { - #[::axum::async_trait] #[automatically_derived] impl<#impl_generics> ::axum::extract::FromRequest<#trait_generics> for #ident where @@ -404,7 +403,6 @@ fn impl_struct_by_extracting_each_field( } }, Trait::FromRequestParts => quote! { - #[::axum::async_trait] #[automatically_derived] impl<#impl_generics> ::axum::extract::FromRequestParts<#trait_generics> for #ident where @@ -477,7 +475,8 @@ fn extract_fields( let FromRequestFieldAttrs { via } = parse_attrs("from_request", &field.attrs)?; let member = member(field, index); - let ty_span = field.ty.span(); + let ty = &field.ty; + let ty_span = ty.span(); let into_inner = into_inner(via, ty_span); if peel_option(&field.ty).is_some() { @@ -487,7 +486,7 @@ fn extract_fields( #member: { let (mut parts, body) = req.into_parts(); let value = - ::axum::extract::FromRequestParts::from_request_parts( + <$ty as ::axum::extract::FromRequestParts<_>>::from_request_parts( &mut parts, state, ) @@ -502,7 +501,7 @@ fn extract_fields( Trait::FromRequestParts => { quote_spanned! {ty_span=> #member: { - ::axum::extract::FromRequestParts::from_request_parts( + <$ty as ::axum::extract::FromRequestParts<_>>::from_request_parts( parts, state, ) @@ -521,7 +520,7 @@ fn extract_fields( #member: { let (mut parts, body) = req.into_parts(); let value = - ::axum::extract::FromRequestParts::from_request_parts( + <$ty as ::axum::extract::FromRequestParts<_>>::from_request_parts( &mut parts, state, ) @@ -535,7 +534,7 @@ fn extract_fields( Trait::FromRequestParts => { quote_spanned! {ty_span=> #member: { - ::axum::extract::FromRequestParts::from_request_parts( + <$ty as ::axum::extract::FromRequestParts<_>>::from_request_parts( parts, state, ) @@ -559,7 +558,7 @@ fn extract_fields( #member: { let (mut parts, body) = req.into_parts(); let value = - ::axum::extract::FromRequestParts::from_request_parts( + <$ty as ::axum::extract::FromRequestParts<_>>::from_request_parts( &mut parts, state, ) @@ -574,7 +573,7 @@ fn extract_fields( Trait::FromRequestParts => { quote_spanned! {ty_span=> #member: { - ::axum::extract::FromRequestParts::from_request_parts( + <$ty as ::axum::extract::FromRequestParts<_>>::from_request_parts( parts, state, ) @@ -595,13 +594,14 @@ fn extract_fields( let FromRequestFieldAttrs { via } = parse_attrs("from_request", &field.attrs)?; let member = member(field, fields.len() - 1); - let ty_span = field.ty.span(); + let ty = &field.ty; + let ty_span = ty.span(); let into_inner = into_inner(via, ty_span); let item = if peel_option(&field.ty).is_some() { quote_spanned! {ty_span=> #member: { - ::axum::extract::FromRequest::from_request(req, state) + <$ty as ::axum::extract::FromRequest<_, _>>::from_request(req, state) .await .ok() .map(#into_inner) @@ -610,7 +610,7 @@ fn extract_fields( } else if peel_result_ok(&field.ty).is_some() { quote_spanned! {ty_span=> #member: { - ::axum::extract::FromRequest::from_request(req, state) + <$ty as ::axum::extract::FromRequest<_, _>>::from_request(req, state) .await .map(#into_inner) }, @@ -624,7 +624,7 @@ fn extract_fields( quote_spanned! {ty_span=> #member: { - ::axum::extract::FromRequest::from_request(req, state) + <$ty as ::axum::extract::FromRequest<_, _>>::from_request(req, state) .await .map(#into_inner) .map_err(#map_err)? @@ -822,11 +822,10 @@ fn impl_struct_by_extracting_all_at_once( let tokens = match tr { Trait::FromRequest => { quote_spanned! {path_span=> - #[::axum::async_trait] #[automatically_derived] impl<#impl_generics> ::axum::extract::FromRequest<#trait_generics> for #ident #ident_generics where - #via_path<#via_type_generics>: ::axum::extract::FromRequest<#trait_generics>, + #via_path<#via_type_generics>: ::axum::extract::FromRequest<#trait_generics> + 'static, #rejection_bound B: ::std::marker::Send + 'static, #state_bounds @@ -837,7 +836,7 @@ fn impl_struct_by_extracting_all_at_once( req: ::axum::http::Request<B>, state: &#state, ) -> ::std::result::Result<Self, Self::Rejection> { - ::axum::extract::FromRequest::from_request(req, state) + <#via_path<#via_type_generics> as ::axum::extract::FromRequest<_, _>>::from_request(req, state) .await .map(|#via_path(value)| #value_to_self) .map_err(#map_err) @@ -847,11 +846,10 @@ fn impl_struct_by_extracting_all_at_once( } Trait::FromRequestParts => { quote_spanned! {path_span=> - #[::axum::async_trait] #[automatically_derived] impl<#impl_generics> ::axum::extract::FromRequestParts<#trait_generics> for #ident #ident_generics where - #via_path<#via_type_generics>: ::axum::extract::FromRequestParts<#trait_generics>, + #via_path<#via_type_generics>: ::axum::extract::FromRequestParts<#trait_generics> + 'static, #rejection_bound #state_bounds { @@ -861,7 +859,7 @@ fn impl_struct_by_extracting_all_at_once( parts: &mut ::axum::http::request::Parts, state: &#state, ) -> ::std::result::Result<Self, Self::Rejection> { - ::axum::extract::FromRequestParts::from_request_parts(parts, state) + <#via_path<#via_type_generics> as ::axum::extract::FromRequestParts<_>>::from_request_parts(parts, state) .await .map(|#via_path(value)| #value_to_self) .map_err(#map_err) @@ -938,7 +936,6 @@ fn impl_enum_by_extracting_all_at_once( let tokens = match tr { Trait::FromRequest => { quote_spanned! {path_span=> - #[::axum::async_trait] #[automatically_derived] impl<#impl_generics> ::axum::extract::FromRequest<#trait_generics> for #ident where @@ -953,7 +950,7 @@ fn impl_enum_by_extracting_all_at_once( req: ::axum::http::Request<B>, state: &#state, ) -> ::std::result::Result<Self, Self::Rejection> { - ::axum::extract::FromRequest::from_request(req, state) + <#path as ::axum::extract::FromRequest<_, _>>::from_request(req, state) .await .map(|#path(inner)| inner) .map_err(#map_err) @@ -963,7 +960,6 @@ fn impl_enum_by_extracting_all_at_once( } Trait::FromRequestParts => { quote_spanned! {path_span=> - #[::axum::async_trait] #[automatically_derived] impl<#impl_generics> ::axum::extract::FromRequestParts<#trait_generics> for #ident where @@ -975,7 +971,7 @@ fn impl_enum_by_extracting_all_at_once( parts: &mut ::axum::http::request::Parts, state: &#state, ) -> ::std::result::Result<Self, Self::Rejection> { - ::axum::extract::FromRequestParts::from_request_parts(parts, state) + <#path as ::axum::extract::FromRequestParts<_>>::from_request_parts(parts, state) .await .map(|#path(inner)| inner) .map_err(#map_err) diff --git a/axum-macros/src/lib.rs b/axum-macros/src/lib.rs index 43741ddf..680e19ee 100644 --- a/axum-macros/src/lib.rs +++ b/axum-macros/src/lib.rs @@ -191,7 +191,6 @@ use from_request::Trait::{FromRequest, FromRequestParts}; /// http::StatusCode, /// headers::ContentType, /// body::Bytes, -/// async_trait, /// }; /// /// #[derive(FromRequest)] diff --git a/axum-macros/src/typed_path.rs b/axum-macros/src/typed_path.rs index 6a50886f..e9f33870 100644 --- a/axum-macros/src/typed_path.rs +++ b/axum-macros/src/typed_path.rs @@ -133,7 +133,6 @@ fn expand_named_fields( let map_err_rejection = map_err_rejection(&rejection); let from_request_impl = quote! { - #[::axum::async_trait] #[automatically_derived] impl<S> ::axum::extract::FromRequestParts<S> for #ident where @@ -238,7 +237,6 @@ fn expand_unnamed_fields( let map_err_rejection = map_err_rejection(&rejection); let from_request_impl = quote! { - #[::axum::async_trait] #[automatically_derived] impl<S> ::axum::extract::FromRequestParts<S> for #ident where @@ -322,7 +320,6 @@ fn expand_unit_fields( }; let from_request_impl = quote! { - #[::axum::async_trait] #[automatically_derived] impl<S> ::axum::extract::FromRequestParts<S> for #ident where diff --git a/axum-macros/tests/debug_handler/fail/extract_self_mut.rs b/axum-macros/tests/debug_handler/fail/extract_self_mut.rs index d20426e2..3f5b44d8 100644 --- a/axum-macros/tests/debug_handler/fail/extract_self_mut.rs +++ b/axum-macros/tests/debug_handler/fail/extract_self_mut.rs @@ -1,13 +1,8 @@ -use axum::{ - async_trait, - extract::FromRequest, - http::Request, -}; +use axum::{extract::FromRequest, http::Request}; use axum_macros::debug_handler; struct A; -#[async_trait] impl<S, B> FromRequest<S, B> for A where B: Send + 'static, diff --git a/axum-macros/tests/debug_handler/fail/extract_self_ref.rs b/axum-macros/tests/debug_handler/fail/extract_self_ref.rs index 77940e29..c6f57aa5 100644 --- a/axum-macros/tests/debug_handler/fail/extract_self_ref.rs +++ b/axum-macros/tests/debug_handler/fail/extract_self_ref.rs @@ -1,13 +1,8 @@ -use axum::{ - async_trait, - extract::FromRequest, - http::Request, -}; +use axum::{extract::FromRequest, http::Request}; use axum_macros::debug_handler; struct A; -#[async_trait] impl<S, B> FromRequest<S, B> for A where B: Send + 'static, diff --git a/axum-macros/tests/debug_handler/pass/result_impl_into_response.rs b/axum-macros/tests/debug_handler/pass/result_impl_into_response.rs index 782fc930..f23c9b62 100644 --- a/axum-macros/tests/debug_handler/pass/result_impl_into_response.rs +++ b/axum-macros/tests/debug_handler/pass/result_impl_into_response.rs @@ -1,4 +1,4 @@ -use axum::{async_trait, extract::FromRequestParts, http::request::Parts, response::IntoResponse}; +use axum::{extract::FromRequestParts, http::request::Parts, response::IntoResponse}; use axum_macros::debug_handler; fn main() {} @@ -115,7 +115,6 @@ impl A { } } -#[async_trait] impl<S> FromRequestParts<S> for A where S: Send + Sync, diff --git a/axum-macros/tests/debug_handler/pass/self_receiver.rs b/axum-macros/tests/debug_handler/pass/self_receiver.rs index e7bf81ce..2c1a052b 100644 --- a/axum-macros/tests/debug_handler/pass/self_receiver.rs +++ b/axum-macros/tests/debug_handler/pass/self_receiver.rs @@ -1,13 +1,8 @@ -use axum::{ - async_trait, - extract::FromRequest, - http::Request, -}; +use axum::{extract::FromRequest, http::Request}; use axum_macros::debug_handler; struct A; -#[async_trait] impl<S, B> FromRequest<S, B> for A where B: Send + 'static, @@ -20,7 +15,6 @@ where } } -#[async_trait] impl<S, B> FromRequest<S, B> for Box<A> where B: Send + 'static, diff --git a/axum-macros/tests/debug_handler/pass/set_state.rs b/axum-macros/tests/debug_handler/pass/set_state.rs index 5c84dbd2..c710bd9b 100644 --- a/axum-macros/tests/debug_handler/pass/set_state.rs +++ b/axum-macros/tests/debug_handler/pass/set_state.rs @@ -1,7 +1,6 @@ -use axum_macros::debug_handler; use axum::extract::{FromRef, FromRequest}; -use axum::async_trait; use axum::http::Request; +use axum_macros::debug_handler; #[debug_handler(state = AppState)] async fn handler(_: A) {} @@ -11,7 +10,6 @@ struct AppState; struct A; -#[async_trait] impl<S, B> FromRequest<S, B> for A where B: Send + 'static, diff --git a/axum-macros/tests/from_request/pass/override_rejection.rs b/axum-macros/tests/from_request/pass/override_rejection.rs index 0147c9a8..066e004f 100644 --- a/axum-macros/tests/from_request/pass/override_rejection.rs +++ b/axum-macros/tests/from_request/pass/override_rejection.rs @@ -1,7 +1,6 @@ use axum::{ - async_trait, extract::{rejection::ExtensionRejection, FromRequest}, - http::{StatusCode, Request}, + http::{Request, StatusCode}, response::{IntoResponse, Response}, routing::get, Extension, Router, @@ -26,7 +25,6 @@ struct MyExtractor { struct OtherExtractor; -#[async_trait] impl<S, B> FromRequest<S, B> for OtherExtractor where B: Send + 'static, diff --git a/axum-macros/tests/from_request/pass/override_rejection_parts.rs b/axum-macros/tests/from_request/pass/override_rejection_parts.rs index 8ef9cb22..7cc27de2 100644 --- a/axum-macros/tests/from_request/pass/override_rejection_parts.rs +++ b/axum-macros/tests/from_request/pass/override_rejection_parts.rs @@ -1,5 +1,4 @@ use axum::{ - async_trait, extract::{rejection::ExtensionRejection, FromRequestParts}, http::{request::Parts, StatusCode}, response::{IntoResponse, Response}, @@ -26,7 +25,6 @@ struct MyExtractor { struct OtherExtractor; -#[async_trait] impl<S> FromRequestParts<S> for OtherExtractor where S: Send + Sync, diff --git a/axum/Cargo.toml b/axum/Cargo.toml index 06d73f04..a4879153 100644 --- a/axum/Cargo.toml +++ b/axum/Cargo.toml @@ -30,7 +30,6 @@ ws = ["tokio", "dep:tokio-tungstenite", "dep:sha-1", "dep:base64"] __private_docs = ["tower/full", "tower-http/full"] [dependencies] -async-trait = "0.1.43" axum-core = { path = "../axum-core", version = "=0.3.0-rc.3" } bitflags = "1.0" bytes = "1.0" diff --git a/axum/src/docs/extract.md b/axum/src/docs/extract.md index e002a8b7..e7862ca2 100644 --- a/axum/src/docs/extract.md +++ b/axum/src/docs/extract.md @@ -423,7 +423,6 @@ use axum::{ struct ExtractUserAgent(HeaderValue); -#[async_trait] impl<S> FromRequestParts<S> for ExtractUserAgent where S: Send + Sync, @@ -470,7 +469,6 @@ use axum::{ struct ValidatedBody(Bytes); -#[async_trait] impl<S, B> FromRequest<S, B> for ValidatedBody where Bytes: FromRequest<S, B>, @@ -520,7 +518,6 @@ use std::convert::Infallible; struct MyExtractor; // `MyExtractor` implements both `FromRequest` -#[async_trait] impl<S, B> FromRequest<S, B> for MyExtractor where S: Send + Sync, @@ -535,7 +532,6 @@ where } // and `FromRequestParts` -#[async_trait] impl<S> FromRequestParts<S> for MyExtractor where S: Send + Sync, @@ -587,7 +583,6 @@ struct AuthenticatedUser { // ... } -#[async_trait] impl<S> FromRequestParts<S> for AuthenticatedUser where S: Send + Sync, @@ -777,7 +772,6 @@ struct Timing<E> { } // we must implement both `FromRequestParts` -#[async_trait] impl<S, T> FromRequestParts<S> for Timing<T> where S: Send + Sync, @@ -797,7 +791,6 @@ where } // and `FromRequest` -#[async_trait] impl<S, B, T> FromRequest<S, B> for Timing<T> where B: Send + 'static, diff --git a/axum/src/extension.rs b/axum/src/extension.rs index 575d62ca..4396c2ca 100644 --- a/axum/src/extension.rs +++ b/axum/src/extension.rs @@ -1,5 +1,4 @@ use crate::{extract::rejection::*, response::IntoResponseParts}; -use async_trait::async_trait; use axum_core::{ extract::FromRequestParts, response::{IntoResponse, Response, ResponseParts}, @@ -72,7 +71,6 @@ use tower_service::Service; #[derive(Debug, Clone, Copy, Default)] pub struct Extension<T>(pub T); -#[async_trait] impl<T, S> FromRequestParts<S> for Extension<T> where T: Clone + Send + Sync + 'static, diff --git a/axum/src/extract/connect_info.rs b/axum/src/extract/connect_info.rs index fff2b46f..ae33588e 100644 --- a/axum/src/extract/connect_info.rs +++ b/axum/src/extract/connect_info.rs @@ -6,7 +6,6 @@ use super::{Extension, FromRequestParts}; use crate::middleware::AddExtension; -use async_trait::async_trait; use http::request::Parts; use hyper::server::conn::AddrStream; use std::{ @@ -128,7 +127,6 @@ opaque_future! { #[derive(Clone, Copy, Debug)] pub struct ConnectInfo<T>(pub T); -#[async_trait] impl<S, T> FromRequestParts<S> for ConnectInfo<T> where S: Send + Sync, diff --git a/axum/src/extract/host.rs b/axum/src/extract/host.rs index f92a6227..9cf0c638 100644 --- a/axum/src/extract/host.rs +++ b/axum/src/extract/host.rs @@ -2,7 +2,6 @@ use super::{ rejection::{FailedToResolveHost, HostRejection}, FromRequestParts, }; -use async_trait::async_trait; use http::{ header::{HeaderMap, FORWARDED}, request::Parts, @@ -23,7 +22,6 @@ const X_FORWARDED_HOST_HEADER_KEY: &str = "X-Forwarded-Host"; #[derive(Debug, Clone)] pub struct Host(pub String); -#[async_trait] impl<S> FromRequestParts<S> for Host where S: Send + Sync, diff --git a/axum/src/extract/matched_path.rs b/axum/src/extract/matched_path.rs index 064a9726..a70a6a3a 100644 --- a/axum/src/extract/matched_path.rs +++ b/axum/src/extract/matched_path.rs @@ -1,6 +1,5 @@ use super::{rejection::*, FromRequestParts}; use crate::routing::{RouteId, NEST_TAIL_PARAM_CAPTURE}; -use async_trait::async_trait; use http::request::Parts; use std::{collections::HashMap, sync::Arc}; @@ -104,7 +103,6 @@ impl MatchedPath { } } -#[async_trait] impl<S> FromRequestParts<S> for MatchedPath where S: Send + Sync, diff --git a/axum/src/extract/multipart.rs b/axum/src/extract/multipart.rs index 76dd52de..493b4674 100644 --- a/axum/src/extract/multipart.rs +++ b/axum/src/extract/multipart.rs @@ -5,7 +5,6 @@ use super::{BodyStream, FromRequest}; use crate::body::{Bytes, HttpBody}; use crate::BoxError; -use async_trait::async_trait; use axum_core::RequestExt; use futures_util::stream::Stream; use http::header::{HeaderMap, CONTENT_TYPE}; @@ -54,7 +53,6 @@ pub struct Multipart { inner: multer::Multipart<'static>, } -#[async_trait] impl<S, B> FromRequest<S, B> for Multipart where B: HttpBody + Send + 'static, diff --git a/axum/src/extract/path/mod.rs b/axum/src/extract/path/mod.rs index ad4e5eb4..78123591 100644 --- a/axum/src/extract/path/mod.rs +++ b/axum/src/extract/path/mod.rs @@ -7,7 +7,6 @@ use crate::{ extract::{rejection::*, FromRequestParts}, routing::url_params::UrlParams, }; -use async_trait::async_trait; use axum_core::response::{IntoResponse, Response}; use http::{request::Parts, StatusCode}; use serde::de::DeserializeOwned; @@ -166,10 +165,9 @@ impl<T> DerefMut for Path<T> { } } -#[async_trait] impl<T, S> FromRequestParts<S> for Path<T> where - T: DeserializeOwned + Send, + T: DeserializeOwned + Send + 'static, S: Send + Sync, { type Rejection = PathRejection; diff --git a/axum/src/extract/query.rs b/axum/src/extract/query.rs index 23cb02dc..39d14acf 100644 --- a/axum/src/extract/query.rs +++ b/axum/src/extract/query.rs @@ -1,5 +1,4 @@ use super::{rejection::*, FromRequestParts}; -use async_trait::async_trait; use http::request::Parts; use serde::de::DeserializeOwned; use std::ops::Deref; @@ -49,10 +48,9 @@ use std::ops::Deref; #[derive(Debug, Clone, Copy, Default)] pub struct Query<T>(pub T); -#[async_trait] impl<T, S> FromRequestParts<S> for Query<T> where - T: DeserializeOwned, + T: DeserializeOwned + 'static, S: Send + Sync, { type Rejection = QueryRejection; @@ -85,7 +83,7 @@ mod tests { async fn check<T>(uri: impl AsRef<str>, value: T) where - T: DeserializeOwned + PartialEq + Debug, + T: DeserializeOwned + PartialEq + Debug + 'static, { let req = Request::builder().uri(uri.as_ref()).body(()).unwrap(); assert_eq!(Query::<T>::from_request(req, &()).await.unwrap().0, value); diff --git a/axum/src/extract/raw_form.rs b/axum/src/extract/raw_form.rs index 3f9f67f6..c4fa7b40 100644 --- a/axum/src/extract/raw_form.rs +++ b/axum/src/extract/raw_form.rs @@ -1,4 +1,3 @@ -use async_trait::async_trait; use axum_core::extract::FromRequest; use bytes::{Bytes, BytesMut}; use http::{Method, Request}; @@ -34,7 +33,6 @@ use crate::{body::HttpBody, BoxError}; #[derive(Debug)] pub struct RawForm(pub Bytes); -#[async_trait] impl<S, B> FromRequest<S, B> for RawForm where B: HttpBody + Send + 'static, diff --git a/axum/src/extract/raw_query.rs b/axum/src/extract/raw_query.rs index 0e507cfc..744f87ed 100644 --- a/axum/src/extract/raw_query.rs +++ b/axum/src/extract/raw_query.rs @@ -1,5 +1,4 @@ use super::FromRequestParts; -use async_trait::async_trait; use http::request::Parts; use std::convert::Infallible; @@ -27,7 +26,6 @@ use std::convert::Infallible; #[derive(Debug)] pub struct RawQuery(pub Option<String>); -#[async_trait] impl<S> FromRequestParts<S> for RawQuery where S: Send + Sync, diff --git a/axum/src/extract/request_parts.rs b/axum/src/extract/request_parts.rs index 933e7a71..6e459dac 100644 --- a/axum/src/extract/request_parts.rs +++ b/axum/src/extract/request_parts.rs @@ -3,7 +3,6 @@ use crate::{ body::{Body, Bytes, HttpBody}, BoxError, Error, }; -use async_trait::async_trait; use futures_util::stream::Stream; use http::{request::Parts, Request, Uri}; use std::{ @@ -85,7 +84,6 @@ use sync_wrapper::SyncWrapper; pub struct OriginalUri(pub Uri); #[cfg(feature = "original-uri")] -#[async_trait] impl<S> FromRequestParts<S> for OriginalUri where S: Send + Sync, @@ -145,7 +143,6 @@ impl Stream for BodyStream { } } -#[async_trait] impl<S, B> FromRequest<S, B> for BodyStream where B: HttpBody + Send + 'static, @@ -208,10 +205,9 @@ fn body_stream_traits() { #[derive(Debug, Default, Clone)] pub struct RawBody<B = Body>(pub B); -#[async_trait] impl<S, B> FromRequest<S, B> for RawBody<B> where - B: Send, + B: Send + 'static, S: Send + Sync, { type Rejection = Infallible; diff --git a/axum/src/extract/state.rs b/axum/src/extract/state.rs index 966d72a0..35291ed2 100644 --- a/axum/src/extract/state.rs +++ b/axum/src/extract/state.rs @@ -1,4 +1,3 @@ -use async_trait::async_trait; use axum_core::extract::{FromRef, FromRequestParts}; use http::request::Parts; use std::{ @@ -8,7 +7,7 @@ use std::{ /// Extractor for state. /// -/// See ["Accessing state in middleware"][state-from-middleware] for how to +/// See ["Accessing state in middleware"][state-from-middleware] for how to /// access state in middleware. /// /// [state-from-middleware]: crate::middleware#accessing-state-in-middleware @@ -151,13 +150,11 @@ use std::{ /// ```rust /// use axum_core::extract::{FromRequestParts, FromRef}; /// use http::request::Parts; -/// use async_trait::async_trait; /// use std::convert::Infallible; /// /// // the extractor your library provides /// struct MyLibraryExtractor; /// -/// #[async_trait] /// impl<S> FromRequestParts<S> for MyLibraryExtractor /// where /// // keep `S` generic but require that it can produce a `MyLibraryState` @@ -231,10 +228,9 @@ use std::{ #[derive(Debug, Default, Clone, Copy)] pub struct State<S>(pub S); -#[async_trait] impl<OuterState, InnerState> FromRequestParts<OuterState> for State<InnerState> where - InnerState: FromRef<OuterState>, + InnerState: FromRef<OuterState> + 'static, OuterState: Send + Sync, { type Rejection = Infallible; diff --git a/axum/src/extract/ws.rs b/axum/src/extract/ws.rs index 2f55a6ba..8284a052 100644 --- a/axum/src/extract/ws.rs +++ b/axum/src/extract/ws.rs @@ -101,7 +101,6 @@ use crate::{ response::Response, Error, }; -use async_trait::async_trait; use futures_util::{ sink::{Sink, SinkExt}, stream::{Stream, StreamExt}, @@ -368,7 +367,6 @@ impl OnFailedUpdgrade for DefaultOnFailedUpdgrade { fn call(self, _error: Error) {} } -#[async_trait] impl<S> FromRequestParts<S> for WebSocketUpgrade<DefaultOnFailedUpdgrade> where S: Send + Sync, diff --git a/axum/src/form.rs b/axum/src/form.rs index c30b2260..43e13833 100644 --- a/axum/src/form.rs +++ b/axum/src/form.rs @@ -1,7 +1,6 @@ use crate::body::HttpBody; use crate::extract::{rejection::*, FromRequest, RawForm}; use crate::BoxError; -use async_trait::async_trait; use axum_core::response::{IntoResponse, Response}; use axum_core::RequestExt; use http::header::CONTENT_TYPE; @@ -61,10 +60,9 @@ use std::ops::Deref; #[derive(Debug, Clone, Copy, Default)] pub struct Form<T>(pub T); -#[async_trait] impl<T, S, B> FromRequest<S, B> for Form<T> where - T: DeserializeOwned, + T: DeserializeOwned + 'static, B: HttpBody + Send + 'static, B::Data: Send, B::Error: Into<BoxError>, @@ -126,7 +124,10 @@ mod tests { page: Option<u64>, } - async fn check_query<T: DeserializeOwned + PartialEq + Debug>(uri: impl AsRef<str>, value: T) { + async fn check_query<T: DeserializeOwned + PartialEq + Debug + 'static>( + uri: impl AsRef<str>, + value: T, + ) { let req = Request::builder() .uri(uri.as_ref()) .body(Empty::<Bytes>::new()) @@ -134,7 +135,7 @@ mod tests { assert_eq!(Form::<T>::from_request(req, &()).await.unwrap().0, value); } - async fn check_body<T: Serialize + DeserializeOwned + PartialEq + Debug>(value: T) { + async fn check_body<T: Serialize + DeserializeOwned + PartialEq + Debug + 'static>(value: T) { let req = Request::builder() .uri("http://example.com/test") .method(Method::POST) diff --git a/axum/src/json.rs b/axum/src/json.rs index ca52e069..568d451b 100644 --- a/axum/src/json.rs +++ b/axum/src/json.rs @@ -3,7 +3,6 @@ use crate::{ extract::{rejection::*, FromRequest}, BoxError, }; -use async_trait::async_trait; use axum_core::response::{IntoResponse, Response}; use bytes::{BufMut, BytesMut}; use http::{ @@ -99,10 +98,9 @@ use std::ops::{Deref, DerefMut}; #[cfg_attr(docsrs, doc(cfg(feature = "json")))] pub struct Json<T>(pub T); -#[async_trait] impl<T, S, B> FromRequest<S, B> for Json<T> where - T: DeserializeOwned, + T: DeserializeOwned + 'static, B: HttpBody + Send + 'static, B::Data: Send, B::Error: Into<BoxError>, diff --git a/axum/src/lib.rs b/axum/src/lib.rs index 60221147..3f372aca 100644 --- a/axum/src/lib.rs +++ b/axum/src/lib.rs @@ -391,6 +391,7 @@ //! [`axum-core`]: http://crates.io/crates/axum-core //! [`State`]: crate::extract::State +#![feature(async_fn_in_trait)] #![cfg_attr(nightly_error_messages, feature(rustc_attrs))] #![warn( clippy::all, @@ -428,7 +429,11 @@ missing_docs )] #![deny(unreachable_pub, private_in_public)] -#![allow(elided_lifetimes_in_paths, clippy::type_complexity)] +#![allow( + elided_lifetimes_in_paths, + incomplete_features, + clippy::type_complexity +)] #![forbid(unsafe_code)] #![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg))] #![cfg_attr(test, allow(clippy::float_cmp))] @@ -458,8 +463,6 @@ pub mod routing; #[cfg(test)] mod test_helpers; -#[doc(no_inline)] -pub use async_trait::async_trait; #[cfg(feature = "headers")] #[doc(no_inline)] pub use headers; diff --git a/axum/src/middleware/from_extractor.rs b/axum/src/middleware/from_extractor.rs index a6822af8..f4a75eaa 100644 --- a/axum/src/middleware/from_extractor.rs +++ b/axum/src/middleware/from_extractor.rs @@ -39,12 +39,10 @@ use tower_service::Service; /// Router, /// http::{header, StatusCode, request::Parts}, /// }; -/// use async_trait::async_trait; /// /// // An extractor that performs authorization. /// struct RequireAuth; /// -/// #[async_trait] /// impl<S> FromRequestParts<S> for RequireAuth /// where /// S: Send + Sync, @@ -200,7 +198,7 @@ where impl<T, E, B, S> Service<Request<B>> for FromExtractor<T, E, S> where - E: FromRequestParts<S> + 'static, + E: FromRequestParts<S>, B: Send + 'static, T: Service<Request<B>> + Clone, T::Response: IntoResponse, @@ -304,7 +302,7 @@ where #[cfg(test)] mod tests { use super::*; - use crate::{async_trait, handler::Handler, routing::get, test_helpers::*, Router}; + use crate::{handler::Handler, routing::get, test_helpers::*, Router}; use axum_core::extract::FromRef; use http::{header, request::Parts, StatusCode}; use tower_http::limit::RequestBodyLimitLayer; @@ -316,7 +314,6 @@ mod tests { struct RequireAuth; - #[async_trait::async_trait] impl<S> FromRequestParts<S> for RequireAuth where S: Send + Sync, @@ -369,7 +366,6 @@ mod tests { fn works_with_request_body_limit() { struct MyExtractor; - #[async_trait] impl<S> FromRequestParts<S> for MyExtractor where S: Send + Sync, diff --git a/axum/src/typed_header.rs b/axum/src/typed_header.rs index 87805a82..c4ffdf1e 100644 --- a/axum/src/typed_header.rs +++ b/axum/src/typed_header.rs @@ -1,5 +1,4 @@ use crate::extract::FromRequestParts; -use async_trait::async_trait; use axum_core::response::{IntoResponse, IntoResponseParts, Response, ResponseParts}; use headers::HeaderMapExt; use http::request::Parts; @@ -52,10 +51,9 @@ use std::{convert::Infallible, ops::Deref}; #[derive(Debug, Clone, Copy)] pub struct TypedHeader<T>(pub T); -#[async_trait] impl<T, S> FromRequestParts<S> for TypedHeader<T> where - T: headers::Header, + T: headers::Header + 'static, S: Send + Sync, { type Rejection = TypedHeaderRejection; diff --git a/examples/consume-body-in-extractor-or-middleware/src/main.rs b/examples/consume-body-in-extractor-or-middleware/src/main.rs index b3363d99..cc8ba2e6 100644 --- a/examples/consume-body-in-extractor-or-middleware/src/main.rs +++ b/examples/consume-body-in-extractor-or-middleware/src/main.rs @@ -4,8 +4,10 @@ //! cd examples && cargo run -p example-consume-body-in-extractor-or-middleware //! ``` +#![feature(async_fn_in_trait)] +#![allow(incomplete_features)] + use axum::{ - async_trait, body::{self, BoxBody, Bytes, Full}, extract::FromRequest, http::{Request, StatusCode}, @@ -80,7 +82,6 @@ async fn handler(BufferRequestBody(body): BufferRequestBody) { struct BufferRequestBody(Bytes); // we must implement `FromRequest` (and not `FromRequestParts`) to consume the body -#[async_trait] impl<S> FromRequest<S, BoxBody> for BufferRequestBody where S: Send + Sync, diff --git a/examples/customize-extractor-error/src/custom_extractor.rs b/examples/customize-extractor-error/src/custom_extractor.rs index d9093bc4..7aa37c93 100644 --- a/examples/customize-extractor-error/src/custom_extractor.rs +++ b/examples/customize-extractor-error/src/custom_extractor.rs @@ -5,7 +5,6 @@ //! - Boilerplate: Requires creating a new extractor for every custom rejection //! - Complexity: Manually implementing `FromRequest` results on more complex code use axum::{ - async_trait, extract::{rejection::JsonRejection, FromRequest, MatchedPath}, http::Request, http::StatusCode, @@ -21,10 +20,9 @@ pub async fn handler(Json(value): Json<Value>) -> impl IntoResponse { // We define our own `Json` extractor that customizes the error from `axum::Json` pub struct Json<T>(pub T); -#[async_trait] impl<S, B, T> FromRequest<S, B> for Json<T> where - axum::Json<T>: FromRequest<S, B, Rejection = JsonRejection>, + axum::Json<T>: FromRequest<S, B, Rejection = JsonRejection> + 'static, S: Send + Sync, B: Send + 'static, { diff --git a/examples/customize-extractor-error/src/derive_from_request.rs b/examples/customize-extractor-error/src/derive_from_request.rs index 762d602e..14c7ed2f 100644 --- a/examples/customize-extractor-error/src/derive_from_request.rs +++ b/examples/customize-extractor-error/src/derive_from_request.rs @@ -11,6 +11,7 @@ //! //! [`thiserror`]: https://crates.io/crates/thiserror //! [FromRequest#known-limitations]: https://docs.rs/axum-macros/*/axum_macros/derive.FromRequest.html#known-limitations + use axum::{extract::rejection::JsonRejection, http::StatusCode, response::IntoResponse}; use axum_macros::FromRequest; use serde_json::{json, Value}; diff --git a/examples/customize-extractor-error/src/main.rs b/examples/customize-extractor-error/src/main.rs index b7b24f76..56e6866e 100644 --- a/examples/customize-extractor-error/src/main.rs +++ b/examples/customize-extractor-error/src/main.rs @@ -4,6 +4,9 @@ //! cd examples && cargo run -p example-customize-extractor-error //! ``` +#![feature(async_fn_in_trait)] +#![allow(incomplete_features)] + mod custom_extractor; mod derive_from_request; mod with_rejection; diff --git a/examples/customize-path-rejection/src/main.rs b/examples/customize-path-rejection/src/main.rs index 68baf8f8..d74fe9a1 100644 --- a/examples/customize-path-rejection/src/main.rs +++ b/examples/customize-path-rejection/src/main.rs @@ -4,8 +4,10 @@ //! cd examples && cargo run -p example-customize-path-rejection //! ``` +#![feature(async_fn_in_trait)] +#![allow(incomplete_features)] + use axum::{ - async_trait, extract::{path::ErrorKind, rejection::PathRejection, FromRequestParts}, http::{request::Parts, StatusCode}, response::IntoResponse, @@ -51,11 +53,10 @@ struct Params { // We define our own `Path` extractor that customizes the error from `axum::extract::Path` struct Path<T>(T); -#[async_trait] impl<S, T> FromRequestParts<S> for Path<T> where // these trait bounds are copied from `impl FromRequest for axum::extract::path::Path` - T: DeserializeOwned + Send, + T: DeserializeOwned + Send + 'static, S: Send + Sync, { type Rejection = (StatusCode, axum::Json<PathError>); diff --git a/examples/error-handling-and-dependency-injection/Cargo.toml b/examples/error-handling-and-dependency-injection/Cargo.toml index 583ab15a..f275eb17 100644 --- a/examples/error-handling-and-dependency-injection/Cargo.toml +++ b/examples/error-handling-and-dependency-injection/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" publish = false [dependencies] +async-trait = "0.1.58" axum = { path = "../../axum" } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/examples/error-handling-and-dependency-injection/src/main.rs b/examples/error-handling-and-dependency-injection/src/main.rs index af897e3a..9678befc 100644 --- a/examples/error-handling-and-dependency-injection/src/main.rs +++ b/examples/error-handling-and-dependency-injection/src/main.rs @@ -7,8 +7,8 @@ //! cd examples && cargo run -p example-error-handling-and-dependency-injection //! ``` +use async_trait::async_trait; use axum::{ - async_trait, extract::{Path, State}, http::StatusCode, response::{IntoResponse, Response}, diff --git a/examples/jwt/src/main.rs b/examples/jwt/src/main.rs index 82633d96..07e041cb 100644 --- a/examples/jwt/src/main.rs +++ b/examples/jwt/src/main.rs @@ -6,8 +6,10 @@ //! JWT_SECRET=secret cargo run -p example-jwt //! ``` +#![feature(async_fn_in_trait)] +#![allow(incomplete_features)] + use axum::{ - async_trait, extract::{FromRequestParts, TypedHeader}, headers::{authorization::Bearer, Authorization}, http::{request::Parts, StatusCode}, @@ -121,7 +123,6 @@ impl AuthBody { } } -#[async_trait] impl<S> FromRequestParts<S> for Claims where S: Send + Sync, diff --git a/examples/key-value-store/src/main.rs b/examples/key-value-store/src/main.rs index 334e0e25..5d6c2bf7 100644 --- a/examples/key-value-store/src/main.rs +++ b/examples/key-value-store/src/main.rs @@ -26,7 +26,7 @@ use std::{ use tower::{BoxError, ServiceBuilder}; use tower_http::{ auth::RequireAuthorizationLayer, compression::CompressionLayer, limit::RequestBodyLimitLayer, - trace::TraceLayer, ServiceBuilderExt, + trace::TraceLayer, }; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; diff --git a/examples/oauth/src/main.rs b/examples/oauth/src/main.rs index ea692df8..36245c6e 100644 --- a/examples/oauth/src/main.rs +++ b/examples/oauth/src/main.rs @@ -8,9 +8,11 @@ //! CLIENT_ID=REPLACE_ME CLIENT_SECRET=REPLACE_ME cargo run -p example-oauth //! ``` +#![feature(async_fn_in_trait)] +#![allow(incomplete_features)] + use async_session::{MemoryStore, Session, SessionStore}; use axum::{ - async_trait, extract::{ rejection::TypedHeaderRejectionReason, FromRef, FromRequestParts, Query, State, TypedHeader, }, @@ -223,7 +225,6 @@ impl IntoResponse for AuthRedirect { } } -#[async_trait] impl<S> FromRequestParts<S> for User where MemoryStore: FromRef<S>, diff --git a/examples/parse-body-based-on-content-type/src/main.rs b/examples/parse-body-based-on-content-type/src/main.rs index 9167d1e0..d179e22c 100644 --- a/examples/parse-body-based-on-content-type/src/main.rs +++ b/examples/parse-body-based-on-content-type/src/main.rs @@ -6,8 +6,10 @@ //! cd examples && cargo run -p example-parse-body-based-on-content-type //! ``` +#![feature(async_fn_in_trait)] +#![allow(incomplete_features)] + use axum::{ - async_trait, extract::FromRequest, http::{header::CONTENT_TYPE, Request, StatusCode}, response::{IntoResponse, Response}, @@ -56,7 +58,6 @@ enum JsonOrForm<T, K = T> { Form(K), } -#[async_trait] impl<S, B, T, U> FromRequest<S, B> for JsonOrForm<T, U> where B: Send + 'static, diff --git a/examples/sessions/src/main.rs b/examples/sessions/src/main.rs index 716ee41a..1d4d2641 100644 --- a/examples/sessions/src/main.rs +++ b/examples/sessions/src/main.rs @@ -4,9 +4,11 @@ //! cd examples && cargo run -p example-sessions //! ``` +#![feature(async_fn_in_trait)] +#![allow(incomplete_features)] + use async_session::{MemoryStore, Session, SessionStore as _}; use axum::{ - async_trait, extract::{FromRef, FromRequestParts, TypedHeader}, headers::Cookie, http::{ @@ -80,7 +82,6 @@ enum UserIdFromSession { CreatedFreshUserId(FreshUserId), } -#[async_trait] impl<S> FromRequestParts<S> for UserIdFromSession where MemoryStore: FromRef<S>, diff --git a/examples/sqlx-postgres/src/main.rs b/examples/sqlx-postgres/src/main.rs index 0330edab..ef85d2c7 100644 --- a/examples/sqlx-postgres/src/main.rs +++ b/examples/sqlx-postgres/src/main.rs @@ -13,8 +13,10 @@ //! curl -X POST 127.0.0.1:3000 //! ``` +#![feature(async_fn_in_trait)] +#![allow(incomplete_features)] + use axum::{ - async_trait, extract::{FromRef, FromRequestParts, State}, http::{request::Parts, StatusCode}, routing::get, @@ -76,7 +78,6 @@ async fn using_connection_pool_extractor( // which setup is appropriate depends on your application struct DatabaseConnection(sqlx::pool::PoolConnection<sqlx::Postgres>); -#[async_trait] impl<S> FromRequestParts<S> for DatabaseConnection where PgPool: FromRef<S>, diff --git a/examples/tokio-postgres/src/main.rs b/examples/tokio-postgres/src/main.rs index faef52b5..f23b49ad 100644 --- a/examples/tokio-postgres/src/main.rs +++ b/examples/tokio-postgres/src/main.rs @@ -4,8 +4,10 @@ //! cd examples && cargo run -p example-tokio-postgres //! ``` +#![feature(async_fn_in_trait)] +#![allow(incomplete_features)] + use axum::{ - async_trait, extract::{FromRef, FromRequestParts, State}, http::{request::Parts, StatusCode}, routing::get, @@ -69,7 +71,6 @@ async fn using_connection_pool_extractor( // which setup is appropriate depends on your application struct DatabaseConnection(PooledConnection<'static, PostgresConnectionManager<NoTls>>); -#[async_trait] impl<S> FromRequestParts<S> for DatabaseConnection where ConnectionPool: FromRef<S>, diff --git a/examples/validator/Cargo.toml b/examples/validator/Cargo.toml index 8c35019f..816a22d3 100644 --- a/examples/validator/Cargo.toml +++ b/examples/validator/Cargo.toml @@ -5,7 +5,6 @@ publish = false version = "0.1.0" [dependencies] -async-trait = "0.1" axum = { path = "../../axum" } http-body = "0.4.3" serde = { version = "1.0", features = ["derive"] } diff --git a/examples/validator/src/main.rs b/examples/validator/src/main.rs index 359be614..808f2084 100644 --- a/examples/validator/src/main.rs +++ b/examples/validator/src/main.rs @@ -10,7 +10,9 @@ //! -> <h1>Hello, LT!</h1> //! ``` -use async_trait::async_trait; +#![feature(async_fn_in_trait)] +#![allow(incomplete_features)] + use axum::{ extract::{rejection::FormRejection, Form, FromRequest}, http::{Request, StatusCode}, @@ -59,10 +61,9 @@ async fn handler(ValidatedForm(input): ValidatedForm<NameInput>) -> Html<String> #[derive(Debug, Clone, Copy, Default)] pub struct ValidatedForm<T>(pub T); -#[async_trait] impl<T, S, B> FromRequest<S, B> for ValidatedForm<T> where - T: DeserializeOwned + Validate, + T: DeserializeOwned + Validate + 'static, S: Send + Sync, Form<T>: FromRequest<S, B, Rejection = FormRejection>, B: Send + 'static, diff --git a/examples/versioning/src/main.rs b/examples/versioning/src/main.rs index 6948eb1d..f1e141a6 100644 --- a/examples/versioning/src/main.rs +++ b/examples/versioning/src/main.rs @@ -4,8 +4,10 @@ //! cd examples && cargo run -p example-versioning //! ``` +#![feature(async_fn_in_trait)] +#![allow(incomplete_features)] + use axum::{ - async_trait, extract::{FromRequestParts, Path}, http::{request::Parts, StatusCode}, response::{IntoResponse, Response}, @@ -47,7 +49,6 @@ enum Version { V3, } -#[async_trait] impl<S> FromRequestParts<S> for Version where S: Send + Sync,