tower_web/routing/
resource.rs

1use error;
2use response::Serializer;
3use routing::{RouteMatch, RouteSet};
4use util::BufStream;
5
6use bytes::Buf;
7use futures::{Future, Poll};
8use futures::future::FutureResult;
9use http;
10
11use std::marker::PhantomData;
12
13/// A `Resource` processes HTTP requests received by the service.
14///
15/// A single service is composed of one or more resources. A resource instance
16/// is created with a route set representing the set of routes that it is able
17/// to handle. The service merges the route sets together and uses it to match
18/// inbound requests.
19///
20/// When matching a route, the route set returns a `Self::Destination` value.
21/// This value is then provided to `Resource::dispatch` and this is how the
22/// resource instance knows which method to dispatch the request to.
23///
24/// Users are not expected to implement `Resource` themselves. Instead, the
25/// `impl_web!` macro will generate a `Resource` implementation. The
26/// implementation is then passed to `ServiceBuilder` to define the web service.
27pub trait Resource: Clone {
28    /// Token mapping a route to a resource method.
29    type Destination: Clone + Send + Sync + 'static;
30
31    /// The HTTP request body type.
32    type RequestBody: BufStream;
33
34    /// Buffer type yielded by the response body.
35    type Buf: Buf;
36
37    /// The HTTP response body type.
38    ///
39    /// This value will yield one or more `Self::Buf` values.
40    type Body: BufStream<Item = Self::Buf, Error = ::Error>;
41
42    /// Response future
43    type Future: ResourceFuture<Body = Self::Body>;
44
45    /// Process the HTTP request and return the response asynchronously.
46    ///
47    /// The HTTP request has already been matched against the route set before
48    /// calling this function. The `destination` and `route_match` arguments
49    /// provide the necessary context for the resource to process the matched
50    /// HTTP request.
51    fn dispatch(
52        &mut self,
53        destination: Self::Destination,
54        route_match: &RouteMatch,
55        body: Self::RequestBody,
56    ) -> Self::Future;
57}
58
59/// A specialized response future returned by resources.
60///
61/// The `ResourceFuture` allows passing the HTTP response into the future when
62/// polling.
63pub trait ResourceFuture {
64    /// HTTP response body type
65    type Body;
66
67    /// Attempt to resolve the response future to a final value.
68    fn poll_response(&mut self, request: &http::Request<()>)
69        -> Poll<http::Response<Self::Body>, ::Error>;
70}
71
72/// Convert a value into a `Resource`
73pub trait IntoResource<S, RequestBody>
74where S: Serializer,
75      RequestBody: BufStream,
76{
77    /// Token mapping a route to a resource method.
78    ///
79    /// This will always be set to the same type as
80    /// `Self::Resource::Destination`.
81    type Destination: Clone + Send + Sync + 'static;
82
83    /// The `Resource` value being converted to
84    type Resource: Resource<Destination = Self::Destination,
85                            RequestBody = RequestBody>;
86
87    /// Returns the resource's set of routes.
88    fn routes(&self) -> RouteSet<Self::Destination>;
89
90    /// Convert `self` into a `Resource` value.
91    fn into_resource(self, serializer: S) -> Self::Resource;
92}
93
94impl<T, B> ResourceFuture for T
95where
96    T: Future<Item = http::Response<B>, Error = ::Error>
97{
98    type Body = B;
99
100    fn poll_response(&mut self, _: &http::Request<()>) -> Poll<T::Item, ::Error> {
101        self.poll()
102    }
103}
104
105/// A resource with no methods.
106///
107/// Attempting to route to this resource will result in a 404 response.
108#[derive(Debug)]
109pub struct Unit<B> {
110    _p: PhantomData<B>,
111}
112
113impl<B> Unit<B> {
114    /// Create a new `Unit` instance.
115    pub fn new() -> Self {
116        Unit { _p: PhantomData }
117    }
118}
119
120impl<B> Resource for Unit<B>
121where B: BufStream,
122{
123    type Destination = ();
124    type RequestBody = B;
125    type Buf = <Self::Body as BufStream>::Item;
126    type Body = error::Map<String>;
127    type Future = FutureResult<http::Response<Self::Body>, ::Error>;
128
129    fn dispatch(&mut self, _: (), _: &RouteMatch, _: Self::RequestBody) -> Self::Future {
130        unreachable!();
131    }
132}
133
134impl<B> Clone for Unit<B> {
135    fn clone(&self) -> Self {
136        Unit::new()
137    }
138}