diff --git a/codegen/src/decorators/route.rs b/codegen/src/decorators/route.rs index b2c490b8..ec6aafbe 100644 --- a/codegen/src/decorators/route.rs +++ b/codegen/src/decorators/route.rs @@ -144,18 +144,26 @@ impl RouteGenerateExt for RouteParams { } }; + // Note: the `None` case shouldn't happen if a route is matched. let ident = param.ident().prepend(PARAM_PREFIX); let expr = match param { - Param::Single(_) => quote_expr!(ecx, _req.get_param($i)), - Param::Many(_) => quote_expr!(ecx, _req.get_segments($i)), + Param::Single(_) => quote_expr!(ecx, match _req.get_param_str($i) { + Some(s) => <$ty as ::rocket::request::FromParam>::from_param(s), + None => return ::rocket::Response::forward(_data) + }), + Param::Many(_) => quote_expr!(ecx, match _req.get_raw_segments($i) { + Some(s) => <$ty as ::rocket::request::FromSegments>::from_segments(s), + None => return ::rocket::Response::forward(_data) + }), }; + let original_ident = param.ident(); fn_param_statements.push(quote_stmt!(ecx, let $ident: $ty = match $expr { Ok(v) => v, Err(e) => { println!(" => Failed to parse '{}': {:?}", - stringify!($ident), e); + stringify!($original_ident), e); return ::rocket::Response::forward(_data) } }; diff --git a/lib/src/request/request.rs b/lib/src/request/request.rs index 1b6e6925..b2a3d7ca 100644 --- a/lib/src/request/request.rs +++ b/lib/src/request/request.rs @@ -8,7 +8,7 @@ use error::Error; use super::{FromParam, FromSegments}; use router::Route; -use http::uri::{URI, URIBuf}; +use http::uri::{URI, URIBuf, Segments}; use http::hyper::{header, HyperCookie, HyperHeaders, HyperMethod, HyperRequestUri}; use http::{Method, ContentType, Cookies}; @@ -45,14 +45,20 @@ impl Request { /// let my_param: T = request.get_param(n); /// } /// ``` - #[inline(always)] pub fn get_param<'r, T: FromParam<'r>>(&'r self, n: usize) -> Result { + let param = self.get_param_str(n).ok_or(Error::NoKey)?; + T::from_param(param).map_err(|_| Error::BadParse) + } + + /// Get the `n`th path parameter, if it exists. + #[doc(hidden)] + pub fn get_param_str(&self, n: usize) -> Option<&str> { let params = self.params.borrow(); if n >= params.len() { debug!("{} is >= param count {}", n, params.len()); - Err(Error::NoKey) + None } else { - T::from_param(params[n]).map_err(|_| Error::BadParse) + Some(¶ms[n]) } } @@ -73,16 +79,22 @@ impl Request { /// `request.get_segments::(1)` will attempt to parse the segments /// `"there/i/am/here"` as type `T`. pub fn get_segments<'r, T: FromSegments<'r>>(&'r self, i: usize) -> Result { + let segments = self.get_raw_segments(i).ok_or(Error::NoKey)?; + T::from_segments(segments).map_err(|_| Error::BadParse) + } + + /// Get the segments beginning at the `i`th, if they exists. + #[doc(hidden)] + pub fn get_raw_segments(&self, i: usize) -> Option { if i >= self.uri().segment_count() { debug!("{} is >= segment count {}", i, self.uri().segment_count()); - Err(Error::NoKey) + None } else { // TODO: Really want to do self.uri.segments().skip(i).into_inner(), // but the std lib doesn't implement it for Skip. let mut segments = self.uri.as_uri().segments(); for _ in segments.by_ref().take(i) { /* do nothing */ } - - T::from_segments(segments).map_err(|_| Error::BadParse) + Some(segments) } }