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 crate::http::Method;
use crate::{async_trait, Context, Endpoint, Result};
use doc_comment::doc_comment;
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:

```rust
use roa::{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:

```rust
use roa::{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)
            }
        }
    };
}

/// An endpoint wrapper to dispatch requests by http method.
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);
}

/// Empty dispatcher.
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()),
        }
    }
}