rama_http/layer/validate_request/
validate_fn.rs

1use super::ValidateRequest;
2use crate::{Request, Response};
3use rama_core::Context;
4use std::marker::PhantomData;
5
6/// Trait for validating requests.
7pub trait ValidateRequestFn<S, B, A>: Send + Sync + 'static {
8    /// The body type used for responses to unvalidated requests.
9    type ResponseBody;
10
11    /// Validate the request.
12    ///
13    /// If `Ok(())` is returned then the request is allowed through, otherwise not.
14    fn call(
15        &self,
16        ctx: Context<S>,
17        request: Request<B>,
18    ) -> impl Future<Output = Result<(Context<S>, Request<B>), Response<Self::ResponseBody>>> + Send + '_;
19}
20
21impl<S, B, F, Fut, ResBody> ValidateRequestFn<S, B, ()> for F
22where
23    S: Clone + Send + Sync + 'static,
24    B: Send + 'static,
25    ResBody: Send + 'static,
26    F: Fn() -> Fut + Send + Sync + 'static,
27    Fut: Future<Output = Result<(), Response<ResBody>>> + Send + 'static,
28{
29    type ResponseBody = ResBody;
30
31    async fn call(
32        &self,
33        ctx: Context<S>,
34        req: Request<B>,
35    ) -> Result<(Context<S>, Request<B>), Response<Self::ResponseBody>> {
36        match self().await {
37            Ok(_) => Ok((ctx, req)),
38            Err(res) => Err(res),
39        }
40    }
41}
42
43impl<S, B, F, Fut, ResBody> ValidateRequestFn<S, B, ((), Request<B>)> for F
44where
45    S: Clone + Send + Sync + 'static,
46    B: Send + 'static,
47    ResBody: Send + 'static,
48    F: Fn(Request<B>) -> Fut + Send + Sync + 'static,
49    Fut: Future<Output = Result<Request<B>, Response<ResBody>>> + Send + 'static,
50{
51    type ResponseBody = ResBody;
52
53    async fn call(
54        &self,
55        ctx: Context<S>,
56        req: Request<B>,
57    ) -> Result<(Context<S>, Request<B>), Response<Self::ResponseBody>> {
58        match self(req).await {
59            Ok(req) => Ok((ctx, req)),
60            Err(res) => Err(res),
61        }
62    }
63}
64
65impl<S, B, F, Fut, ResBody> ValidateRequestFn<S, B, (Context<S>,)> for F
66where
67    S: Clone + Send + Sync + 'static,
68    B: Send + 'static,
69    ResBody: Send + 'static,
70    F: Fn(Context<S>) -> Fut + Send + Sync + 'static,
71    Fut: Future<Output = Result<Context<S>, Response<ResBody>>> + Send + 'static,
72{
73    type ResponseBody = ResBody;
74
75    async fn call(
76        &self,
77        ctx: Context<S>,
78        req: Request<B>,
79    ) -> Result<(Context<S>, Request<B>), Response<Self::ResponseBody>> {
80        match self(ctx).await {
81            Ok(ctx) => Ok((ctx, req)),
82            Err(res) => Err(res),
83        }
84    }
85}
86
87impl<S, B, F, Fut, ResBody> ValidateRequestFn<S, B, (Context<S>, Request<B>)> for F
88where
89    F: Fn(Context<S>, Request<B>) -> Fut + Send + Sync + 'static,
90    Fut: Future<Output = Result<(Context<S>, Request<B>), Response<ResBody>>> + Send + 'static,
91{
92    type ResponseBody = ResBody;
93
94    fn call(
95        &self,
96        ctx: Context<S>,
97        request: Request<B>,
98    ) -> impl Future<Output = Result<(Context<S>, Request<B>), Response<Self::ResponseBody>>> + Send + '_
99    {
100        self(ctx, request)
101    }
102}
103
104/// The public wrapper type for [`ValidateRequestFn`].
105pub struct BoxValidateRequestFn<F, A> {
106    f: F,
107    _marker: PhantomData<A>,
108}
109
110impl<F, A> BoxValidateRequestFn<F, A> {
111    /// Create a new [`BoxValidateRequestFn`].
112    pub const fn new(f: F) -> Self {
113        Self {
114            f,
115            _marker: PhantomData,
116        }
117    }
118}
119
120impl<F, A> Clone for BoxValidateRequestFn<F, A>
121where
122    F: Clone,
123{
124    fn clone(&self) -> Self {
125        Self {
126            f: self.f.clone(),
127            _marker: PhantomData,
128        }
129    }
130}
131
132impl<F, A> std::fmt::Debug for BoxValidateRequestFn<F, A>
133where
134    F: std::fmt::Debug,
135{
136    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137        f.debug_struct("BoxValidateRequestFn")
138            .field("f", &self.f)
139            .finish()
140    }
141}
142
143impl<S, B, A, F> ValidateRequest<S, B> for BoxValidateRequestFn<F, A>
144where
145    A: Send + Sync + 'static,
146    F: ValidateRequestFn<S, B, A>,
147{
148    type ResponseBody = F::ResponseBody;
149
150    fn validate(
151        &self,
152        ctx: Context<S>,
153        request: Request<B>,
154    ) -> impl Future<Output = Result<(Context<S>, Request<B>), Response<Self::ResponseBody>>> + Send + '_
155    {
156        self.f.call(ctx, request)
157    }
158}