Remove unneeded lifetime in Request.

Previously, a Request's only lifetime parameter referred to itself. This
causes many issues and is simply wrong. Instead, use `transmute` to make
the lifetime `static`. As long the contents inside Request don't move or
change, the references are valid. We keep the lifetime as a phantom in
`Request` for future use.
This commit is contained in:
Sergio Benitez 2016-10-06 20:57:17 -07:00
parent bcb9bd860b
commit 39f7f2d32b
1 changed files with 21 additions and 12 deletions

View File

@ -34,11 +34,10 @@ pub struct Request<'a> {
/// The data in the request. /// The data in the request.
pub data: Vec<u8>, // FIXME: Don't read this! (bad Hyper.) pub data: Vec<u8>, // FIXME: Don't read this! (bad Hyper.)
uri: URIBuf, // FIXME: Should be URI (without Hyper). uri: URIBuf, // FIXME: Should be URI (without Hyper).
params: RefCell<Vec<&'static str>>,
cookies: Cookies, cookies: Cookies,
headers: HyperHeaders, // This sucks. headers: HyperHeaders, // This sucks.
/// Indexes into the URI. _phantom: Option<&'a str>,
// params: RefCell<Vec<(usize, usize)>>,
params: RefCell<Option<Vec<&'a str>>>,
} }
impl<'a> Request<'a> { impl<'a> Request<'a> {
@ -58,13 +57,13 @@ impl<'a> Request<'a> {
/// let my_param: T = request.get_param(n); /// let my_param: T = request.get_param(n);
/// } /// }
/// ``` /// ```
pub fn get_param<T: FromParam<'a>>(&self, n: usize) -> Result<T, Error> { pub fn get_param<'r, T: FromParam<'r>>(&'r self, n: usize) -> Result<T, Error> {
let params = self.params.borrow(); let params = self.params.borrow();
if params.is_none() || n >= params.as_ref().unwrap().len() { if n >= params.len() {
debug!("{} is >= param count {}", n, params.as_ref().unwrap().len()); debug!("{} is >= param count {}", n, params.len());
Err(Error::NoKey) Err(Error::NoKey)
} else { } else {
T::from_param(params.as_ref().unwrap()[n]).map_err(|_| Error::BadParse) T::from_param(params[n]).map_err(|_| Error::BadParse)
} }
} }
@ -101,12 +100,13 @@ impl<'a> Request<'a> {
#[doc(hidden)] #[doc(hidden)]
pub fn mock(method: Method, uri: &str) -> Request { pub fn mock(method: Method, uri: &str) -> Request {
Request { Request {
params: RefCell::new(None), params: RefCell::new(vec![]),
method: method, method: method,
cookies: Cookies::new(&[]), cookies: Cookies::new(&[]),
uri: URIBuf::from(uri), uri: URIBuf::from(uri),
data: vec![], data: vec![],
headers: HyperHeaders::new(), headers: HyperHeaders::new(),
_phantom: None,
} }
} }
@ -160,10 +160,18 @@ impl<'a> Request<'a> {
self.uri.as_uri() self.uri.as_uri()
} }
// FIXME: Don't need a refcell for this.
#[doc(hidden)] #[doc(hidden)]
pub fn set_params(&'a self, route: &Route) { pub fn set_params(&self, route: &Route) {
*self.params.borrow_mut() = Some(route.get_params(self.uri.as_uri())) // We use transmute to cast the lifetime of self.uri.as_uri() to
// 'static. This is because that lifetime refers to the String in URIBuf
// in this structure, which is (obviously) guaranteed to live as long as
// the structure AS LONG AS it is not moved out or changed. AS A RESULT,
// the `uri` fields MUST NEVER be changed once it is set.
// TODO: Find a way to enforce these. Look at OwningRef for inspiration.
use ::std::mem::transmute;
*self.params.borrow_mut() = unsafe {
transmute(route.get_params(self.uri.as_uri()))
};
} }
#[doc(hidden)] #[doc(hidden)]
@ -200,12 +208,13 @@ impl<'a> Request<'a> {
h_body.read_to_end(&mut data).unwrap(); h_body.read_to_end(&mut data).unwrap();
let request = Request { let request = Request {
params: RefCell::new(None), params: RefCell::new(vec![]),
method: method, method: method,
cookies: cookies, cookies: cookies,
uri: uri, uri: uri,
data: data, data: data,
headers: h_headers, headers: h_headers,
_phantom: None,
}; };
Ok(request) Ok(request)