mirror of https://github.com/rwf2/Rocket.git
It works! Next steps: clean-up, error handling, docs.
This commit is contained in:
parent
5cdb645fc9
commit
433a9119bd
|
@ -3,36 +3,19 @@
|
||||||
|
|
||||||
extern crate rocket;
|
extern crate rocket;
|
||||||
use rocket::Rocket;
|
use rocket::Rocket;
|
||||||
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
|
||||||
#[route(GET, path = "/")]
|
#[route(GET, path = "/")]
|
||||||
fn simple() -> File {
|
fn root() -> File {
|
||||||
File::open("/tmp/index.html").unwrap()
|
File::open("/tmp/index.html").unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[route(GET, path = "/hello/")]
|
#[route(GET, path = "/hello/<name>/<age>")]
|
||||||
fn simple2() -> &'static str {
|
fn hello(name: &str, age: i8) -> String {
|
||||||
"Hello, world!"
|
|
||||||
}
|
|
||||||
|
|
||||||
#[route(GET, path = "/hello")]
|
|
||||||
fn simple3() -> String {
|
|
||||||
String::from("Hello, world!")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[route(GET, path = "/<name>/<age>")]
|
|
||||||
fn simple4(name: &str, age: i8) -> String {
|
|
||||||
format!("Hello, {} year old named {}!", age, name)
|
format!("Hello, {} year old named {}!", age, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[route(GET, path = "/something")]
|
|
||||||
fn simple5() -> &'static str {
|
|
||||||
"hi"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut rocket = Rocket::new("localhost", 8000);
|
let rocket = Rocket::new("localhost", 8000);
|
||||||
rocket.mount("/", routes![simple, simple2, simple3, simple4, simple5]);
|
rocket.mount_and_launch("/", routes![root, hello]);
|
||||||
rocket.mount_and_launch("/hello/", routes![simple, simple3, simple4, simple5]);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
BadMethod,
|
BadMethod,
|
||||||
BadParse,
|
BadParse,
|
||||||
|
NoRoute,
|
||||||
NoKey
|
NoKey
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,15 +27,14 @@ use hyper::Server;
|
||||||
|
|
||||||
pub type Handler<'a> = fn(Request) -> Response<'a>;
|
pub type Handler<'a> = fn(Request) -> Response<'a>;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
// TODO: Figure out if having Handler<'static> there is a good idea.
|
||||||
#[derive(Clone)]
|
pub struct Route {
|
||||||
pub struct Route<'a> {
|
|
||||||
pub method: Method,
|
pub method: Method,
|
||||||
pub path: &'static str,
|
pub path: &'static str,
|
||||||
pub handler: Handler<'a>
|
pub handler: Handler<'static>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> fmt::Display for Route<'a> {
|
impl<'a> fmt::Display for Route {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{} {:?}", Green.paint(&self.method), Blue.paint(&self.path))
|
write!(f, "{} {:?}", Green.paint(&self.method), Blue.paint(&self.path))
|
||||||
}
|
}
|
||||||
|
@ -54,9 +53,15 @@ impl HypHandler for Rocket {
|
||||||
if let RequestUri::AbsolutePath(uri_string) = req.uri {
|
if let RequestUri::AbsolutePath(uri_string) = req.uri {
|
||||||
if let Some(method) = Method::from_hyp(req.method) {
|
if let Some(method) = Method::from_hyp(req.method) {
|
||||||
println!("Request: {:?}", uri_string);
|
println!("Request: {:?}", uri_string);
|
||||||
self.router.route(method, uri_string.as_str());
|
let uri_str = uri_string.as_str();
|
||||||
res.send(b"Hello, world!").unwrap();
|
let route = self.router.route(method, uri_str);
|
||||||
return;
|
let mut response = route.map_or(Response::not_found(), |route| {
|
||||||
|
let params = route.get_params(uri_str);
|
||||||
|
let request = Request::new(params, uri_str);
|
||||||
|
(route.handler)(request)
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.body.respond(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,19 +78,17 @@ impl Rocket {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mount(&mut self, base: &'static str, routes: &[&Route<'static>])
|
pub fn mount(&mut self, base: &'static str, routes: &[&Route]) -> &mut Self {
|
||||||
-> &mut Self {
|
|
||||||
println!("🛰 {} '{}':", Magenta.paint("Mounting"), Blue.paint(base));
|
println!("🛰 {} '{}':", Magenta.paint("Mounting"), Blue.paint(base));
|
||||||
for route in routes {
|
for route in routes {
|
||||||
println!("\t* {}", route);
|
println!("\t* {}", route);
|
||||||
self.router.add_route(route.method.clone(), base, route.path);
|
self.router.add_route(route.method, base, route.path, route.handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mount_and_launch(mut self, base: &'static str,
|
pub fn mount_and_launch(mut self, base: &'static str, routes: &[&Route]) {
|
||||||
routes: &[&Route<'static>]) {
|
|
||||||
self.mount(base, routes);
|
self.mount(base, routes);
|
||||||
self.launch();
|
self.launch();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,32 @@
|
||||||
use error::Error;
|
use error::Error;
|
||||||
use param::FromParam;
|
use param::FromParam;
|
||||||
|
|
||||||
pub struct Request;
|
pub struct Request<'a> {
|
||||||
|
params: Vec<&'a str>,
|
||||||
|
uri: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
impl Request {
|
impl<'a> Request<'a> {
|
||||||
pub fn empty() -> Request {
|
pub fn empty() -> Request<'static> {
|
||||||
Request
|
Request::new(vec![], "")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_param_str<'a>(&self, _name: &'a str) -> Result<&'a str, Error> {
|
pub fn new(params: Vec<&'a str>, uri: &'a str) -> Request<'a> {
|
||||||
|
Request {
|
||||||
|
params: params,
|
||||||
|
uri: uri
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_uri(&self) -> &'a str {
|
||||||
|
self.uri
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_param<T: FromParam<'a>>(&'a self, n: usize) -> Result<T, Error> {
|
||||||
|
if n >= self.params.len() {
|
||||||
Err(Error::NoKey)
|
Err(Error::NoKey)
|
||||||
|
} else {
|
||||||
|
T::from_param(self.params[n])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_param<'b, T: FromParam<'b>>(&self, name: &'b str)
|
|
||||||
-> Result<T, Error> {
|
|
||||||
self.get_param_str(name).and_then(T::from_param)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,8 @@ pub trait Collider<T: ?Sized = Self> {
|
||||||
fn collides_with(&self, other: &T) -> bool;
|
fn collides_with(&self, other: &T) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_match_until(break_c: char, a: &str, b: &str, dir: bool) -> bool {
|
pub fn index_match_until(break_c: char, a: &str, b: &str, dir: bool)
|
||||||
|
-> Option<(isize, isize)> {
|
||||||
let (a_len, b_len) = (a.len() as isize, b.len() as isize);
|
let (a_len, b_len) = (a.len() as isize, b.len() as isize);
|
||||||
let (mut i, mut j, delta) = if dir {
|
let (mut i, mut j, delta) = if dir {
|
||||||
(0, 0, 1)
|
(0, 0, 1)
|
||||||
|
@ -17,14 +18,18 @@ fn check_match_until(break_c: char, a: &str, b: &str, dir: bool) -> bool {
|
||||||
if c1 == break_c || c2 == break_c {
|
if c1 == break_c || c2 == break_c {
|
||||||
break;
|
break;
|
||||||
} else if c1 != c2 {
|
} else if c1 != c2 {
|
||||||
return false;
|
return None;
|
||||||
} else {
|
} else {
|
||||||
i += delta;
|
i += delta;
|
||||||
j += delta;
|
j += delta;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return Some((i, j));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_match_until(break_c: char, a: &str, b: &str, dir: bool) -> bool {
|
||||||
|
index_match_until(break_c, a, b, dir).is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! comp_to_str {
|
macro_rules! comp_to_str {
|
||||||
|
@ -42,7 +47,7 @@ macro_rules! comp_to_str {
|
||||||
impl<'a> Collider for Component<'a> {
|
impl<'a> Collider for Component<'a> {
|
||||||
fn collides_with(&self, other: &Component<'a>) -> bool {
|
fn collides_with(&self, other: &Component<'a>) -> bool {
|
||||||
let (a, b) = (comp_to_str!(self), comp_to_str!(other));
|
let (a, b) = (comp_to_str!(self), comp_to_str!(other));
|
||||||
check_match_until('<', a, b, true) && check_match_until('>', a, b, false)
|
do_match_until('<', a, b, true) && do_match_until('>', a, b, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,25 +57,30 @@ mod tests {
|
||||||
use router::route::Route;
|
use router::route::Route;
|
||||||
use Method;
|
use Method;
|
||||||
use Method::*;
|
use Method::*;
|
||||||
|
use {Request, Response};
|
||||||
|
|
||||||
type SimpleRoute = (Method, &'static str);
|
type SimpleRoute = (Method, &'static str);
|
||||||
|
|
||||||
|
fn dummy_handler(_req: Request) -> Response<'static> {
|
||||||
|
Response::empty()
|
||||||
|
}
|
||||||
|
|
||||||
fn m_collide(a: SimpleRoute, b: SimpleRoute) -> bool {
|
fn m_collide(a: SimpleRoute, b: SimpleRoute) -> bool {
|
||||||
let route_a = Route::new(a.0, "/", a.1);
|
let route_a = Route::new(a.0, "/", a.1, dummy_handler);
|
||||||
route_a.collides_with(&Route::new(b.0, "/", b.1))
|
route_a.collides_with(&Route::new(b.0, "/", b.1, dummy_handler))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collide(a: &'static str, b: &'static str) -> bool {
|
fn collide(a: &'static str, b: &'static str) -> bool {
|
||||||
let route_a = Route::new(Get, "/", a);
|
let route_a = Route::new(Get, "/", a, dummy_handler);
|
||||||
route_a.collides_with(&Route::new(Get, "/", b))
|
route_a.collides_with(&Route::new(Get, "/", b, dummy_handler))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn s_r_collide(a: &'static str, b: &'static str) -> bool {
|
fn s_r_collide(a: &'static str, b: &'static str) -> bool {
|
||||||
a.collides_with(&Route::new(Get, "/", b))
|
a.collides_with(&Route::new(Get, "/", b, dummy_handler))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn r_s_collide(a: &'static str, b: &'static str) -> bool {
|
fn r_s_collide(a: &'static str, b: &'static str) -> bool {
|
||||||
let route_a = Route::new(Get, "/", a);
|
let route_a = Route::new(Get, "/", a, dummy_handler);
|
||||||
route_a.collides_with(b)
|
route_a.collides_with(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ use self::route::Route;
|
||||||
use std::collections::hash_map::HashMap;
|
use std::collections::hash_map::HashMap;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use method::Method;
|
use method::Method;
|
||||||
|
use Handler;
|
||||||
|
|
||||||
type Selector = (Method, usize);
|
type Selector = (Method, usize);
|
||||||
|
|
||||||
|
@ -25,25 +26,28 @@ impl Router {
|
||||||
|
|
||||||
// FIXME: Take in Handler.
|
// FIXME: Take in Handler.
|
||||||
pub fn add_route(&mut self, method: Method, base: &'static str,
|
pub fn add_route(&mut self, method: Method, base: &'static str,
|
||||||
route: &'static str) {
|
route: &'static str, handler: Handler<'static>) {
|
||||||
let route = Route::new(method, base, route);
|
let route = Route::new(method, base, route, handler);
|
||||||
let selector = (method, route.component_count());
|
let selector = (method, route.component_count());
|
||||||
self.routes.entry(selector).or_insert(vec![]).push(route);
|
self.routes.entry(selector).or_insert(vec![]).push(route);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Make a `Router` trait with this function. Rename this `Router`
|
// TODO: Make a `Router` trait with this function. Rename this `Router`
|
||||||
// struct to something like `RocketRouter`.
|
// struct to something like `RocketRouter`.
|
||||||
// TODO: Return an array of matches to the parameters.
|
pub fn route<'b>(&'b self, method: Method, uri: &str) -> Option<&'b Route> {
|
||||||
pub fn route<'a>(&self, method: Method, uri: &'a str) {
|
let mut matched_route = None;
|
||||||
let path = Path::new(uri);
|
let path = Path::new(uri);
|
||||||
let num_components = path.components().count();
|
let num_components = path.components().count();
|
||||||
if let Some(routes) = self.routes.get(&(method, num_components)) {
|
if let Some(routes) = self.routes.get(&(method, num_components)) {
|
||||||
for route in routes {
|
for route in routes.iter().filter(|r| r.collides_with(uri)) {
|
||||||
if route.collides_with(uri) {
|
|
||||||
println!("Matched {} to: {}", uri, route);
|
println!("Matched {} to: {}", uri, route);
|
||||||
|
if let None = matched_route {
|
||||||
|
matched_route = Some(route);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
matched_route
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_collisions(&self) -> bool {
|
pub fn has_collisions(&self) -> bool {
|
||||||
|
@ -65,3 +69,133 @@ impl Router {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::Router;
|
||||||
|
use Method::*;
|
||||||
|
use {Response, Request};
|
||||||
|
|
||||||
|
fn dummy_handler(_req: Request) -> Response<'static> {
|
||||||
|
Response::empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn router_with_routes(routes: &[&'static str]) -> Router {
|
||||||
|
let mut router = Router::new();
|
||||||
|
for route in routes {
|
||||||
|
router.add_route(Get, "/", route, dummy_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
router
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_collisions() {
|
||||||
|
let router = router_with_routes(&["/hello", "/hello"]);
|
||||||
|
assert!(router.has_collisions());
|
||||||
|
|
||||||
|
let router = router_with_routes(&["/<a>", "/hello"]);
|
||||||
|
assert!(router.has_collisions());
|
||||||
|
|
||||||
|
let router = router_with_routes(&["/<a>", "/<b>"]);
|
||||||
|
assert!(router.has_collisions());
|
||||||
|
|
||||||
|
let router = router_with_routes(&["/hello/bob", "/hello/<b>"]);
|
||||||
|
assert!(router.has_collisions());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ok_routing() {
|
||||||
|
let router = router_with_routes(&["/hello"]);
|
||||||
|
assert!(router.route(Get, "/hello").is_some());
|
||||||
|
|
||||||
|
let router = router_with_routes(&["/<a>"]);
|
||||||
|
assert!(router.route(Get, "/hello").is_some());
|
||||||
|
assert!(router.route(Get, "/hi").is_some());
|
||||||
|
assert!(router.route(Get, "/bobbbbbbbbbby").is_some());
|
||||||
|
assert!(router.route(Get, "/dsfhjasdf").is_some());
|
||||||
|
|
||||||
|
let router = router_with_routes(&["/<a>/<b>"]);
|
||||||
|
assert!(router.route(Get, "/hello/hi").is_some());
|
||||||
|
assert!(router.route(Get, "/a/b/").is_some());
|
||||||
|
assert!(router.route(Get, "/i/a").is_some());
|
||||||
|
assert!(router.route(Get, "/jdlk/asdij").is_some());
|
||||||
|
|
||||||
|
let mut router = Router::new();
|
||||||
|
router.add_route(Put, "/", "/hello", dummy_handler);
|
||||||
|
router.add_route(Post, "/", "/hello", dummy_handler);
|
||||||
|
router.add_route(Delete, "/", "/hello", dummy_handler);
|
||||||
|
assert!(router.route(Put, "/hello").is_some());
|
||||||
|
assert!(router.route(Post, "/hello").is_some());
|
||||||
|
assert!(router.route(Delete, "/hello").is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_err_routing() {
|
||||||
|
let router = router_with_routes(&["/hello"]);
|
||||||
|
assert!(router.route(Put, "/hello").is_none());
|
||||||
|
assert!(router.route(Post, "/hello").is_none());
|
||||||
|
assert!(router.route(Options, "/hello").is_none());
|
||||||
|
assert!(router.route(Get, "/hell").is_none());
|
||||||
|
assert!(router.route(Get, "/hi").is_none());
|
||||||
|
assert!(router.route(Get, "/hello/there").is_none());
|
||||||
|
assert!(router.route(Get, "/hello/i").is_none());
|
||||||
|
assert!(router.route(Get, "/hillo").is_none());
|
||||||
|
|
||||||
|
let router = router_with_routes(&["/<a>"]);
|
||||||
|
assert!(router.route(Put, "/hello").is_none());
|
||||||
|
assert!(router.route(Post, "/hello").is_none());
|
||||||
|
assert!(router.route(Options, "/hello").is_none());
|
||||||
|
assert!(router.route(Get, "/hello/there").is_none());
|
||||||
|
assert!(router.route(Get, "/hello/i").is_none());
|
||||||
|
|
||||||
|
let router = router_with_routes(&["/<a>/<b>"]);
|
||||||
|
assert!(router.route(Get, "/a/b/c").is_none());
|
||||||
|
assert!(router.route(Get, "/a").is_none());
|
||||||
|
assert!(router.route(Get, "/a/").is_none());
|
||||||
|
assert!(router.route(Get, "/a/b/c/d").is_none());
|
||||||
|
assert!(router.route(Put, "/hello/hi").is_none());
|
||||||
|
assert!(router.route(Put, "/a/b").is_none());
|
||||||
|
assert!(router.route(Put, "/a/b").is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn match_params(router: &Router, path: &str, expected: &[&str]) -> bool {
|
||||||
|
router.route(Get, path).map_or(false, |route| {
|
||||||
|
let params = route.get_params(path);
|
||||||
|
if params.len() != expected.len() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..params.len() {
|
||||||
|
if params[i] != expected[i] {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_params() {
|
||||||
|
let router = router_with_routes(&["/<a>"]);
|
||||||
|
assert!(match_params(&router, "/hello", &["hello"]));
|
||||||
|
assert!(match_params(&router, "/hi", &["hi"]));
|
||||||
|
assert!(match_params(&router, "/bob", &["bob"]));
|
||||||
|
assert!(match_params(&router, "/i", &["i"]));
|
||||||
|
|
||||||
|
let router = router_with_routes(&["/hello"]);
|
||||||
|
assert!(match_params(&router, "/hello", &[]));
|
||||||
|
|
||||||
|
let router = router_with_routes(&["/<a>/<b>"]);
|
||||||
|
assert!(match_params(&router, "/a/b", &["a", "b"]));
|
||||||
|
assert!(match_params(&router, "/912/sas", &["912", "sas"]));
|
||||||
|
|
||||||
|
let router = router_with_routes(&["/hello/<b>"]);
|
||||||
|
assert!(match_params(&router, "/hello/b", &["b"]));
|
||||||
|
assert!(match_params(&router, "/hello/sergio", &["sergio"]));
|
||||||
|
|
||||||
|
let router = router_with_routes(&["/hello/<b>/age"]);
|
||||||
|
assert!(match_params(&router, "/hello/sergio/age", &["sergio"]));
|
||||||
|
assert!(match_params(&router, "/hello/you/age", &["you"]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,35 +4,68 @@ use std::path::{Path, PathBuf};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use method::Method;
|
use method::Method;
|
||||||
use super::Collider; // :D
|
use super::Collider; // :D
|
||||||
|
use std::path::Component;
|
||||||
|
use Handler;
|
||||||
|
|
||||||
// FIXME: Take in the handler! Or maybe keep that in `Router`?
|
// FIXME: Take in the handler! Or maybe keep that in `Router`?
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Route {
|
pub struct Route {
|
||||||
method: Method,
|
method: Method,
|
||||||
mount: &'static str,
|
|
||||||
route: &'static str,
|
|
||||||
n_components: usize,
|
n_components: usize,
|
||||||
|
pub handler: Handler<'static>,
|
||||||
path: PathBuf
|
path: PathBuf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! comp_to_str {
|
||||||
|
($component:expr) => (
|
||||||
|
match $component {
|
||||||
|
&Component::Normal(ref comp) => {
|
||||||
|
if let Some(string) = comp.to_str() { string }
|
||||||
|
else { panic!("Whoops, no string!") }
|
||||||
|
},
|
||||||
|
&Component::RootDir => "/",
|
||||||
|
&c@_ => panic!("Whoops, not normal: {:?}!", c)
|
||||||
|
};
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
impl Route {
|
impl Route {
|
||||||
pub fn new(m: Method, mount: &'static str, route: &'static str) -> Route {
|
pub fn new(m: Method, mount: &'static str, route: &'static str,
|
||||||
|
handler: Handler<'static>) -> Route {
|
||||||
let deduped_path = Route::dedup(mount, route);
|
let deduped_path = Route::dedup(mount, route);
|
||||||
let path = PathBuf::from(deduped_path);
|
let path = PathBuf::from(deduped_path);
|
||||||
|
|
||||||
Route {
|
Route {
|
||||||
method: m,
|
method: m,
|
||||||
mount: mount,
|
|
||||||
route: route,
|
|
||||||
n_components: path.components().count(),
|
n_components: path.components().count(),
|
||||||
path: path
|
handler: handler,
|
||||||
|
path: path,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn component_count(&self) -> usize {
|
pub fn component_count(&self) -> usize {
|
||||||
self.n_components
|
self.n_components
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: This is dirty (the comp_to_str and the RootDir thing). Might need
|
||||||
|
// to have my own wrapper arround path strings.
|
||||||
|
// FIXME: Decide whether a component has to be fully variable or not. That
|
||||||
|
// is, whether you can have: /a<a>b/
|
||||||
|
// TODO: Don't return a Vec...take in an &mut [&'a str] (no alloc!)
|
||||||
|
pub fn get_params<'a>(&self, uri: &'a str) -> Vec<&'a str> {
|
||||||
|
let mut result = Vec::with_capacity(self.component_count());
|
||||||
|
let route_components = self.path.components();
|
||||||
|
let uri_components = Path::new(uri).components();
|
||||||
|
|
||||||
|
for (route_comp, uri_comp) in route_components.zip(uri_components) {
|
||||||
|
if comp_to_str!(&route_comp).starts_with("<") {
|
||||||
|
result.push(comp_to_str!(&uri_comp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
fn dedup(base: &'static str, route: &'static str) -> String {
|
fn dedup(base: &'static str, route: &'static str) -> String {
|
||||||
let mut deduped = String::with_capacity(base.len() + route.len() + 1);
|
let mut deduped = String::with_capacity(base.len() + route.len() + 1);
|
||||||
|
|
||||||
|
@ -56,7 +89,7 @@ impl fmt::Display for Route {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Collider for Path {
|
impl Collider for Path {
|
||||||
// FIXME: It's expensive to compute the number of components: O(n) per path
|
// TODO: It's expensive to compute the number of components: O(n) per path
|
||||||
// where n == number of chars.
|
// where n == number of chars.
|
||||||
//
|
//
|
||||||
// Idea: Create a `CachedPath` type that caches the number of components
|
// Idea: Create a `CachedPath` type that caches the number of components
|
||||||
|
|
|
@ -189,10 +189,10 @@ pub fn route_decorator(ecx: &mut ExtCtxt, sp: Span, meta_item: &MetaItem,
|
||||||
debug!("Function Declaration: {:?}", fn_decl);
|
debug!("Function Declaration: {:?}", fn_decl);
|
||||||
|
|
||||||
let mut fn_param_exprs = vec![];
|
let mut fn_param_exprs = vec![];
|
||||||
for param in &fn_params {
|
for (i, param) in fn_params.iter().enumerate() {
|
||||||
let param_ident = str_to_ident(param.as_str());
|
let param_ident = str_to_ident(param.as_str());
|
||||||
let param_fn_item = quote_stmt!(ecx,
|
let param_fn_item = quote_stmt!(ecx,
|
||||||
let $param_ident = match _req.get_param($param) {
|
let $param_ident = match _req.get_param($i) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(_) => return rocket::Response::not_found()
|
Err(_) => return rocket::Response::not_found()
|
||||||
};
|
};
|
||||||
|
@ -230,7 +230,7 @@ pub fn route_decorator(ecx: &mut ExtCtxt, sp: Span, meta_item: &MetaItem,
|
||||||
let method = method_variant_to_expr(ecx, route_params.method);
|
let method = method_variant_to_expr(ecx, route_params.method);
|
||||||
push(Annotatable::Item(quote_item!(ecx,
|
push(Annotatable::Item(quote_item!(ecx,
|
||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
pub static $struct_name: rocket::Route<'static> = rocket::Route {
|
pub static $struct_name: rocket::Route = rocket::Route {
|
||||||
method: $method,
|
method: $method,
|
||||||
path: $path,
|
path: $path,
|
||||||
handler: $route_fn_name
|
handler: $route_fn_name
|
||||||
|
|
Loading…
Reference in New Issue