1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use std::future::Future;
use futures_util::future::BoxFuture;
use crate::middleware::next::Next;
use crate::request::ctx::Ctx;
use crate::request::ctx::extract::ExtractFromRequestCtx;
use crate::response::Response;

pub trait Middleware: Send + Sync {
    fn call(&self, ctx: Ctx, next: &'static dyn Next) -> BoxFuture<'static, crate::path::Result<Response>>;
}

impl<F, Fut> Middleware for F where
    F: Fn(Ctx, &'static dyn Next) -> Fut + Sync + Send,
    Fut: Future<Output = crate::path::Result<Response>> + Send + 'static {
    fn call(&self, ctx: Ctx, next: &'static dyn Next) -> BoxFuture<'static, crate::path::Result<Response>> {
        Box::pin(self(ctx, next))
    }
}

pub(crate) fn empty_middleware() -> &'static dyn Middleware {
    Box::leak(Box::new(|ctx: Ctx, next: &'static dyn Next| async move {
        next.call(ctx).await
    }))
}

pub(crate) fn combine_middleware(middlewares: Vec<&'static dyn Middleware>) -> &'static dyn Middleware {
    match middlewares.len() {
        0 => empty_middleware(),
        1 => *middlewares.first().unwrap(),
        2 => join_middleware(*middlewares.get(1).unwrap(), *middlewares.get(0).unwrap()),
        _ => {
            let inner_most = *middlewares.first().unwrap();
            let mut result = join_middleware(*middlewares.get(1).unwrap(), inner_most);
            for (index, middleware) in middlewares.iter().enumerate() {
                if index >= 2 {
                    result = join_middleware(*middleware, result);
                }
            }
            result
        }
    }
}

fn join_middleware(outer: &'static dyn Middleware, inner: &'static dyn Middleware) -> &'static dyn Middleware {
    return Box::leak(Box::new(move |ctx: Ctx, next: &'static dyn Next| async move {
        outer.call(ctx, Box::leak(Box::new(move |ctx: Ctx| async move {
            inner.call(ctx, next).await
        }))).await
    }))
}

pub trait MiddlewareArgument<A>: Send + Sync + 'static {
    fn call(&self, ctx: Ctx, next: &'static dyn Next) -> BoxFuture<'static, crate::path::Result<Response>>;
}

impl<A0, F, Fut> MiddlewareArgument<(A0,)> for F where
    A0: ExtractFromRequestCtx + Send + Sync,
    F: Fn(A0, &'static dyn Next) -> Fut + Sync + Send + Clone + 'static,
    Fut: Future<Output = crate::path::Result<Response>> + Send + 'static {
    fn call(&self, ctx: Ctx, next: &'static dyn Next) -> BoxFuture<'static, crate::path::Result<Response>> {
        let value: A0 = ExtractFromRequestCtx::extract(&ctx);
        Box::pin(self(value, next))
    }
}

impl<A0, A1, F, Fut> MiddlewareArgument<(A0, A1)> for F where
    A0: ExtractFromRequestCtx + Send + Sync,
    A1: ExtractFromRequestCtx + Send + Sync,
    F: Fn(A0, A1, &'static dyn Next) -> Fut + Sync + Send + Clone + 'static,
    Fut: Future<Output = crate::path::Result<Response>> + Send + 'static {
    fn call(&self, ctx: Ctx, next: &'static dyn Next) -> BoxFuture<'static, crate::path::Result<Response>> {
        let a0: A0 = ExtractFromRequestCtx::extract(&ctx);
        let a1: A1 = ExtractFromRequestCtx::extract(&ctx);
        Box::pin(self(a0, a1, next))
    }
}

impl<A0, A1, A2, F, Fut> MiddlewareArgument<(A0, A1, A2)> for F where
    A0: ExtractFromRequestCtx + Send + Sync,
    A1: ExtractFromRequestCtx + Send + Sync,
    A2: ExtractFromRequestCtx + Send + Sync,
    F: Fn(A0, A1, A2, &'static dyn Next) -> Fut + Sync + Send + Clone + 'static,
    Fut: Future<Output = crate::path::Result<Response>> + Send + 'static {
    fn call(&self, ctx: Ctx, next: &'static dyn Next) -> BoxFuture<'static, crate::path::Result<Response>> {
        let a0: A0 = ExtractFromRequestCtx::extract(&ctx);
        let a1: A1 = ExtractFromRequestCtx::extract(&ctx);
        let a2: A2 = ExtractFromRequestCtx::extract(&ctx);
        Box::pin(self(a0, a1, a2, next))
    }
}

impl<A0, A1, A2, A3, F, Fut> MiddlewareArgument<(A0, A1, A2, A3)> for F where
    A0: ExtractFromRequestCtx + Send + Sync,
    A1: ExtractFromRequestCtx + Send + Sync,
    A2: ExtractFromRequestCtx + Send + Sync,
    A3: ExtractFromRequestCtx + Send + Sync,
    F: Fn(A0, A1, A2, A3, &'static dyn Next) -> Fut + Sync + Send + Clone + 'static,
    Fut: Future<Output = crate::path::Result<Response>> + Send + 'static {
    fn call(&self, ctx: Ctx, next: &'static dyn Next) -> BoxFuture<'static, crate::path::Result<Response>> {
        let a0: A0 = ExtractFromRequestCtx::extract(&ctx);
        let a1: A1 = ExtractFromRequestCtx::extract(&ctx);
        let a2: A2 = ExtractFromRequestCtx::extract(&ctx);
        let a3: A3 = ExtractFromRequestCtx::extract(&ctx);
        Box::pin(self(a0, a1, a2, a3, next))
    }
}

pub fn middleware_wrap_fn<T, F>(call: F) -> &'static dyn Middleware where
    T: Send + Sync + 'static,
    F: MiddlewareArgument<T> + 'static
{
    let wrap_call = Box::leak(Box::new(call));
    Box::leak(Box::new(|ctx: Ctx, next: &'static dyn Next| async {
        wrap_call.call(ctx, next).await
    }))
}