diff --git a/src/handler.rs b/src/handler.rs index 90603af..337a65b 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -1,66 +1,61 @@ use std::sync::Arc; -use tokio::sync::Mutex; use crate::{HTTPResult, Params}; use async_trait::async_trait; use http::{Request, Response}; -pub type HandlerFunc<'a, T, R> = - dyn Fn(&'a Request, Params, Option<&'a Response>) -> HTTPResult<'a, T, R>; +pub type HandlerFunc = + dyn Fn(Request, Params, Option>) -> HTTPResult + Sync; #[async_trait] -pub trait Handler<'a, 'b, T, R> +pub trait Handler where - Self: Send + Sync + 'b, + Self: Sync + Sized, { - async fn perform(&'b self, response: Option<&'a Response>) -> HTTPResult<'a, T, R>; + async fn perform( + &self, + req: Request, + response: Option>, + ) -> HTTPResult; } -pub struct BasicHandler<'a, T, R> +#[derive(Clone)] +pub struct BasicHandler where - T: Send + Sync + 'a, - R: Send + Sync + 'a, + Self: Sync + Sized, { - req: Arc>>, params: Params, - next: Option<&'a BasicHandler<'a, T, R>>, - func: &'a HandlerFunc<'a, T, R>, + next: Option>, + func: &'static HandlerFunc, } -impl<'a, 'b, T, R> BasicHandler<'b, T, R> +impl BasicHandler where - T: Send + Sync + 'b, - R: Send + Sync + 'b, + Self: Sync + Sized, { pub fn new( - req: Request, params: Params, - next: Option<&'b BasicHandler<'b, T, R>>, - func: &'static HandlerFunc<'b, T, R>, + next: Option>, + func: &'static HandlerFunc, ) -> Self { - Self { - req: Arc::new(Mutex::new(req)), - params, - next, - func, - } + Self { params, next, func } } } #[async_trait] -impl<'a, 'b, T, R> Handler<'a, 'b, T, R> for BasicHandler<'b, T, R> +impl Handler for BasicHandler where - Self: Send + Sync + 'b, - R: Copy + Send + Sync + Sized + 'static, - T: Copy + Send + Sync + Sized + 'static, + Self: Sync + Sized, { - async fn perform(&'b self, response: Option<&'a Response>) -> HTTPResult<'a, T, R> { - let mut req = self.req.lock().await; - - let (req, response) = (*self.func)(&mut req, self.params, response)?; + async fn perform( + &self, + req: Request, + response: Option>, + ) -> HTTPResult { + let (req, response) = (*self.func)(req, self.params.clone(), response)?; if self.next.is_some() { - return Ok(self.next.unwrap().perform(response).await?); + return Ok(self.next.clone().unwrap().perform(req, response).await?); } Ok((req, response)) @@ -72,44 +67,76 @@ mod tests { use http::{HeaderValue, Request, Response, StatusCode}; use hyper::Body; - fn one<'a>( - mut req: &'a Request, + // this method adds a header: + // wakka: wakka wakka + // to the request. that's it! + #[allow(dead_code)] + fn one( + mut req: Request, _params: Params, - _response: Option<&'a Response>, - ) -> HTTPResult<'a, Body, Body> { + _response: Option>, + ) -> HTTPResult { let headers = req.headers_mut(); headers.insert("wakka", HeaderValue::from_str("wakka wakka").unwrap()); - Ok((&req, None)) + Ok((req, None)) } - fn two<'a>( - mut req: &'a Request, + // this method returns an OK status when the wakka header exists. + #[allow(dead_code)] + fn two( + req: Request, _params: Params, - response: Option<&'a Response>, - ) -> HTTPResult<'a, Body, Body> { + mut response: Option>, + ) -> HTTPResult { if let Some(header) = req.headers().get("wakka") { if header != "wakka wakka" { return Err(Error::new("invalid header value")); } if response.is_some() { - return Ok((&req, response)); + return Ok((req, response)); } else { - response.replace( - &Response::builder() - .status(StatusCode::OK) - .body(Body::default())?, - ); + let resp = Response::builder() + .status(StatusCode::OK) + .body(Body::default())?; + response.replace(resp); - return Ok((&req, response)); + return Ok((req, response)); } } Err(Error::default()) } - #[test] - fn test_handler_basic() { - let bh = super::BasicHandler::new(Request::default(), Params::default(), None, &one); + // orchestration!!!! + #[tokio::test] + async fn test_handler_basic() { + use super::Handler; + use std::sync::Arc; + + // single stage handler that never yields a response + let bh = super::BasicHandler::new(Params::default(), None, &one); + let req = Request::default(); + let (req, response) = bh.perform(req, None).await.unwrap(); + if !req.headers().get("wakka").is_some() { + panic!("no wakkas") + } + + if response.is_some() { + panic!("response should be none at this point") + } + + // two-stage handler; yields a response if the first one was good. + let bh_two = super::BasicHandler::new(Params::default(), None, &two); + let bh = super::BasicHandler::new(Params::default(), Some(Arc::new(bh_two.clone())), &one); + let (_, response) = bh.perform(req, None).await.unwrap(); + + if !(response.is_some() && response.unwrap().status() == StatusCode::OK) { + panic!("response not ok") + } + + if !bh_two.perform(Request::default(), None).await.is_err() { + panic!("no error") + } } } diff --git a/src/lib.rs b/src/lib.rs index 5c71049..77c85be 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,9 +39,9 @@ impl From for Error { } } -pub type HTTPResult<'a, Req, Resp> = Result<(&'a Request, Option<&'a Response>), Error>; +pub type HTTPResult = Result<(Request, Option>), Error>; -pub struct App<'a> { +pub struct App { #[allow(dead_code)] // FIXME remove - routes: BTreeMap>, + routes: Vec<&'static BasicHandler>, }