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
use anyhow::Result;
use hyper::Body;
use std::{future::Future, pin::Pin};

pub use hyper::http::response::Builder as ResponseBuilder;
pub type Request = hyper::Request<Body>;
pub type Response = Result<hyper::Response<Body>>;

/// A route path is just a vec of [PathSegment](enum.PathSegment.html)s.
///
/// Use the [path!](../macro.path.html) macro to generate this more easily.
pub type Path<'a> = Vec<PathSegment<'a>>;

/// Create a [Path](route/type.Path.html) with simplified syntax.
/// ```
/// path![foo / _ / bar / _] // -> vec![Static("foo"), Dynamic, Static("bar"), Dynamic]
/// ```
#[macro_export]
macro_rules! path {
	[] => { vec![] };
	[ @single _ ] => {
		PathSegment::Dynamic
	};
	[ @single $first:tt ] => {
		PathSegment::Static(stringify!($first))
	};
	[ $($segment:tt) / * ] => {
		vec![$(path![@single $segment]), *]
	};
}

/// Path segments are matched during routing. Static segments are matched through hash equality.
/// If no static segments match, a corresponding dynamic segment is attempted. For example:
/// `GET /foo/bar` matches `vec![Static("foo"), Dynamic]` instead of `vec![Dynamic, Dynamic]`.
///
/// Dynamic parameters are collected during routing and passed into the handler in an ordered list.
#[derive(Debug, Eq, PartialEq, Hash)]
pub enum PathSegment<'a> {
	Dynamic,
	Static(&'a str),
}

/// Represents the route handler type. Although this is typed with a generic return type, this is
/// only to allow async functions to be used as handlers. T is generally going to be `impl Future<
/// Output = Response>`, meaning your route handlers are going to look exactly like this:
/// ```
/// async fn handler(params: Vec<String>, req: Request) -> Response {}
/// ```
pub type Route<T> = fn(Vec<String>, Request) -> T;

/// Boxed closure for route handlers. Apparently different abstract types don't match, so we need
/// to box the return type of the user-land route handlers. To keep the API clean, this type is
/// used internally and created when the user registers a route.
pub(crate) type DynRoute = Box<
	dyn Fn(Vec<String>, Request) -> Pin<Box<dyn Future<Output = Response> + Send>> + Send + Sync,
>;