httpz/
generic_endpoint.rs

1use http::Method;
2use std::future::Future;
3
4use crate::{Endpoint, HttpEndpoint, HttpResponse, Request};
5
6/// represents an async function used to handle the HTTP request. I would highly recommend using [GenericHttpEndpoint] instead of implementing this trait yourself.
7pub trait EndpointFn<'this>
8where
9    Self: Send + Sync + 'this,
10{
11    /// TODO
12    type Response: HttpResponse;
13
14    /// the type of the future returned by the handler function.
15    type Fut: Future<Output = Self::Response> + Send + 'this;
16
17    /// is called to handle the HTTP request.
18    fn call(&self, req: Request) -> Self::Fut;
19}
20
21impl<'this, TFut, TFunc, TRes> EndpointFn<'this> for TFunc
22where
23    TFunc: Fn(Request) -> TFut + Send + Sync + 'this,
24    TFut: Future<Output = TRes> + Send + 'this,
25    TRes: HttpResponse,
26{
27    type Response = TRes;
28    type Fut = TFut;
29
30    fn call(&self, req: Request) -> Self::Fut {
31        self(req)
32    }
33}
34
35/// is an easy way of constructing an endpoint from an async function you provide.
36pub struct GenericEndpoint<TMethods, TEndpointFn, TUrl>
37where
38    TMethods: AsRef<[Method]> + Send + Sync + 'static,
39    TEndpointFn: for<'this> EndpointFn<'this>,
40    TUrl: AsRef<str> + Send + Sync + 'static,
41{
42    methods: Option<TMethods>,
43    func: TEndpointFn,
44    url: Option<TUrl>,
45}
46
47impl<TMethods, TEndpointFn, TUrl> Clone for GenericEndpoint<TMethods, TEndpointFn, TUrl>
48where
49    TMethods: AsRef<[Method]> + Clone + Send + Sync + 'static,
50    TEndpointFn: for<'this> EndpointFn<'this> + Clone,
51    TUrl: AsRef<str> + Clone + Send + Sync + 'static,
52{
53    fn clone(&self) -> Self {
54        Self {
55            methods: self.methods.clone(),
56            func: self.func.clone(),
57            url: self.url.clone(),
58        }
59    }
60}
61
62impl<TMethods, TEndpointFn, TUrl> GenericEndpoint<TMethods, TEndpointFn, TUrl>
63where
64    TMethods: AsRef<[Method]> + Send + Sync + 'static,
65    TEndpointFn: for<'this> EndpointFn<'this>,
66    TUrl: AsRef<str> + Send + Sync + 'static,
67{
68    /// create a new [Endpoint] from a context, a list of methods and a function to handle the request.
69    pub fn new(url: TUrl, methods: TMethods, func: TEndpointFn) -> Endpoint<Self> {
70        Endpoint::from_endpoint(Self::new_raw(url, methods, func))
71    }
72
73    /// create a new generic endpoint from a context, a list of methods and a function to handle the request.
74    pub fn new_raw(url: TUrl, methods: TMethods, func: TEndpointFn) -> Self {
75        Self {
76            methods: Some(methods),
77            func,
78            url: Some(url),
79        }
80    }
81}
82
83impl<TMethods, TEndpointFn, TUrl> HttpEndpoint for GenericEndpoint<TMethods, TEndpointFn, TUrl>
84where
85    TMethods: AsRef<[Method]> + Send + Sync + 'static,
86    TEndpointFn: for<'this> EndpointFn<'this>,
87    TUrl: AsRef<str> + Send + Sync + 'static,
88{
89    type Routes = TMethods;
90    type Url = TUrl;
91    type EndpointFn = TEndpointFn;
92
93    fn register(&mut self) -> (Self::Url, Self::Routes) {
94        (
95            match self.url.take() {
96                Some(url) => url,
97                None => unreachable!(),
98            },
99            match self.methods.take() {
100                Some(methods) => methods,
101                None => unreachable!(),
102            },
103        )
104    }
105
106    fn handler(&self, req: Request) -> <Self::EndpointFn as EndpointFn<'_>>::Fut {
107        self.func.call(req)
108    }
109}