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
use error;
use response::Serializer;
use routing::{RouteMatch, RouteSet};
use util::BufStream;

use bytes::Buf;
use futures::{Future, Poll};
use futures::future::FutureResult;
use http;

use std::marker::PhantomData;

/// A `Resource` processes HTTP requests received by the service.
///
/// A single service is composed of one or more resources. A resource instance
/// is created with a route set representing the set of routes that it is able
/// to handle. The service merges the route sets together and uses it to match
/// inbound requests.
///
/// When matching a route, the route set returns a `Self::Destination` value.
/// This value is then provided to `Resource::dispatch` and this is how the
/// resource instance knows which method to dispatch the request to.
///
/// Users are not expected to implement `Resource` themselves. Instead, the
/// `impl_web!` macro will generate a `Resource` implementation. The
/// implementation is then passed to `ServiceBuilder` to define the web service.
pub trait Resource: Clone {
    /// Token mapping a route to a resource method.
    type Destination: Clone + Send + Sync + 'static;

    /// The HTTP request body type.
    type RequestBody: BufStream;

    /// Buffer type yielded by the response body.
    type Buf: Buf;

    /// The HTTP response body type.
    ///
    /// This value will yield one or more `Self::Buf` values.
    type Body: BufStream<Item = Self::Buf, Error = ::Error>;

    /// Response future
    type Future: ResourceFuture<Body = Self::Body>;

    /// Process the HTTP request and return the response asynchronously.
    ///
    /// The HTTP request has already been matched against the route set before
    /// calling this function. The `destination` and `route_match` arguments
    /// provide the necessary context for the resource to process the matched
    /// HTTP request.
    fn dispatch(
        &mut self,
        destination: Self::Destination,
        route_match: &RouteMatch,
        body: Self::RequestBody,
    ) -> Self::Future;
}

/// A specialized response future returned by resources.
///
/// The `ResourceFuture` allows passing the HTTP response into the future when
/// polling.
pub trait ResourceFuture {
    /// HTTP response body type
    type Body;

    /// Attempt to resolve the response future to a final value.
    fn poll_response(&mut self, request: &http::Request<()>)
        -> Poll<http::Response<Self::Body>, ::Error>;
}

/// Convert a value into a `Resource`
pub trait IntoResource<S, RequestBody>
where S: Serializer,
      RequestBody: BufStream,
{
    /// Token mapping a route to a resource method.
    ///
    /// This will always be set to the same type as
    /// `Self::Resource::Destination`.
    type Destination: Clone + Send + Sync + 'static;

    /// The `Resource` value being converted to
    type Resource: Resource<Destination = Self::Destination,
                            RequestBody = RequestBody>;

    /// Returns the resource's set of routes.
    fn routes(&self) -> RouteSet<Self::Destination>;

    /// Convert `self` into a `Resource` value.
    fn into_resource(self, serializer: S) -> Self::Resource;
}

impl<T, B> ResourceFuture for T
where
    T: Future<Item = http::Response<B>, Error = ::Error>
{
    type Body = B;

    fn poll_response(&mut self, _: &http::Request<()>) -> Poll<T::Item, ::Error> {
        self.poll()
    }
}

/// A resource with no methods.
///
/// Attempting to route to this resource will result in a 404 response.
#[derive(Debug)]
pub struct Unit<B> {
    _p: PhantomData<B>,
}

impl<B> Unit<B> {
    /// Create a new `Unit` instance.
    pub fn new() -> Self {
        Unit { _p: PhantomData }
    }
}

impl<B> Resource for Unit<B>
where B: BufStream,
{
    type Destination = ();
    type RequestBody = B;
    type Buf = <Self::Body as BufStream>::Item;
    type Body = error::Map<String>;
    type Future = FutureResult<http::Response<Self::Body>, ::Error>;

    fn dispatch(&mut self, _: (), _: &RouteMatch, _: Self::RequestBody) -> Self::Future {
        unreachable!();
    }
}

impl<B> Clone for Unit<B> {
    fn clone(&self) -> Self {
        Unit::new()
    }
}