finchers/endpoint/
mod.rs

1//! Components for constructing `Endpoint`.
2
3mod boxed;
4pub mod context;
5pub mod error;
6pub mod syntax;
7pub mod wrapper;
8
9mod and;
10mod apply;
11mod by_ref;
12mod cloned;
13mod lazy;
14mod or;
15mod or_strict;
16mod unit;
17
18// re-exports
19pub use self::boxed::{EndpointObj, LocalEndpointObj};
20pub use self::context::{with_get_cx, ApplyContext, TaskContext};
21pub(crate) use self::context::{with_set_cx, Cursor};
22pub use self::error::{ApplyError, ApplyResult};
23pub use self::wrapper::{EndpointWrapExt, Wrapper};
24
25pub use self::and::And;
26pub use self::or::Or;
27pub use self::or_strict::OrStrict;
28
29pub use self::apply::{apply, apply_raw, Apply, ApplyRaw};
30pub use self::by_ref::{by_ref, ByRef};
31pub use self::cloned::{cloned, Cloned};
32pub use self::lazy::{lazy, Lazy};
33pub use self::unit::{unit, Unit};
34
35pub use self::output_endpoint::OutputEndpoint;
36pub use self::send_endpoint::SendEndpoint;
37
38// ====
39
40use std::rc::Rc;
41use std::sync::Arc;
42
43use futures::Future;
44
45use common::{Combine, Tuple};
46use error::Error;
47
48/// Trait representing an endpoint.
49pub trait Endpoint<'a>: 'a {
50    /// The inner type associated with this endpoint.
51    type Output: Tuple;
52
53    /// The type of value which will be returned from `apply`.
54    type Future: Future<Item = Self::Output, Error = Error> + 'a;
55
56    /// Perform checking the incoming HTTP request and returns
57    /// an instance of the associated Future if matched.
58    fn apply(&'a self, ecx: &mut ApplyContext<'_>) -> ApplyResult<Self::Future>;
59
60    /// Add an annotation that the associated type `Output` is fixed to `T`.
61    #[inline(always)]
62    fn with_output<T: Tuple>(self) -> Self
63    where
64        Self: Endpoint<'a, Output = T> + Sized,
65    {
66        self
67    }
68
69    /// Converts `self` using the provided `Wrapper`.
70    fn wrap<W>(self, wrapper: W) -> W::Endpoint
71    where
72        Self: Sized,
73        W: Wrapper<'a, Self>,
74    {
75        (wrapper.wrap(self)).with_output::<W::Output>()
76    }
77}
78
79impl<'a, E: Endpoint<'a>> Endpoint<'a> for Box<E> {
80    type Output = E::Output;
81    type Future = E::Future;
82
83    fn apply(&'a self, ecx: &mut ApplyContext<'_>) -> ApplyResult<Self::Future> {
84        (**self).apply(ecx)
85    }
86}
87
88impl<'a, E: Endpoint<'a>> Endpoint<'a> for Rc<E> {
89    type Output = E::Output;
90    type Future = E::Future;
91
92    fn apply(&'a self, ecx: &mut ApplyContext<'_>) -> ApplyResult<Self::Future> {
93        (**self).apply(ecx)
94    }
95}
96
97impl<'a, E: Endpoint<'a>> Endpoint<'a> for Arc<E> {
98    type Output = E::Output;
99    type Future = E::Future;
100
101    fn apply(&'a self, ecx: &mut ApplyContext<'_>) -> ApplyResult<Self::Future> {
102        (**self).apply(ecx)
103    }
104}
105
106/// Trait representing the transformation into an `Endpoint`.
107pub trait IntoEndpoint<'a> {
108    /// The inner type of associated `Endpoint`.
109    type Output: Tuple;
110
111    /// The type of transformed `Endpoint`.
112    type Endpoint: Endpoint<'a, Output = Self::Output>;
113
114    /// Consume itself and transform into an `Endpoint`.
115    fn into_endpoint(self) -> Self::Endpoint;
116}
117
118impl<'a, E: Endpoint<'a>> IntoEndpoint<'a> for E {
119    type Output = E::Output;
120    type Endpoint = E;
121
122    #[inline]
123    fn into_endpoint(self) -> Self::Endpoint {
124        self
125    }
126}
127
128/// A set of extension methods for composing multiple endpoints.
129pub trait IntoEndpointExt<'a>: IntoEndpoint<'a> + Sized {
130    /// Create an endpoint which evaluates `self` and `e` and returns a pair of their tasks.
131    ///
132    /// The returned future from this endpoint contains both futures from
133    /// `self` and `e` and resolved as a pair of values returned from theirs.
134    fn and<E>(self, other: E) -> And<Self::Endpoint, E::Endpoint>
135    where
136        E: IntoEndpoint<'a>,
137        Self::Output: Combine<E::Output>,
138    {
139        (And {
140            e1: self.into_endpoint(),
141            e2: other.into_endpoint(),
142        }).with_output::<<Self::Output as Combine<E::Output>>::Out>()
143    }
144
145    /// Create an endpoint which evaluates `self` and `e` sequentially.
146    ///
147    /// The returned future from this endpoint contains the one returned
148    /// from either `self` or `e` matched "better" to the input.
149    fn or<E>(self, other: E) -> Or<Self::Endpoint, E::Endpoint>
150    where
151        E: IntoEndpoint<'a>,
152    {
153        (Or {
154            e1: self.into_endpoint(),
155            e2: other.into_endpoint(),
156        }).with_output::<(self::or::Wrapped<Self::Output, E::Output>,)>()
157    }
158
159    /// Create an endpoint which evaluates `self` and `e` sequentially.
160    ///
161    /// The differences of behaviour to `Or` are as follows:
162    ///
163    /// * The associated type `E::Output` must be equal to `Self::Output`.
164    ///   It means that the generated endpoint has the same output type
165    ///   as the original endpoints and the return value will be used later.
166    /// * If `self` is matched to the request, `other.apply(cx)`
167    ///   is not called and the future returned from `self.apply(cx)` is
168    ///   immediately returned.
169    fn or_strict<E>(self, other: E) -> OrStrict<Self::Endpoint, E::Endpoint>
170    where
171        E: IntoEndpoint<'a, Output = Self::Output>,
172    {
173        (OrStrict {
174            e1: self.into_endpoint(),
175            e2: other.into_endpoint(),
176        }).with_output::<Self::Output>()
177    }
178}
179
180impl<'a, E: IntoEndpoint<'a>> IntoEndpointExt<'a> for E {}
181
182mod send_endpoint {
183    use futures::Future;
184
185    use super::{ApplyContext, ApplyResult, Endpoint};
186    use common::Tuple;
187    use error::Error;
188
189    /// A trait representing an endpoint with a constraint that the returned "Future"
190    /// to be transferred across thread boundaries.
191    pub trait SendEndpoint<'a>: 'a + Sealed {
192        #[doc(hidden)]
193        type Output: Tuple;
194        #[doc(hidden)]
195        type Future: Future<Item = Self::Output, Error = Error> + Send + 'a;
196        #[doc(hidden)]
197        fn apply_send(&'a self, cx: &mut ApplyContext<'_>) -> ApplyResult<Self::Future>;
198    }
199
200    pub trait Sealed {}
201
202    impl<'a, E> Sealed for E
203    where
204        E: Endpoint<'a>,
205        E::Future: Send,
206    {
207    }
208
209    impl<'a, E> SendEndpoint<'a> for E
210    where
211        E: Endpoint<'a>,
212        E::Future: Send,
213    {
214        type Output = E::Output;
215        type Future = E::Future;
216
217        #[inline(always)]
218        fn apply_send(&'a self, cx: &mut ApplyContext<'_>) -> ApplyResult<Self::Future> {
219            self.apply(cx)
220        }
221    }
222}
223
224mod output_endpoint {
225    use futures::Future;
226
227    use common::Tuple;
228    use endpoint::{ApplyContext, ApplyResult, Endpoint};
229    use error::Error;
230    use output::Output;
231
232    /// A trait representing an endpoint with a constraint that the returned value
233    /// can be convert into an HTTP response.
234    pub trait OutputEndpoint<'a>: 'a + Sealed {
235        #[doc(hidden)]
236        type Output: Tuple + Output;
237        #[doc(hidden)]
238        type Future: Future<Item = Self::Output, Error = Error> + 'a;
239        #[doc(hidden)]
240        fn apply_output(&'a self, cx: &mut ApplyContext<'_>) -> ApplyResult<Self::Future>;
241    }
242
243    impl<'a, E> OutputEndpoint<'a> for E
244    where
245        E: Endpoint<'a>,
246        E::Output: Output,
247    {
248        type Output = E::Output;
249        type Future = E::Future;
250
251        #[inline]
252        fn apply_output(&'a self, cx: &mut ApplyContext<'_>) -> ApplyResult<Self::Future> {
253            self.apply(cx)
254        }
255    }
256
257    pub trait Sealed {}
258
259    impl<'a, E> Sealed for E
260    where
261        E: Endpoint<'a>,
262        E::Output: Output,
263    {
264    }
265}