From d4c9c001f8249c6203c90906e73933a9d86c62a8 Mon Sep 17 00:00:00 2001 From: Tamo Date: Tue, 14 Feb 2023 11:43:20 +0100 Subject: [PATCH] provide an extractor for the query parameters in actix-web --- Cargo.toml | 5 ++- src/actix_web/mod.rs | 4 ++ src/actix_web/query_parameters.rs | 71 +++++++++++++++++++++++++++++++ src/value.rs | 1 + 4 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 src/actix_web/query_parameters.rs diff --git a/Cargo.toml b/Cargo.toml index 6736f6c..5fad4fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,12 +17,15 @@ actix-web = { version = "4.3.0", optional = true } futures = { version = "0.3.25", optional = true } deserr-internal = { version = "=0.4.0", path = "derive" } strsim = "0.10.0" +actix-http = { version = "3.3.0", optional = true } +actix-utils = { version = "3.0.1", optional = true } +serde_urlencoded = "0.7.1" [features] default = ["serde-json", "serde-cs", "actix-web"] serde-json = ["serde_json"] serde-cs = ["dep:serde-cs"] -actix-web = ["dep:actix-web", "futures"] +actix-web = ["dep:actix-web", "futures", "actix-http", "actix-utils"] [dev-dependencies] automod = "1.0" diff --git a/src/actix_web/mod.rs b/src/actix_web/mod.rs index 716da7c..da06d58 100644 --- a/src/actix_web/mod.rs +++ b/src/actix_web/mod.rs @@ -1,5 +1,9 @@ #[cfg(feature = "serde-json")] +mod query_parameters; +#[cfg(feature = "serde-json")] mod serde_json; +#[cfg(feature = "serde-json")] +pub use self::query_parameters::AwebQueryParameter; #[cfg(feature = "serde-json")] pub use self::serde_json::{AwebJson, AwebJsonExtractFut}; diff --git a/src/actix_web/query_parameters.rs b/src/actix_web/query_parameters.rs new file mode 100644 index 0000000..ad40d21 --- /dev/null +++ b/src/actix_web/query_parameters.rs @@ -0,0 +1,71 @@ +//! A module to parse query parameter as String with deserr + +use std::marker::PhantomData; +use std::{fmt, ops}; + +use crate::{DeserializeError, Deserr}; +use actix_http::Payload; +use actix_utils::future::{err, ok, Ready}; +use actix_web::web::Query; +use actix_web::{FromRequest, HttpRequest, ResponseError}; + +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct AwebQueryParameter(pub T, PhantomData<*const E>); + +impl AwebQueryParameter { + /// Unwrap into inner `T` value. + pub fn into_inner(self) -> T { + self.0 + } +} + +impl AwebQueryParameter +where + T: Deserr, + E: DeserializeError + ResponseError + 'static, +{ + pub fn from_query(query_str: &str) -> Result { + let value = Query::::from_query(query_str)?; + + match deserr::deserialize::<_, _, E>(value.0) { + Ok(data) => Ok(AwebQueryParameter(data, PhantomData)), + Err(e) => Err(e)?, + } + } +} + +impl ops::Deref for AwebQueryParameter { + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } +} + +impl ops::DerefMut for AwebQueryParameter { + fn deref_mut(&mut self) -> &mut T { + &mut self.0 + } +} + +impl fmt::Display for AwebQueryParameter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl FromRequest for AwebQueryParameter +where + T: Deserr, + E: DeserializeError + ResponseError + 'static, +{ + type Error = actix_web::Error; + type Future = Ready>; + + #[inline] + fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future { + AwebQueryParameter::from_query(req.query_string()) + .map(ok) + .unwrap_or_else(err) + } +} diff --git a/src/value.rs b/src/value.rs index e9b1367..f6a3fc5 100644 --- a/src/value.rs +++ b/src/value.rs @@ -247,6 +247,7 @@ impl Sequence for Infallible { unreachable!() } } + impl Map for Infallible { type Value = Self; type Iter = std::iter::Empty<(String, Infallible)>;