#![doc = include_str!("readme.md")]
use http::{Method, Uri, Version, header::HeaderMap};
use serde::de::DeserializeOwned;
use std::fmt;
#[derive(Debug)]
pub struct RequestParts {
pub method: Method,
pub uri: Uri,
pub version: Version,
pub headers: HeaderMap,
pub path_params: Vec<(String, String)>,
}
impl RequestParts {
pub fn new(method: Method, uri: Uri, version: Version, headers: HeaderMap) -> Self {
Self { method, uri, version, headers, path_params: Vec::new() }
}
}
pub trait FromRequestParts<S>: Sized {
type Error;
fn from_request_parts(parts: &RequestParts, state: &S) -> Result<Self, Self::Error>;
}
#[derive(Debug)]
pub enum ExtractorError {
PathRejection(String),
QueryRejection(String),
JsonRejection(String),
FormRejection(String),
ExtensionRejection(String),
HostRejection(String),
TypedHeaderRejection(String),
CookieRejection(String),
MultipartRejection(String),
WebSocketUpgradeRejection(String),
BytesRejection(String),
StreamRejection(String),
Custom(String),
}
impl fmt::Display for ExtractorError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ExtractorError::PathRejection(e) => write!(f, "Path extraction failed: {}", e),
ExtractorError::QueryRejection(e) => write!(f, "Query extraction failed: {}", e),
ExtractorError::JsonRejection(e) => write!(f, "Json extraction failed: {}", e),
ExtractorError::FormRejection(e) => write!(f, "Form extraction failed: {}", e),
ExtractorError::ExtensionRejection(e) => write!(f, "Extension extraction failed: {}", e),
ExtractorError::HostRejection(e) => write!(f, "Host extraction failed: {}", e),
ExtractorError::TypedHeaderRejection(e) => write!(f, "TypedHeader extraction failed: {}", e),
ExtractorError::CookieRejection(e) => write!(f, "Cookie extraction failed: {}", e),
ExtractorError::MultipartRejection(e) => write!(f, "Multipart extraction failed: {}", e),
ExtractorError::WebSocketUpgradeRejection(e) => write!(f, "WebSocketUpgrade extraction failed: {}", e),
ExtractorError::BytesRejection(e) => write!(f, "Bytes extraction failed: {}", e),
ExtractorError::StreamRejection(e) => write!(f, "Stream extraction failed: {}", e),
ExtractorError::Custom(msg) => write!(f, "Extractor error: {}", msg),
}
}
}
impl std::error::Error for ExtractorError {}
#[derive(Debug, Clone)]
pub struct Path<T>(pub T);
impl<T, S> FromRequestParts<S> for Path<T>
where
T: std::str::FromStr,
T::Err: std::fmt::Display,
{
type Error = ExtractorError;
fn from_request_parts(parts: &RequestParts, _state: &S) -> Result<Self, Self::Error> {
if let Some((_, value)) = parts.path_params.first() {
T::from_str(value)
.map(Path)
.map_err(|e| ExtractorError::PathRejection(format!("Failed to parse path parameter: {}", e)))
}
else {
Err(ExtractorError::PathRejection("No path parameters found".to_string()))
}
}
}
#[derive(Debug, Clone, serde::Deserialize)]
pub struct Query<T>(pub T);
impl<T, S> FromRequestParts<S> for Query<T>
where
T: DeserializeOwned,
{
type Error = ExtractorError;
fn from_request_parts(parts: &RequestParts, _state: &S) -> Result<Self, Self::Error> {
let query = parts.uri.query().unwrap_or_default();
serde_urlencoded::from_str(query)
.map(Query)
.map_err(|e| ExtractorError::QueryRejection(format!("Failed to parse query parameters: {}", e)))
}
}
#[derive(Debug, Clone, serde::Deserialize)]
pub struct Json<T>(pub T);
#[derive(Debug, Clone, serde::Deserialize)]
pub struct Form<T>(pub T);
#[derive(Debug, Clone)]
pub struct Header<T>(pub T);
pub type HttpMethod = Method;
impl<S> FromRequestParts<S> for HttpMethod {
type Error = ExtractorError;
fn from_request_parts(parts: &RequestParts, _state: &S) -> Result<Self, Self::Error> {
Ok(parts.method.clone())
}
}
pub type RequestUri = Uri;
impl<S> FromRequestParts<S> for RequestUri {
type Error = ExtractorError;
fn from_request_parts(parts: &RequestParts, _state: &S) -> Result<Self, Self::Error> {
Ok(parts.uri.clone())
}
}
impl<S> FromRequestParts<S> for RequestParts {
type Error = ExtractorError;
fn from_request_parts(parts: &RequestParts, _state: &S) -> Result<Self, Self::Error> {
Ok(parts.clone())
}
}
impl Clone for RequestParts {
fn clone(&self) -> Self {
Self {
method: self.method.clone(),
uri: self.uri.clone(),
version: self.version,
headers: self.headers.clone(),
path_params: self.path_params.clone(),
}
}
}
pub type HttpVersion = Version;
impl<S> FromRequestParts<S> for HttpVersion {
type Error = ExtractorError;
fn from_request_parts(parts: &RequestParts, _state: &S) -> Result<Self, Self::Error> {
Ok(parts.version)
}
}
pub type Headers = HeaderMap;
impl<S> FromRequestParts<S> for Headers {
type Error = ExtractorError;
fn from_request_parts(parts: &RequestParts, _state: &S) -> Result<Self, Self::Error> {
Ok(parts.headers.clone())
}
}
#[derive(Debug, Clone)]
pub struct Extension<T>(pub T);
#[derive(Debug, Clone)]
pub struct Multipart;
pub type OriginalUri = http::Uri;
#[derive(Debug, Clone)]
pub struct State<T>(pub T);
impl<T, S> FromRequestParts<S> for State<T>
where
T: Clone + Send + Sync + 'static,
S: std::ops::Deref<Target = T>,
{
type Error = ExtractorError;
fn from_request_parts(_parts: &RequestParts, state: &S) -> Result<Self, Self::Error> {
Ok(State(state.deref().clone()))
}
}
#[derive(Debug, Clone)]
pub struct WebSocketUpgrade;
pub type Stream = crate::Body;
macro_rules! impl_from_request_parts_tuple {
($($ty:ident),*) => {
#[allow(non_snake_case, unused_variables)]
impl<S, $($ty,)*> FromRequestParts<S> for ($($ty,)*)
where
$($ty: FromRequestParts<S, Error = ExtractorError>,)*
{
type Error = ExtractorError;
fn from_request_parts(parts: &RequestParts, state: &S) -> Result<Self, Self::Error> {
Ok(($(
$ty::from_request_parts(parts, state)?,
)*))
}
}
};
}
impl_from_request_parts_tuple!();
impl_from_request_parts_tuple!(T1);
impl_from_request_parts_tuple!(T1, T2);
impl_from_request_parts_tuple!(T1, T2, T3);
impl_from_request_parts_tuple!(T1, T2, T3, T4);
impl_from_request_parts_tuple!(T1, T2, T3, T4, T5);
impl_from_request_parts_tuple!(T1, T2, T3, T4, T5, T6);
impl_from_request_parts_tuple!(T1, T2, T3, T4, T5, T6, T7);
impl_from_request_parts_tuple!(T1, T2, T3, T4, T5, T6, T7, T8);
impl_from_request_parts_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9);
impl_from_request_parts_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
impl_from_request_parts_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
impl_from_request_parts_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
impl_from_request_parts_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13);
impl_from_request_parts_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14);
impl_from_request_parts_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15);
impl_from_request_parts_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16);