1use failure::{Compat, Error};
2use hyper::service::Service;
3use hyper::{Body, Method, Request, Response, StatusCode};
4use std::borrow::Cow;
5use futures::prelude::*;
6
7type HandlerFuture = Box<dyn Future<Item = Response<Body>, Error = failure::Error> + Send + 'static>;
8
9pub type Handler = Box<dyn Fn(Request<Body>, Vec<String>) -> HandlerFuture + Send + 'static>;
16
17pub type Route = super::router::Route<Method, Handler>;
21
22pub type Router = super::router::Router<Method, Handler>;
26
27pub type Build = super::router::Build<Method, Handler>;
31
32macro_rules! route {
33 (
34 $(#$meta:tt)*
35 $name:ident => $method:expr
36 ) => {
37 $(#$meta)*
38 pub fn $name<P, F>(path: P, handler: F) -> Self
39 where
40 P: Into<Cow<'static, str>>,
41 F: Fn(Request<Body>, Vec<String>) -> HandlerFuture + Send + 'static
42 {
43 Self::new(path, $method, Box::new(handler))
44 }
45 };
46}
47
48impl Route {
49 route!(options => Method::OPTIONS);
50 route!(get => Method::GET);
51 route!(post => Method::POST);
52 route!(put => Method::PUT);
53 route!(delete => Method::DELETE);
54 route!(head => Method::HEAD);
55 route!(trace => Method::TRACE);
56 route!(connect => Method::CONNECT);
57 route!(patch => Method::PATCH);
58}
59
60macro_rules! build {
61 (
62 $(#$meta:tt)*
63 $name:ident
64 ) => {
65 $(#$meta)*
66 pub fn $name<P, F>(&mut self, path: P, handler: F) -> &mut Self
67 where
68 P: Into<Cow<'static, str>>,
69 F: Fn(Request<Body>, Vec<String>) -> HandlerFuture + Send + 'static
70 {
71 self.add(Route::$name(path, handler))
72 }
73 }
74}
75
76impl Build {
77 build!(options);
78 build!(get);
79 build!(post);
80 build!(put);
81 build!(delete);
82 build!(head);
83 build!(trace);
84 build!(connect);
85 build!(patch);
86
87 pub fn default_fn<F>(&mut self, default: F) -> &mut Self
88 where F: Fn(Request<Body>, Vec<String>) -> HandlerFuture + Send + 'static
89 {
90 self.with_default(Box::new(default))
91 }
92}
93
94impl Service for Router {
95 type ReqBody = Body;
96 type ResBody = Body;
97 type Error = Compat<Error>;
98 type Future = Box<dyn Future<Item = Response<Body>, Error = Compat<Error>> + Send + 'static>;
99
100 fn call(&mut self, req: Request<Self::ReqBody>) -> Self::Future {
101 let path = req.uri().path();
102 if let Some((handler, params)) = self.lookup(req.method(), path) {
103 let params = params.into_iter().map(str::to_string).collect();
104 Box::new(handler(req, params).map_err(Error::compat))
105 } else {
106 let response = Response::builder()
107 .status(StatusCode::NOT_FOUND)
108 .body(Body::empty())
109 .map_err(Error::from)
110 .map_err(Error::compat);
111 Box::new(futures::future::result(response))
112 }
113 }
114}