2022-09-28 22:20:47 +02:00
|
|
|
use crate::extract::FromRequestParts;
|
2022-08-22 18:34:46 +02:00
|
|
|
use futures_util::future::BoxFuture;
|
|
|
|
|
use http::request::Parts;
|
|
|
|
|
|
|
|
|
|
mod sealed {
|
|
|
|
|
pub trait Sealed {}
|
|
|
|
|
impl Sealed for http::request::Parts {}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Extension trait that adds additional methods to [`Parts`].
|
|
|
|
|
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>>
|
|
|
|
|
where
|
|
|
|
|
E: FromRequestParts<()> + 'static;
|
|
|
|
|
|
|
|
|
|
/// Apply an extractor that requires some state to this `Parts`.
|
|
|
|
|
///
|
|
|
|
|
/// This is just a convenience for `E::from_request_parts(parts, state)`.
|
|
|
|
|
fn extract_with_state<'a, E, S>(
|
|
|
|
|
&'a mut self,
|
|
|
|
|
state: &'a S,
|
|
|
|
|
) -> BoxFuture<'a, Result<E, E::Rejection>>
|
|
|
|
|
where
|
|
|
|
|
E: FromRequestParts<S> + 'static,
|
|
|
|
|
S: Send + Sync;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl RequestPartsExt for Parts {
|
|
|
|
|
fn extract<E>(&mut self) -> BoxFuture<'_, Result<E, E::Rejection>>
|
|
|
|
|
where
|
|
|
|
|
E: FromRequestParts<()> + 'static,
|
|
|
|
|
{
|
|
|
|
|
self.extract_with_state(&())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn extract_with_state<'a, E, S>(
|
|
|
|
|
&'a mut self,
|
|
|
|
|
state: &'a S,
|
|
|
|
|
) -> BoxFuture<'a, Result<E, E::Rejection>>
|
|
|
|
|
where
|
|
|
|
|
E: FromRequestParts<S> + 'static,
|
|
|
|
|
S: Send + Sync,
|
|
|
|
|
{
|
|
|
|
|
E::from_request_parts(self, state)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use std::convert::Infallible;
|
|
|
|
|
|
|
|
|
|
use super::*;
|
2022-09-28 22:20:47 +02:00
|
|
|
use crate::{
|
|
|
|
|
ext_traits::tests::{RequiresState, State},
|
|
|
|
|
extract::FromRef,
|
|
|
|
|
};
|
2022-08-22 18:34:46 +02:00
|
|
|
use async_trait::async_trait;
|
|
|
|
|
use http::{Method, Request};
|
|
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
|
async fn extract_without_state() {
|
|
|
|
|
let (mut parts, _) = Request::new(()).into_parts();
|
|
|
|
|
|
|
|
|
|
let method: Method = parts.extract().await.unwrap();
|
|
|
|
|
|
|
|
|
|
assert_eq!(method, Method::GET);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
|
async fn extract_with_state() {
|
|
|
|
|
let (mut parts, _) = Request::new(()).into_parts();
|
|
|
|
|
|
|
|
|
|
let state = "state".to_owned();
|
|
|
|
|
|
2022-09-28 22:20:47 +02:00
|
|
|
let State(extracted_state): State<String> = parts
|
|
|
|
|
.extract_with_state::<State<String>, String>(&state)
|
|
|
|
|
.await
|
|
|
|
|
.unwrap();
|
2022-08-22 18:34:46 +02:00
|
|
|
|
|
|
|
|
assert_eq!(extracted_state, state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// this stuff just needs to compile
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
|
struct WorksForCustomExtractor {
|
|
|
|
|
method: Method,
|
|
|
|
|
from_state: String,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[async_trait]
|
|
|
|
|
impl<S> FromRequestParts<S> for WorksForCustomExtractor
|
|
|
|
|
where
|
|
|
|
|
S: Send + Sync,
|
|
|
|
|
String: FromRef<S>,
|
|
|
|
|
{
|
|
|
|
|
type Rejection = Infallible;
|
|
|
|
|
|
|
|
|
|
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
|
|
|
|
|
let RequiresState(from_state) = parts.extract_with_state(state).await?;
|
|
|
|
|
let method = parts.extract().await?;
|
|
|
|
|
|
|
|
|
|
Ok(Self { method, from_state })
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|