use std::{
convert::Infallible,
future::{ready, Future, Ready},
};
use futures_util::{
future::{try_join, MapErr, MapOk, TryJoin},
TryFutureExt,
};
use http::{request::Parts, Request, StatusCode};
use crate::{
body::{empty, BoxBody},
rejection::any_rejections,
response::IntoResponse,
};
pub mod connect_info;
pub mod extension;
#[cfg(feature = "aws-lambda")]
#[cfg_attr(docsrs, doc(cfg(feature = "aws-lambda")))]
pub mod lambda;
#[cfg(feature = "request-id")]
#[cfg_attr(docsrs, doc(cfg(feature = "request-id")))]
pub mod request_id;
fn internal_server_error() -> http::Response<BoxBody> {
let mut response = http::Response::new(empty());
*response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
response
}
pub trait FromParts<Protocol>: Sized {
type Rejection: IntoResponse<Protocol>;
fn from_parts(parts: &mut Parts) -> Result<Self, Self::Rejection>;
}
impl<P> FromParts<P> for () {
type Rejection = Infallible;
fn from_parts(_parts: &mut Parts) -> Result<Self, Self::Rejection> {
Ok(())
}
}
impl<P, T> FromParts<P> for (T,)
where
T: FromParts<P>,
{
type Rejection = T::Rejection;
fn from_parts(parts: &mut Parts) -> Result<Self, Self::Rejection> {
Ok((T::from_parts(parts)?,))
}
}
macro_rules! impl_from_parts {
($error_name:ident, $($var:ident),+) => (
impl<P, $($var,)*> FromParts<P> for ($($var),*)
where
$($var: FromParts<P>,)*
{
type Rejection = any_rejections::$error_name<$($var::Rejection),*>;
fn from_parts(parts: &mut Parts) -> Result<Self, Self::Rejection> {
let tuple = (
$($var::from_parts(parts).map_err(any_rejections::$error_name::$var)?,)*
);
Ok(tuple)
}
}
)
}
impl_from_parts!(Two, A, B);
impl_from_parts!(Three, A, B, C);
impl_from_parts!(Four, A, B, C, D);
impl_from_parts!(Five, A, B, C, D, E);
impl_from_parts!(Six, A, B, C, D, E, F);
impl_from_parts!(Seven, A, B, C, D, E, F, G);
impl_from_parts!(Eight, A, B, C, D, E, F, G, H);
pub trait FromRequest<Protocol, B>: Sized {
type Rejection: IntoResponse<Protocol>;
type Future: Future<Output = Result<Self, Self::Rejection>>;
fn from_request(request: Request<B>) -> Self::Future;
}
impl<P, B, T1> FromRequest<P, B> for (T1,)
where
T1: FromRequest<P, B>,
{
type Rejection = T1::Rejection;
type Future = MapOk<T1::Future, fn(T1) -> (T1,)>;
fn from_request(request: Request<B>) -> Self::Future {
T1::from_request(request).map_ok(|t1| (t1,))
}
}
impl<P, B, T1, T2> FromRequest<P, B> for (T1, T2)
where
T1: FromRequest<P, B>,
T2: FromParts<P>,
T1::Rejection: std::fmt::Display,
T2::Rejection: std::fmt::Display,
{
type Rejection = any_rejections::Two<T1::Rejection, T2::Rejection>;
type Future = TryJoin<MapErr<T1::Future, fn(T1::Rejection) -> Self::Rejection>, Ready<Result<T2, Self::Rejection>>>;
fn from_request(request: Request<B>) -> Self::Future {
let (mut parts, body) = request.into_parts();
let t2_result: Result<T2, any_rejections::Two<T1::Rejection, T2::Rejection>> = T2::from_parts(&mut parts)
.map_err(|e| {
tracing::error!(
error = %e,
"additional parameter for the handler function could not be constructed");
any_rejections::Two::B(e)
});
try_join(
T1::from_request(Request::from_parts(parts, body)).map_err(|e| {
tracing::debug!(error = %e, "failed to deserialize request into operation's input");
any_rejections::Two::A(e)
}),
ready(t2_result),
)
}
}
impl<P, T> FromParts<P> for Option<T>
where
T: FromParts<P>,
{
type Rejection = Infallible;
fn from_parts(parts: &mut Parts) -> Result<Self, Self::Rejection> {
Ok(T::from_parts(parts).ok())
}
}
impl<P, T> FromParts<P> for Result<T, T::Rejection>
where
T: FromParts<P>,
{
type Rejection = Infallible;
fn from_parts(parts: &mut Parts) -> Result<Self, Self::Rejection> {
Ok(T::from_parts(parts))
}
}