mirror of https://github.com/rwf2/Rocket.git
HRTB for the win! Manual routes example fully working.
This commit is contained in:
parent
72329a7145
commit
3dfa049a1a
|
@ -5,4 +5,3 @@ authors = ["Sergio Benitez <sb@sergio.bz>"]
|
|||
|
||||
[dependencies]
|
||||
rocket = { path = "../../lib" }
|
||||
rocket_macros = { path = "../../macros" }
|
||||
|
|
|
@ -3,23 +3,25 @@ extern crate rocket;
|
|||
use rocket::{Rocket, Request, Response, Route};
|
||||
use rocket::Method::*;
|
||||
|
||||
fn root(req: Request) -> Response<'static> {
|
||||
fn root(req: Request) -> Response {
|
||||
let name = req.get_param(0).unwrap_or("unnamed");
|
||||
Response::new(format!("Hello, {}!", name))
|
||||
}
|
||||
|
||||
// TODO: Work with these lifetimes.
|
||||
#[allow(dead_code)]
|
||||
fn lifetime_root<'a>(req: Request<'a>) -> Response<'a> {
|
||||
Response::new(req.get_uri())
|
||||
fn echo_url<'a>(req: Request<'a>) -> Response<'a> {
|
||||
Response::new(req.get_uri().split_at(6).1)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut rocket = Rocket::new("localhost", 8000);
|
||||
|
||||
let first = Route::new(Get, "/hello", root);
|
||||
let second = Route::new(Get, "/hello/<any>", root);
|
||||
Rocket::new("localhost", 8000).mount_and_launch("/", &[&first, &second]);
|
||||
rocket.mount("/", vec![first, second]);
|
||||
|
||||
// This below _should_ work.
|
||||
// let lifetime = Route::new(Get, "/other", lifetime_root);
|
||||
// Rocket::new("localhost", 8000).mount_and_launch("/", &[&lifetime]);
|
||||
let echo = Route::new(Get, "/", echo_url);
|
||||
rocket.mount("/echo:<str>", vec![echo]);
|
||||
|
||||
rocket.launch();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
use method::Method;
|
||||
use handler::Handler;
|
||||
|
||||
pub struct StaticRouteInfo {
|
||||
pub method: Method,
|
||||
pub path: &'static str,
|
||||
pub handler: Handler
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(str_char)]
|
||||
#![feature(str_char, question_mark)]
|
||||
#![feature(specialization)]
|
||||
|
||||
extern crate term_painter;
|
||||
|
@ -9,6 +9,7 @@ mod error;
|
|||
mod param;
|
||||
mod router;
|
||||
mod rocket;
|
||||
mod codegen;
|
||||
|
||||
pub mod request;
|
||||
pub mod response;
|
||||
|
@ -16,9 +17,10 @@ pub mod response;
|
|||
pub mod handler {
|
||||
use super::{Request, Response};
|
||||
|
||||
pub type Handler<'a> = fn(Request) -> Response<'a>;
|
||||
pub type Handler = for<'r> fn(Request<'r>) -> Response<'r>;
|
||||
}
|
||||
|
||||
pub use codegen::StaticRouteInfo;
|
||||
pub use request::Request;
|
||||
pub use method::Method;
|
||||
pub use response::{Response, Responder};
|
||||
|
|
|
@ -9,10 +9,6 @@ pub struct Request<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Request<'a> {
|
||||
pub fn empty() -> Request<'static> {
|
||||
Request::new(vec![], "")
|
||||
}
|
||||
|
||||
pub fn new(params: Vec<&'a str>, uri: &'a str) -> Request<'a> {
|
||||
Request {
|
||||
params: params,
|
||||
|
|
|
@ -69,11 +69,6 @@ impl Rocket {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn mount_and_launch(mut self, base: &'static str, routes: Vec<Route>) {
|
||||
self.mount(base, routes);
|
||||
self.launch();
|
||||
}
|
||||
|
||||
pub fn launch(self) {
|
||||
if self.router.has_collisions() {
|
||||
println!("{}", Yellow.paint("Warning: route collisions detected!"));
|
||||
|
@ -84,4 +79,9 @@ impl Rocket {
|
|||
White.bold().paint(&full_addr));
|
||||
let _ = HyperServer::http(full_addr.as_str()).unwrap().handle(self);
|
||||
}
|
||||
|
||||
pub fn mount_and_launch(mut self, base: &'static str, routes: Vec<Route>) {
|
||||
self.mount(base, routes);
|
||||
self.launch();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ use method::Method;
|
|||
type Selector = (Method, usize);
|
||||
|
||||
pub struct Router {
|
||||
routes: HashMap<Selector, Vec<Route>> // for now
|
||||
routes: HashMap<Selector, Vec<Route>> // using 'selector' for now
|
||||
}
|
||||
|
||||
impl Router {
|
||||
|
|
|
@ -5,36 +5,36 @@ use method::Method;
|
|||
use super::{Collider, URI, URIBuf}; // :D
|
||||
use handler::Handler;
|
||||
|
||||
// FIXME: Take in the handler! Or maybe keep that in `Router`?
|
||||
pub struct Route {
|
||||
pub method: Method,
|
||||
pub handler: Handler<'static>,
|
||||
pub handler: Handler,
|
||||
pub path: URIBuf,
|
||||
pub rank: isize
|
||||
}
|
||||
|
||||
impl Route {
|
||||
pub fn ranked(rank: isize, m: Method, path: String,
|
||||
handler: Handler<'static>) -> Route {
|
||||
pub fn ranked<S>(rank: isize, m: Method, path: S, handler: Handler)
|
||||
-> Route where S: AsRef<str> {
|
||||
Route {
|
||||
method: m,
|
||||
path: URIBuf::new(path),
|
||||
path: URIBuf::from(path.as_ref()),
|
||||
handler: handler,
|
||||
rank: rank
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(m: Method, path: String, handler: Handler<'static>) -> Route {
|
||||
pub fn new<S>(m: Method, path: S, handler: Handler)
|
||||
-> Route where S: AsRef<str> {
|
||||
Route {
|
||||
method: m,
|
||||
handler: handler,
|
||||
rank: (!path.contains("<") as isize),
|
||||
path: URIBuf::new(path),
|
||||
rank: (!path.as_ref().contains("<") as isize),
|
||||
path: URIBuf::from(path.as_ref()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_path(&mut self, path: String) {
|
||||
self.path = URIBuf::new(path);
|
||||
pub fn set_path<S>(&mut self, path: S) where S: AsRef<str> {
|
||||
self.path = URIBuf::from(path.as_ref());
|
||||
}
|
||||
|
||||
// FIXME: Decide whether a component has to be fully variable or not. That
|
||||
|
@ -57,7 +57,7 @@ impl Route {
|
|||
|
||||
impl fmt::Display for Route {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
use std::cell::Cell;
|
||||
use super::Collider;
|
||||
use std::convert::From;
|
||||
use std::fmt::{self, Write};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct URI<'a> {
|
||||
path: &'a str,
|
||||
segment_count: Cell<Option<usize>>
|
||||
|
@ -32,9 +34,21 @@ impl<'a> URI<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Display for URI<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut last = '\0';
|
||||
for c in self.path.chars() {
|
||||
if !(c == '/' && last == '/') { f.write_char(c)?; }
|
||||
last = c;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<'a> Sync for URI<'a> { /* It's safe! */ }
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct URIBuf {
|
||||
path: String,
|
||||
segment_count: Cell<Option<usize>>
|
||||
|
@ -42,16 +56,8 @@ pub struct URIBuf {
|
|||
|
||||
// I don't like repeating all of this stuff. Is there a better way?
|
||||
impl URIBuf {
|
||||
pub fn new(path: String) -> URIBuf {
|
||||
URIBuf {
|
||||
segment_count: Cell::new(None),
|
||||
path: path,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn segment_count(&self) -> usize {
|
||||
self.segment_count.get().unwrap_or_else(|| {
|
||||
println!("Computing!");
|
||||
let count = self.segments().count();
|
||||
self.segment_count.set(Some(count));
|
||||
count
|
||||
|
@ -62,6 +68,10 @@ impl URIBuf {
|
|||
Segments(self.path.as_str())
|
||||
}
|
||||
|
||||
fn as_uri_uncached<'a>(&'a self) -> URI<'a> {
|
||||
URI::new(self.path.as_str())
|
||||
}
|
||||
|
||||
pub fn as_uri<'a>(&'a self) -> URI<'a> {
|
||||
let mut uri = URI::new(self.path.as_str());
|
||||
uri.segment_count = self.segment_count.clone();
|
||||
|
@ -79,6 +89,30 @@ impl URIBuf {
|
|||
|
||||
unsafe impl Sync for URIBuf { /* It's safe! */ }
|
||||
|
||||
impl fmt::Display for URIBuf {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.as_uri_uncached().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for URIBuf {
|
||||
fn from(path: String) -> URIBuf {
|
||||
URIBuf {
|
||||
segment_count: Cell::new(None),
|
||||
path: path,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for URIBuf {
|
||||
fn from(path: &'a str) -> URIBuf {
|
||||
URIBuf {
|
||||
segment_count: Cell::new(None),
|
||||
path: path.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Collider for URI<'a> {
|
||||
fn collides_with(&self, other: &URI) -> bool {
|
||||
if self.segment_count() != other.segment_count() {
|
||||
|
@ -156,7 +190,7 @@ mod tests {
|
|||
|
||||
fn seg_count(path: &str, expected: usize) -> bool {
|
||||
let actual = URI::new(path).segment_count();
|
||||
let actual_buf = URIBuf::new(path.to_string()).segment_count();
|
||||
let actual_buf = URIBuf::from(path).segment_count();
|
||||
if actual != expected || actual_buf != expected {
|
||||
println!("Count mismatch: expected {}, got {}.", expected, actual);
|
||||
println!("{}", if actual != expected { "lifetime" } else { "buf" });
|
||||
|
@ -173,7 +207,7 @@ mod tests {
|
|||
let uri = URI::new(path);
|
||||
let actual: Vec<&str> = uri.segments().collect();
|
||||
|
||||
let uri_buf = URIBuf::new(path.to_string());
|
||||
let uri_buf = URIBuf::from(path);
|
||||
let actual_buf: Vec<&str> = uri_buf.segments().collect();
|
||||
|
||||
actual == expected && actual_buf == expected
|
||||
|
|
|
@ -17,7 +17,7 @@ use syntax::parse::token::intern;
|
|||
use routes_macro::routes_macro;
|
||||
use route_decorator::route_decorator;
|
||||
|
||||
const STRUCT_PREFIX: &'static str = "ROCKET_ROUTE_STRUCT_";
|
||||
const STRUCT_PREFIX: &'static str = "static_rocket_route_info_for_";
|
||||
const FN_PREFIX: &'static str = "rocket_route_fn_";
|
||||
|
||||
#[plugin_registrar]
|
||||
|
|
|
@ -365,7 +365,8 @@ pub fn route_decorator(ecx: &mut ExtCtxt, sp: Span, meta_item: &MetaItem,
|
|||
let route_fn_name = prepend_ident(FN_PREFIX, &item.ident);
|
||||
let fn_name = item.ident;
|
||||
let route_fn_item = quote_item!(ecx,
|
||||
fn $route_fn_name<'rocket>(_req: rocket::Request) -> rocket::Response<'rocket> {
|
||||
fn $route_fn_name<'rocket>(_req: rocket::Request<'rocket>)
|
||||
-> rocket::Response<'rocket> {
|
||||
$form_stmt
|
||||
$fn_param_exprs
|
||||
let result = $fn_name($fn_param_idents);
|
||||
|
@ -381,7 +382,7 @@ pub fn route_decorator(ecx: &mut ExtCtxt, sp: Span, meta_item: &MetaItem,
|
|||
let method = method_variant_to_expr(ecx, route_params.method.node);
|
||||
push(Annotatable::Item(quote_item!(ecx,
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub static $struct_name: rocket::Route = rocket::Route {
|
||||
pub static $struct_name: rocket::StaticRouteInfo = rocket::StaticRouteInfo {
|
||||
method: $method,
|
||||
path: $path,
|
||||
handler: $route_fn_name
|
||||
|
|
Loading…
Reference in New Issue