//! A module to parse query parameter with deserr use std::marker::PhantomData; use std::{fmt, ops}; use actix_http::Payload; use actix_utils::future::{err, ok, Ready}; use actix_web::{FromRequest, HttpRequest}; use deserr::{DeserializeError, DeserializeFromValue}; use meilisearch_types::error::{Code, ErrorCode, ResponseError}; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct QueryParameter(pub T, PhantomData<*const E>); impl QueryParameter { /// Unwrap into inner `T` value. pub fn into_inner(self) -> T { self.0 } } impl QueryParameter where T: DeserializeFromValue, E: DeserializeError + ErrorCode + std::error::Error + 'static, { pub fn from_query(query_str: &str) -> Result { let value = serde_urlencoded::from_str::(query_str) .map_err(|e| ResponseError::from_msg(e.to_string(), Code::BadRequest))?; match deserr::deserialize::<_, _, E>(value) { Ok(data) => Ok(QueryParameter(data, PhantomData)), Err(e) => Err(ResponseError::from(e).into()), } } } impl ops::Deref for QueryParameter { type Target = T; fn deref(&self) -> &T { &self.0 } } impl ops::DerefMut for QueryParameter { fn deref_mut(&mut self) -> &mut T { &mut self.0 } } impl fmt::Display for QueryParameter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } impl FromRequest for QueryParameter where T: DeserializeFromValue, E: DeserializeError + ErrorCode + std::error::Error + 'static, { type Error = actix_web::Error; type Future = Ready>; #[inline] fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future { QueryParameter::from_query(req.query_string()).map(ok).unwrap_or_else(err) } }