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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
use futures::future::{Future, FutureObj};

use crate::{
    configuration::Store, extract::Extract, head::Head, IntoResponse, Request, Response, RouteMatch,
};

/// The raw representation of an endpoint.
///
/// This trait is automatically implemented by a host of `Fn` types, and should not be
/// implemented directly by Tide users.
///
/// # Examples
///
/// Endpoints are implemented as asynchronous functions that make use of language features
/// currently only available in Rust Nightly. For this reason, we have to explicitly enable
/// those features with `#![feature(async_await, futures_api)]`. To keep examples concise,
/// the attribute will be omitted in most of the documentation.
///
/// A simple endpoint that is invoked on a `GET` request and returns a `String`:
///
/// ```rust, no_run
/// # #![feature(async_await, futures_api)]
/// async fn hello() -> String {
///     String::from("hello")
/// }
///
/// fn main() {
///     let mut app = tide::App::new(());
///     app.at("/hello").get(hello);
///     app.serve()
/// }
/// ```
///
/// Endpoint accessing `App` state (`Data`) and body of `POST` request as `String`:
///
/// ```rust, no_run
/// # #![feature(async_await, futures_api)]
/// use std::sync::Arc;
/// use std::sync::Mutex;
/// use tide::AppData;
/// use tide::body;
///
/// #[derive(Clone, Default)]
/// struct Database {
///     contents: Arc<Mutex<Vec<String>>>,
/// }
///
/// async fn insert(
///     mut db: AppData<Database>,
///     msg: body::Str,
/// ) -> String {
///     // insert into db
///     # String::from("")
/// }
///
/// fn main() {
///     let mut app = tide::App::new(Database::default());
///     app.at("/messages/insert").post(insert);
///     app.serve()
/// }
/// ```
///
/// See [`body`](body/index.html) module for examples of how to work with request and response bodies.
///
pub trait Endpoint<Data, Kind>: Send + Sync + 'static {
    /// The async result of `call`.
    type Fut: Future<Output = Response> + Send + 'static;

    /// Invoke the endpoint on the given request and app data handle.
    fn call(
        &self,
        data: Data,
        req: Request,
        params: Option<RouteMatch<'_>>,
        store: &Store,
    ) -> Self::Fut;
}

type BoxedEndpointFn<Data> =
    dyn Fn(Data, Request, Option<RouteMatch>, &Store) -> FutureObj<'static, Response> + Send + Sync;

pub(crate) struct BoxedEndpoint<Data> {
    endpoint: Box<BoxedEndpointFn<Data>>,
}

impl<Data> BoxedEndpoint<Data> {
    pub fn new<T, Kind>(ep: T) -> BoxedEndpoint<Data>
    where
        T: Endpoint<Data, Kind>,
    {
        BoxedEndpoint {
            endpoint: Box::new(move |data, request, params, store| {
                FutureObj::new(Box::new(ep.call(data, request, params, store)))
            }),
        }
    }

    pub fn call(
        &self,
        data: Data,
        req: Request,
        params: Option<RouteMatch<'_>>,
        store: &Store,
    ) -> FutureObj<'static, Response> {
        (self.endpoint)(data, req, params, store)
    }
}

/// A marker type used for the (phantom) `Kind` parameter in endpoints.
#[doc(hidden)]
pub struct Ty<T>(T);

macro_rules! call_f {
    ($head_ty:ty; ($f:ident, $head:ident); $($X:ident),*) => {
        $f($head.clone(), $($X),*)
    };
    (($f:ident, $head:ident); $($X:ident),*) => {
        $f($($X),*)
    };
}

macro_rules! end_point_impl_raw {
    ($([$head:ty])* $($X:ident),*) => {
        impl<T, Data, Fut, $($X),*> Endpoint<Data, (Ty<Fut>, $($head,)* $(Ty<$X>),*)> for T
        where
            T: Send + Sync + Clone + 'static + Fn($($head,)* $($X),*) -> Fut,
            Data: Clone + Send + Sync + 'static,
            Fut: Future + Send + 'static,
            Fut::Output: IntoResponse,
            $(
                $X: Extract<Data>
            ),*
        {
            type Fut = FutureObj<'static, Response>;

            #[allow(unused_mut, non_snake_case)]
            fn call(&self, mut data: Data, mut req: Request, params: Option<RouteMatch<'_>>, store: &Store) -> Self::Fut {
                let f = self.clone();
                $(let $X = $X::extract(&mut data, &mut req, &params, store);)*
                FutureObj::new(Box::new(async move {
                    let (parts, _) = req.into_parts();
                    let head = Head::from(parts);
                    $(let $X = match await!($X) {
                        Ok(x) => x,
                        Err(resp) => return resp,
                    };)*
                    let res = await!(call_f!($($head;)* (f, head); $($X),*));

                    res.into_response()
                }))
            }
        }
    };
}

macro_rules! end_point_impl {
    ($($X:ident),*) => {
        end_point_impl_raw!([Head] $($X),*);
        end_point_impl_raw!($($X),*);
    }
}

end_point_impl!();
end_point_impl!(T0);
end_point_impl!(T0, T1);
end_point_impl!(T0, T1, T2);
end_point_impl!(T0, T1, T2, T3);
end_point_impl!(T0, T1, T2, T3, T4);
end_point_impl!(T0, T1, T2, T3, T4, T5);
end_point_impl!(T0, T1, T2, T3, T4, T5, T6);
end_point_impl!(T0, T1, T2, T3, T4, T5, T6, T7);
end_point_impl!(T0, T1, T2, T3, T4, T5, T6, T7, T8);
end_point_impl!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);