pub mod header;
pub mod method;
mod predicate;
pub use header::Header;
pub use predicate::*;
use std::fmt::Debug;
use crate::request::Request;
use crate::{BoxFuture, Error, Middleware, Next};
pub type Content<T, U> = (
Header<header::Contains<Or<(header::Media<header::CaseSensitive>, U)>>>,
When<Not<method::IsSafe>, (Header<T>, Header<Wildcard>)>,
);
pub struct AndThen<T, U> {
middleware: U,
guard: Guard<T>,
}
pub struct Filter<T, U> {
middleware: U,
guard: Guard<T>,
}
pub struct Guard<T> {
predicate: T,
}
pub fn guard<T>(predicate: T) -> Guard<T> {
Guard { predicate }
}
pub fn header<K, V>(key: K, value: V) -> Header<V>
where
K: TryInto<http::HeaderName>,
K::Error: Debug,
{
Header {
value,
key: key.try_into().expect("invalid header name."),
}
}
pub fn content<T, U>(accepts: T, provides: U) -> Guard<Content<T, U>> {
guard((
header::accept(provides),
when(
method::is_mutation(),
(header::content_type(accepts), header::content_length()),
),
))
}
impl<T, U, App> Middleware<App> for AndThen<T, U>
where
T: Predicate<Request<App>> + Send + Sync,
for<'a> T::Error<'a>: Into<Error>,
U: Middleware<App>,
{
fn call(&self, request: Request<App>, next: Next<App>) -> BoxFuture {
match self.guard.predicate.cmp(&request) {
Ok(_) => self.middleware.call(request, next),
Err(error) => {
let error = error.into();
Box::pin(async { Err(error) })
}
}
}
}
impl<T, U, App> Middleware<App> for Filter<T, U>
where
T: Predicate<Request<App>> + Send + Sync,
U: Middleware<App>,
{
fn call(&self, request: Request<App>, next: Next<App>) -> BoxFuture {
if self.guard.predicate.cmp(&request).is_ok() {
self.middleware.call(request, next)
} else {
next.call(request)
}
}
}
impl<T> Guard<T> {
pub fn and_then<U>(self, middleware: U) -> AndThen<T, U> {
AndThen {
middleware,
guard: self,
}
}
pub fn filter<U>(self, middleware: U) -> Filter<T, U> {
Filter {
middleware,
guard: self,
}
}
}
impl<T, App> Middleware<App> for Guard<T>
where
T: Predicate<Request<App>> + Send + Sync,
for<'a> T::Error<'a>: Into<Error>,
{
fn call(&self, request: Request<App>, next: Next<App>) -> BoxFuture {
match self.predicate.cmp(&request) {
Ok(_) => next.call(request),
Err(error) => {
let error = error.into();
Box::pin(async { Err(error) })
}
}
}
}