From 352cf9a266153d9480d832bde6243e0cef0903a0 Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Mon, 10 Apr 2023 09:18:35 +0200 Subject: [PATCH] Implement `Deref` and `DerefMut` for built-in extractors (#1922) --- axum-core/Cargo.toml | 2 +- axum-core/src/macros.rs | 41 +++++++++++++++++++++++++++++++ axum-extra/CHANGELOG.md | 2 ++ axum-extra/Cargo.toml | 1 + axum-extra/src/extract/cached.rs | 15 +---------- axum-extra/src/extract/form.rs | 10 ++------ axum-extra/src/extract/query.rs | 10 ++------ axum-extra/src/protobuf.rs | 15 +---------- axum/CHANGELOG.md | 2 +- axum/src/extension.rs | 9 +------ axum/src/extract/connect_info.rs | 2 ++ axum/src/extract/path/mod.rs | 22 ++--------------- axum/src/extract/query.rs | 9 +------ axum/src/extract/request_parts.rs | 5 ++++ axum/src/form.rs | 9 +------ axum/src/json.rs | 15 +---------- axum/src/typed_header.rs | 10 ++------ 17 files changed, 67 insertions(+), 112 deletions(-) diff --git a/axum-core/Cargo.toml b/axum-core/Cargo.toml index 5fb23124..cafa46d1 100644 --- a/axum-core/Cargo.toml +++ b/axum-core/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT" name = "axum-core" readme = "README.md" repository = "https://github.com/tokio-rs/axum" -version = "0.3.3" # remember to also bump the version that axum depends on +version = "0.3.3" # remember to also bump the version that axum and axum-extra depends on [features] __private_docs = ["dep:tower-http"] diff --git a/axum-core/src/macros.rs b/axum-core/src/macros.rs index a82f3bbd..58a74625 100644 --- a/axum-core/src/macros.rs +++ b/axum-core/src/macros.rs @@ -171,3 +171,44 @@ macro_rules! all_the_tuples_no_last_special_case { $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16); }; } + +/// Private API. +#[doc(hidden)] +#[macro_export] +macro_rules! __impl_deref { + ($ident:ident) => { + impl std::ops::Deref for $ident { + type Target = T; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + impl std::ops::DerefMut for $ident { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + }; + + ($ident:ident: $ty:ty) => { + impl std::ops::Deref for $ident { + type Target = $ty; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + impl std::ops::DerefMut for $ident { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + }; +} diff --git a/axum-extra/CHANGELOG.md b/axum-extra/CHANGELOG.md index 5149cf0a..ae20a0e8 100644 --- a/axum-extra/CHANGELOG.md +++ b/axum-extra/CHANGELOG.md @@ -7,9 +7,11 @@ and this project adheres to [Semantic Versioning]. # Unreleased +- **added:** Implement `Deref` and `DerefMut` for built-in extractors ([#1922]) - **added:** Add `OptionalPath` extractor ([#1889]) [#1889]: https://github.com/tokio-rs/axum/pull/1889 +[#1922]: https://github.com/tokio-rs/axum/pull/1922 # 0.7.2 (22. March, 2023) diff --git a/axum-extra/Cargo.toml b/axum-extra/Cargo.toml index 59f20df4..4f7515a0 100644 --- a/axum-extra/Cargo.toml +++ b/axum-extra/Cargo.toml @@ -35,6 +35,7 @@ typed-routing = ["dep:axum-macros", "dep:percent-encoding", "dep:serde_html_form [dependencies] axum = { path = "../axum", version = "0.6.9", default-features = false } +axum-core = { path = "../axum-core", version = "0.3.3" } bytes = "1.1.0" futures-util = { version = "0.3", default-features = false, features = ["alloc"] } http = "0.2" diff --git a/axum-extra/src/extract/cached.rs b/axum-extra/src/extract/cached.rs index 03565c77..35fbe324 100644 --- a/axum-extra/src/extract/cached.rs +++ b/axum-extra/src/extract/cached.rs @@ -3,7 +3,6 @@ use axum::{ extract::{Extension, FromRequestParts}, }; use http::request::Parts; -use std::ops::{Deref, DerefMut}; /// Cache results of other extractors. /// @@ -108,19 +107,7 @@ where } } -impl Deref for Cached { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for Cached { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} +axum_core::__impl_deref!(Cached); #[cfg(test)] mod tests { diff --git a/axum-extra/src/extract/form.rs b/axum-extra/src/extract/form.rs index df33e5ca..570b9126 100644 --- a/axum-extra/src/extract/form.rs +++ b/axum-extra/src/extract/form.rs @@ -7,7 +7,7 @@ use axum::{ }; use http::{Request, StatusCode}; use serde::de::DeserializeOwned; -use std::{fmt, ops::Deref}; +use std::fmt; /// Extractor that deserializes `application/x-www-form-urlencoded` requests /// into some type. @@ -43,13 +43,7 @@ use std::{fmt, ops::Deref}; #[cfg(feature = "form")] pub struct Form(pub T); -impl Deref for Form { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} +axum_core::__impl_deref!(Form); #[async_trait] impl FromRequest for Form diff --git a/axum-extra/src/extract/query.rs b/axum-extra/src/extract/query.rs index 7ff81085..43be2ec7 100644 --- a/axum-extra/src/extract/query.rs +++ b/axum-extra/src/extract/query.rs @@ -6,7 +6,7 @@ use axum::{ }; use http::{request::Parts, StatusCode}; use serde::de::DeserializeOwned; -use std::{fmt, ops::Deref}; +use std::fmt; /// Extractor that deserializes query strings into some type. /// @@ -73,13 +73,7 @@ where } } -impl Deref for Query { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} +axum_core::__impl_deref!(Query); /// Rejection used for [`Query`]. /// diff --git a/axum-extra/src/protobuf.rs b/axum-extra/src/protobuf.rs index 6da01175..1750c521 100644 --- a/axum-extra/src/protobuf.rs +++ b/axum-extra/src/protobuf.rs @@ -10,7 +10,6 @@ use axum::{ use bytes::BytesMut; use http::{Request, StatusCode}; use prost::Message; -use std::ops::{Deref, DerefMut}; /// A Protocol Buffer message extractor and response. /// @@ -118,19 +117,7 @@ where } } -impl Deref for Protobuf { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for Protobuf { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} +axum_core::__impl_deref!(Protobuf); impl From for Protobuf { fn from(inner: T) -> Self { diff --git a/axum/CHANGELOG.md b/axum/CHANGELOG.md index 684a9db4..1d6c6b53 100644 --- a/axum/CHANGELOG.md +++ b/axum/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 # Unreleased -- None. +- **added:** Implement `Deref` and `DerefMut` for built-in extractors # 0.6.12 (22. March, 2023) diff --git a/axum/src/extension.rs b/axum/src/extension.rs index 5f94cd69..d66c9466 100644 --- a/axum/src/extension.rs +++ b/axum/src/extension.rs @@ -7,7 +7,6 @@ use axum_core::{ use http::{request::Parts, Request}; use std::{ convert::Infallible, - ops::Deref, task::{Context, Poll}, }; use tower_service::Service; @@ -97,13 +96,7 @@ where } } -impl Deref for Extension { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} +axum_core::__impl_deref!(Extension); impl IntoResponseParts for Extension where diff --git a/axum/src/extract/connect_info.rs b/axum/src/extract/connect_info.rs index 7dd0c47d..f22b8981 100644 --- a/axum/src/extract/connect_info.rs +++ b/axum/src/extract/connect_info.rs @@ -147,6 +147,8 @@ where } } +axum_core::__impl_deref!(ConnectInfo); + /// Middleware used to mock [`ConnectInfo`] during tests. /// /// If you're accidentally using [`MockConnectInfo`] and diff --git a/axum/src/extract/path/mod.rs b/axum/src/extract/path/mod.rs index 93a039dd..65f5c092 100644 --- a/axum/src/extract/path/mod.rs +++ b/axum/src/extract/path/mod.rs @@ -12,11 +12,7 @@ use async_trait::async_trait; use axum_core::response::{IntoResponse, Response}; use http::{request::Parts, StatusCode}; use serde::de::DeserializeOwned; -use std::{ - fmt, - ops::{Deref, DerefMut}, - sync::Arc, -}; +use std::{fmt, sync::Arc}; /// Extractor that will get captures from the URL and parse them using /// [`serde`]. @@ -152,21 +148,7 @@ use std::{ #[derive(Debug)] pub struct Path(pub T); -impl Deref for Path { - type Target = T; - - #[inline] - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for Path { - #[inline] - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} +axum_core::__impl_deref!(Path); #[async_trait] impl FromRequestParts for Path diff --git a/axum/src/extract/query.rs b/axum/src/extract/query.rs index 10b523a4..f9551e07 100644 --- a/axum/src/extract/query.rs +++ b/axum/src/extract/query.rs @@ -2,7 +2,6 @@ use super::{rejection::*, FromRequestParts}; use async_trait::async_trait; use http::request::Parts; use serde::de::DeserializeOwned; -use std::ops::Deref; /// Extractor that deserializes query strings into some type. /// @@ -65,13 +64,7 @@ where } } -impl Deref for Query { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} +axum_core::__impl_deref!(Query); #[cfg(test)] mod tests { diff --git a/axum/src/extract/request_parts.rs b/axum/src/extract/request_parts.rs index b3a28bc4..9af618fa 100644 --- a/axum/src/extract/request_parts.rs +++ b/axum/src/extract/request_parts.rs @@ -101,6 +101,9 @@ where } } +#[cfg(feature = "original-uri")] +axum_core::__impl_deref!(OriginalUri: Uri); + /// Extractor that extracts the request body as a [`Stream`]. /// /// Since extracting the request body requires consuming it, the `BodyStream` extractor must be @@ -221,6 +224,8 @@ where } } +axum_core::__impl_deref!(RawBody); + #[cfg(test)] mod tests { use crate::{extract::Extension, routing::get, test_helpers::*, Router}; diff --git a/axum/src/form.rs b/axum/src/form.rs index 5318dd01..20804913 100644 --- a/axum/src/form.rs +++ b/axum/src/form.rs @@ -8,7 +8,6 @@ use http::header::CONTENT_TYPE; use http::{Request, StatusCode}; use serde::de::DeserializeOwned; use serde::Serialize; -use std::ops::Deref; /// URL encoded extractor and response. /// @@ -115,13 +114,7 @@ where } } -impl Deref for Form { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} +axum_core::__impl_deref!(Form); #[cfg(test)] mod tests { diff --git a/axum/src/json.rs b/axum/src/json.rs index e6d8588c..0f1775c8 100644 --- a/axum/src/json.rs +++ b/axum/src/json.rs @@ -11,7 +11,6 @@ use http::{ Request, StatusCode, }; use serde::{de::DeserializeOwned, Serialize}; -use std::ops::{Deref, DerefMut}; /// JSON Extractor / Response. /// @@ -170,19 +169,7 @@ fn json_content_type(headers: &HeaderMap) -> bool { is_json_content_type } -impl Deref for Json { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for Json { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} +axum_core::__impl_deref!(Json); impl From for Json { fn from(inner: T) -> Self { diff --git a/axum/src/typed_header.rs b/axum/src/typed_header.rs index 717bc240..72b3d7e7 100644 --- a/axum/src/typed_header.rs +++ b/axum/src/typed_header.rs @@ -3,7 +3,7 @@ use async_trait::async_trait; use axum_core::response::{IntoResponse, IntoResponseParts, Response, ResponseParts}; use headers::HeaderMapExt; use http::request::Parts; -use std::{convert::Infallible, ops::Deref}; +use std::convert::Infallible; /// Extractor and response that works with typed header values from [`headers`]. /// @@ -78,13 +78,7 @@ where } } -impl Deref for TypedHeader { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} +axum_core::__impl_deref!(TypedHeader); impl IntoResponseParts for TypedHeader where