diff --git a/examples/hello/src/main.rs b/examples/hello/src/main.rs index dd22479a..27899282 100644 --- a/examples/hello/src/main.rs +++ b/examples/hello/src/main.rs @@ -4,6 +4,11 @@ extern crate rocket; use rocket::Rocket; +#[route(GET, path = "/")] +fn simple() -> &'static str { + "Hello, simple example world! How is thou?" +} + #[route(GET, path = "/")] fn hello(name: String) -> String { format!("Hello, {}!", name) @@ -16,5 +21,5 @@ fn bye(x: usize, y: usize) -> String { fn main() { let rocket = Rocket::new("localhost", 8000); - rocket.mount_and_launch("/", routes![hello, bye]); + rocket.mount_and_launch("/", routes![simple, hello, bye]); } diff --git a/lib/src/lib.rs b/lib/src/lib.rs index f3d2d299..6071abf7 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -5,9 +5,11 @@ mod error; mod response; mod request; +use std::io::Write; + pub use method::Method; pub use error::Error; -pub use response::Response; +pub use response::{Body, Response}; pub use request::Request; use hyper::server::Handler as HypHandler; @@ -16,27 +18,41 @@ use hyper::server::Response as HypResponse; use hyper::net::Fresh as HypFresh; use hyper::Server; -pub type Handler = fn(Request) -> Response; +pub type Handler<'a> = fn(Request) -> Response<'a>; #[allow(dead_code)] -pub struct Route<'a> { +#[derive(Clone)] +pub struct Route<'a, 'b> { pub method: Method, pub path: &'a str, - pub handler: Handler + pub handler: Handler<'b> } #[allow(dead_code)] pub struct Rocket { address: &'static str, port: isize, + handler: Option> // just for testing // mounts: HashMap<&'static str, Route<'a>> } impl HypHandler for Rocket { fn handle<'a, 'k>(&'a self, req: HypRequest<'a, 'k>, - res: HypResponse<'a, HypFresh>) { + mut res: HypResponse<'a, HypFresh>) { println!("Request: {:?}", req.uri); - res.send(b"Hello World!").unwrap(); + if self.handler.is_some() { + let response = (self.handler.as_ref().unwrap().handler)(Request::empty()); + *(res.headers_mut()) = response.headers; + *(res.status_mut()) = response.status; + match response.body { + Body::Str(string) => { + let mut stream = res.start().unwrap(); + stream.write_all(string.as_bytes()).unwrap(); + stream.end(); + } + _ => println!("UNIMPLEMENTED") + } + } } } @@ -44,20 +60,25 @@ impl Rocket { pub fn new(address: &'static str, port: isize) -> Rocket { Rocket { address: address, - port: port + port: port, + handler: None } } - pub fn mount(&mut self, base: &str, routes: &[&Route]) -> &mut Self { + pub fn mount(&mut self, base: &str, routes: &[&Route<'static, 'static>]) -> &mut Self { println!("🛰 Mounting '{}':", base); for route in routes { + if self.handler.is_none() { + println!("\t* INSTALLED: {} '{}'", route.method, route.path); + self.handler = Some((*route).clone()); + } println!("\t* {} '{}'", route.method, route.path); } self } - pub fn mount_and_launch(mut self, base: &str, routes: &[&Route]) { + pub fn mount_and_launch(mut self, base: &str, routes: &[&Route<'static, 'static>]) { self.mount(base, routes); self.launch(); } diff --git a/lib/src/request.rs b/lib/src/request.rs index 1648c5ed..e88bbab1 100644 --- a/lib/src/request.rs +++ b/lib/src/request.rs @@ -4,6 +4,10 @@ use error::Error; pub struct Request; impl Request { + pub fn empty() -> Request { + Request + } + pub fn get_param_str(&self, name: &str) -> Result<&str, Error> { Err(Error::NoKey) } diff --git a/lib/src/response.rs b/lib/src/response.rs index 245b9523..0cd1da46 100644 --- a/lib/src/response.rs +++ b/lib/src/response.rs @@ -1,20 +1,67 @@ -pub struct Response; +pub use hyper::status::StatusCode; +pub use hyper::header::{self, Headers}; +use std::io::Read; -impl<'a> From<&'a str> for Response { - fn from(_s: &'a str) -> Self { - Response +pub enum Body<'a> { + Bytes(&'a [u8]), + Str(&'a str), + String(String), + Stream(Box), + Empty +} + +pub struct Response<'a> { + pub status: StatusCode, + pub headers: Headers, + pub body: Body<'a> +} + +impl<'a> Response<'a> { + pub fn empty() -> Response<'a> { + Response { + status: StatusCode::Ok, + headers: Headers::new(), + body: Body::Empty + } + } + + pub fn not_found() -> Response<'a> { + Response { + status: StatusCode::NotFound, + headers: Headers::new(), + body: Body::Empty + } + } + + pub fn server_error() -> Response<'a> { + Response { + status: StatusCode::InternalServerError, + headers: Headers::new(), + body: Body::Empty + } } } -impl From for Response { - fn from(_s: String) -> Self { - Response +impl<'a> From<&'a str> for Response<'a> { + fn from(s: &'a str) -> Self { + let mut headers = Headers::new(); + headers.set(header::ContentLength(s.len() as u64)); + Response { + status: StatusCode::Ok, + headers: headers, + body: Body::Str(s) + } } } -impl Response { - pub fn error(number: usize) -> Response { - println!("ERROR {}!", number); - Response +impl<'a> From for Response<'a> { + fn from(s: String) -> Self { + let mut headers = Headers::new(); + headers.set(header::ContentLength(s.len() as u64)); + Response { + status: StatusCode::Ok, + headers: headers, + body: Body::String(s) + } } } diff --git a/macros/src/route_decorator.rs b/macros/src/route_decorator.rs index 83d594ae..474296af 100644 --- a/macros/src/route_decorator.rs +++ b/macros/src/route_decorator.rs @@ -189,9 +189,9 @@ pub fn route_decorator(ecx: &mut ExtCtxt, sp: Span, meta_item: &MetaItem, for param in &fn_params { let param_ident = str_to_ident(param.as_str()); fn_param_exprs.push(quote_stmt!(ecx, - let $param_ident = match req.get_param($param) { + let $param_ident = match _req.get_param($param) { Ok(v) => v, - Err(_) => return rocket::Response::error(200) + Err(_) => return rocket::Response::not_found() }; ).unwrap()); } @@ -209,7 +209,7 @@ 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(req: rocket::Request) -> rocket::Response { + fn $route_fn_name<'a>(_req: rocket::Request) -> rocket::Response<'a> { $fn_param_exprs let result = $fn_name($fn_param_idents); rocket::Response::from(result) @@ -223,7 +223,7 @@ pub fn route_decorator(ecx: &mut ExtCtxt, sp: Span, meta_item: &MetaItem, let method = method_variant_to_expr(ecx, route_params.method); push(Annotatable::Item(quote_item!(ecx, #[allow(non_upper_case_globals)] - pub static $struct_name: rocket::Route<'static> = rocket::Route { + pub static $struct_name: rocket::Route<'static, 'static> = rocket::Route { method: $method, path: $path, handler: $route_fn_name diff --git a/macros/src/routes_macro.rs b/macros/src/routes_macro.rs index ee766b77..c16e0510 100644 --- a/macros/src/routes_macro.rs +++ b/macros/src/routes_macro.rs @@ -42,7 +42,7 @@ pub fn routes_macro(ecx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) last_seg.identifier = new_ident; } - // Build up the P for each &path. + // Build up the P for each path. let path_exprs = paths.iter().map(|p| { quote_expr!(ecx, &$p) }).collect(); MacEager::expr(ecx.expr_vec_slice(sp, path_exprs)) }