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
use super::method_not_allowed;
use doc_comment::doc_comment;
use roa_core::http::Method;
use roa_core::{async_trait, Context, Endpoint, Result};
use std::collections::HashMap;
macro_rules! impl_http_methods {
($end:ident, $method:expr) => {
doc_comment! {
concat!("Method to add or override endpoint on ", stringify!($method), ".
You can use it as follow:
```
use roa_core::{App, Context, Result};
use roa_router::get;
async fn foo(ctx: &mut Context<()>) -> Result {
Ok(())
}
async fn bar(ctx: &mut Context<()>) -> Result {
Ok(())
}
let app = App::new(()).end(get(foo).", stringify!($end), "(bar));
```"),
pub fn $end(mut self, endpoint: impl for<'a> Endpoint<'a, S>) -> Self {
self.0.insert($method, Box::new(endpoint));
self
}
}
};
}
macro_rules! impl_http_functions {
($end:ident, $method:expr) => {
doc_comment! {
concat!("Function to construct dispatcher with ", stringify!($method), " and an endpoint.
You can use it as follow:
```
use roa_core::{App, Context, Result};
use roa_router::", stringify!($end), ";
async fn end(ctx: &mut Context<()>) -> Result {
Ok(())
}
let app = App::new(()).end(", stringify!($end), "(end));
```"),
pub fn $end<S>(endpoint: impl for<'a> Endpoint<'a, S>) -> Dispatcher<S> {
Dispatcher::<S>::default().$end(endpoint)
}
}
};
}
pub struct Dispatcher<S>(HashMap<Method, Box<dyn for<'a> Endpoint<'a, S>>>);
impl_http_functions!(get, Method::GET);
impl_http_functions!(post, Method::POST);
impl_http_functions!(put, Method::PUT);
impl_http_functions!(patch, Method::PATCH);
impl_http_functions!(options, Method::OPTIONS);
impl_http_functions!(delete, Method::DELETE);
impl_http_functions!(head, Method::HEAD);
impl_http_functions!(trace, Method::TRACE);
impl_http_functions!(connect, Method::CONNECT);
impl<S> Dispatcher<S> {
impl_http_methods!(get, Method::GET);
impl_http_methods!(post, Method::POST);
impl_http_methods!(put, Method::PUT);
impl_http_methods!(patch, Method::PATCH);
impl_http_methods!(options, Method::OPTIONS);
impl_http_methods!(delete, Method::DELETE);
impl_http_methods!(head, Method::HEAD);
impl_http_methods!(trace, Method::TRACE);
impl_http_methods!(connect, Method::CONNECT);
}
impl<S> Default for Dispatcher<S> {
fn default() -> Self {
Self(HashMap::new())
}
}
#[async_trait(?Send)]
impl<'a, S> Endpoint<'a, S> for Dispatcher<S>
where
S: 'static,
{
#[inline]
async fn call(&'a self, ctx: &'a mut Context<S>) -> Result<()> {
match self.0.get(ctx.method()) {
Some(endpoint) => endpoint.call(ctx).await,
None => method_not_allowed(ctx.method()),
}
}
}