From 692b7e54d8c4403ae5bc2e46211a51f2c4b95186 Mon Sep 17 00:00:00 2001 From: Erik Hollensbe Date: Sat, 22 Jan 2022 15:45:46 -0800 Subject: [PATCH] The great transient state patch. Tests forthcoming. Signed-off-by: Erik Hollensbe --- examples/auth-with-state.rs | 13 ++-- examples/disk-auth.rs | 13 ++-- examples/hello-world.rs | 6 +- examples/log.rs | 13 ++-- src/app.rs | 26 ++++---- src/handler.rs | 80 +++++++++++++---------- src/lib.rs | 33 +++++++++- src/macros.rs | 52 ++++++++++----- src/router.rs | 122 ++++++++++++++++++++++++------------ 9 files changed, 237 insertions(+), 121 deletions(-) diff --git a/examples/auth-with-state.rs b/examples/auth-with-state.rs index 73f8340..85ed7e7 100644 --- a/examples/auth-with-state.rs +++ b/examples/auth-with-state.rs @@ -4,8 +4,9 @@ async fn validate_authtoken( req: Request, resp: Option>, _params: Params, - app: App, -) -> HTTPResult { + app: App, + _state: NoState, +) -> HTTPResult { let token = req.headers().get("X-AuthToken"); if token.is_none() { return Err(Error::StatusCode(StatusCode::UNAUTHORIZED)); @@ -24,21 +25,23 @@ async fn validate_authtoken( return Err(Error::StatusCode(StatusCode::UNAUTHORIZED)); } - return Ok((req, resp)); + return Ok((req, resp, NoState {})); } async fn hello( req: Request, _resp: Option>, params: Params, - _app: App, -) -> HTTPResult { + _app: App, + _state: NoState, +) -> HTTPResult { let name = params.get("name").unwrap(); let bytes = Body::from(format!("hello, {}!\n", name)); return Ok(( req, Some(Response::builder().status(200).body(bytes).unwrap()), + NoState {}, )); } diff --git a/examples/disk-auth.rs b/examples/disk-auth.rs index 17794c0..26d478a 100644 --- a/examples/disk-auth.rs +++ b/examples/disk-auth.rs @@ -7,8 +7,9 @@ async fn validate_authtoken( req: Request, resp: Option>, _params: Params, - _app: App<()>, -) -> HTTPResult { + _app: App<(), NoState>, + _state: NoState, +) -> HTTPResult { let token = req.headers().get("X-AuthToken"); if token.is_none() { return Err(Error::StatusCode(StatusCode::UNAUTHORIZED)); @@ -28,21 +29,23 @@ async fn validate_authtoken( return Err(Error::StatusCode(StatusCode::UNAUTHORIZED)); } - return Ok((req, resp)); + return Ok((req, resp, NoState {})); } async fn hello( req: Request, _resp: Option>, params: Params, - _app: App<()>, -) -> HTTPResult { + _app: App<(), NoState>, + _state: NoState, +) -> HTTPResult { let name = params.get("name").unwrap(); let bytes = Body::from(format!("hello, {}!\n", name)); return Ok(( req, Some(Response::builder().status(200).body(bytes).unwrap()), + NoState {}, )); } diff --git a/examples/hello-world.rs b/examples/hello-world.rs index 7bc7f59..79fedab 100644 --- a/examples/hello-world.rs +++ b/examples/hello-world.rs @@ -4,14 +4,16 @@ async fn hello( req: Request, _resp: Option>, params: Params, - _app: App<()>, -) -> HTTPResult { + _app: App<(), NoState>, + _state: NoState, +) -> HTTPResult { let name = params.get("name").unwrap(); let bytes = Body::from(format!("hello, {}!\n", name)); return Ok(( req, Some(Response::builder().status(200).body(bytes).unwrap()), + NoState {}, )); } diff --git a/examples/log.rs b/examples/log.rs index b8d9256..5f1c69b 100644 --- a/examples/log.rs +++ b/examples/log.rs @@ -5,18 +5,20 @@ async fn log( req: Request, resp: Option>, _params: Params, - _app: App<()>, -) -> HTTPResult { + _app: App<(), NoState>, + _state: NoState, +) -> HTTPResult { log::trace!("New request: {}", req.uri().path()); - Ok((req, resp)) + Ok((req, resp, NoState {})) } async fn hello( req: Request, _resp: Option>, params: Params, - _app: App<()>, -) -> HTTPResult { + _app: App<(), NoState>, + _state: NoState, +) -> HTTPResult { let name = params.get("name").unwrap(); log::info!("Saying hello to {}", name); let bytes = Body::from(format!("hello, {}!\n", name)); @@ -24,6 +26,7 @@ async fn hello( return Ok(( req, Some(Response::builder().status(200).body(bytes).unwrap()), + NoState, )); } diff --git a/src/app.rs b/src/app.rs index ddfc3da..41705ae 100644 --- a/src/app.rs +++ b/src/app.rs @@ -4,7 +4,7 @@ use http::{Method, Request, Response, StatusCode}; use hyper::{server::conn::Http, service::service_fn, Body}; use tokio::{net::TcpListener, sync::Mutex}; -use crate::{handler::Handler, router::Router, Error, ServerError}; +use crate::{handler::Handler, router::Router, Error, ServerError, TransientState}; /// App is used to define application-level functionality and initialize the server. Routes are /// typically programmed here. @@ -49,12 +49,12 @@ use crate::{handler::Handler, router::Router, Error, ServerError}; /// /// Requests are routed through paths to [crate::handler::HandlerFunc]s. #[derive(Clone)] -pub struct App { - router: Router, +pub struct App { + router: Router, global_state: Option>>, } -impl App { +impl App { /// Construct a new App with no state; it will be passed to handlers as `App<()>`. pub fn new() -> Self { Self { @@ -84,55 +84,55 @@ impl App { /// Create a route for a GET request. See App's docs and [crate::handler::Handler] for /// more information. - pub fn get(&mut self, path: &str, ch: Handler) { + pub fn get(&mut self, path: &str, ch: Handler) { self.router.add(Method::GET, path.to_string(), ch); } /// Create a route for a POST request. See App's docs and [crate::handler::Handler] for /// more information. - pub fn post(&mut self, path: &str, ch: Handler) { + pub fn post(&mut self, path: &str, ch: Handler) { self.router.add(Method::POST, path.to_string(), ch); } /// Create a route for a DELETE request. See App's docs and [crate::handler::Handler] for /// more information. - pub fn delete(&mut self, path: &str, ch: Handler) { + pub fn delete(&mut self, path: &str, ch: Handler) { self.router.add(Method::DELETE, path.to_string(), ch); } /// Create a route for a PUT request. See App's docs and [crate::handler::Handler] for /// more information. - pub fn put(&mut self, path: &str, ch: Handler) { + pub fn put(&mut self, path: &str, ch: Handler) { self.router.add(Method::PUT, path.to_string(), ch); } /// Create a route for an OPTIONS request. See App's docs and /// [crate::handler::Handler] for more information. - pub fn options(&mut self, path: &str, ch: Handler) { + pub fn options(&mut self, path: &str, ch: Handler) { self.router.add(Method::OPTIONS, path.to_string(), ch); } /// Create a route for a PATCH request. See App's docs and /// [crate::handler::Handler] for more information. - pub fn patch(&mut self, path: &str, ch: Handler) { + pub fn patch(&mut self, path: &str, ch: Handler) { self.router.add(Method::PATCH, path.to_string(), ch); } /// Create a route for a HEAD request. See App's docs and /// [crate::handler::Handler] for more information. - pub fn head(&mut self, path: &str, ch: Handler) { + pub fn head(&mut self, path: &str, ch: Handler) { self.router.add(Method::HEAD, path.to_string(), ch); } /// Create a route for a CONNECT request. See App's docs and /// [crate::handler::Handler] for more information. - pub fn connect(&mut self, path: &str, ch: Handler) { + pub fn connect(&mut self, path: &str, ch: Handler) { self.router.add(Method::CONNECT, path.to_string(), ch); } /// Create a route for a TRACE request. See App's docs and /// [crate::handler::Handler] for more information. - pub fn trace(&mut self, path: &str, ch: Handler) { + pub fn trace(&mut self, path: &str, ch: Handler) { self.router.add(Method::TRACE, path.to_string(), ch); } diff --git a/src/handler.rs b/src/handler.rs index bde4a8f..088598e 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -1,6 +1,6 @@ use std::future::Future; -use crate::{app::App, HTTPResult, PinBox}; +use crate::{app::App, HTTPResult, PinBox, TransientState}; use async_recursion::async_recursion; use http::{Request, Response}; @@ -18,43 +18,46 @@ use hyper::Body; /// req: Request, /// _resp: Option>, /// params: Params, -/// _app: App<()>, -/// ) -> HTTPResult { +/// _app: App<(), NoState>, +/// _state: NoState, +/// ) -> HTTPResult { /// let name = params.get("name").unwrap(); /// let bytes = Body::from(format!("hello, {}!\n", name)); /// /// return Ok(( /// req, /// Some(Response::builder().status(200).body(bytes).unwrap()), +/// NoState{}, /// )); /// } /// ``` /// -pub type HandlerFunc = fn( +pub type HandlerFunc = fn( req: Request, response: Option>, params: crate::Params, - app: App, -) -> PinBox + Send>; + app: App, + state: T, +) -> PinBox> + Send>; /// Handler is the structure of the handler. Typically, you will not use this directly, and instead /// interact with the [crate::compose_handler!] macro. That said, if you wanted to define your own /// macros or otherwise compose more complicated structures for your handlers, this is available to /// you. #[derive(Clone)] -pub struct Handler { - handler: HandlerFunc, - next: Box>>, +pub struct Handler { + handler: HandlerFunc, + next: Box>>, } -impl Handler +impl Handler where Self: Send, S: Clone + Send, { /// Construct a new handler composed of a HandlerFunc with state, and an optional next handler /// in the chain. - pub fn new(handler: HandlerFunc, next: Option>) -> Self { + pub fn new(handler: HandlerFunc, next: Option>) -> Self { Self { handler, next: Box::new(next), @@ -68,30 +71,35 @@ where req: Request, response: Option>, params: crate::Params, - app: App, - ) -> HTTPResult { - let (req, response) = (self.handler)(req, response, params.clone(), app.clone()).await?; + app: App, + state: T, + ) -> HTTPResult { + let (req, response, state) = + (self.handler)(req, response, params.clone(), app.clone(), state).await?; if self.next.is_some() { return Ok((*self.clone().next) .unwrap() - .perform(req, response, params, app) + .perform(req, response, params, app, state) .await?); } - Ok((req, response)) + Ok((req, response, state)) } } mod tests { #[tokio::test] async fn test_handler_basic() { - use crate::{app::App, Error, HTTPResult, Params}; + use crate::{app::App, Error, HTTPResult, NoState, Params}; use http::{HeaderValue, Request, Response, StatusCode}; use hyper::Body; #[derive(Clone)] struct State; + #[derive(Clone)] + struct TransientState; + // this method adds a header: // wakka: wakka wakka // to the request. that's it! @@ -99,11 +107,12 @@ mod tests { mut req: Request, _response: Option>, _params: Params, - _app: App, - ) -> HTTPResult { + _app: App, + _state: NoState, + ) -> HTTPResult { let headers = req.headers_mut(); headers.insert("wakka", HeaderValue::from_str("wakka wakka").unwrap()); - Ok((req, None)) + Ok((req, None, NoState {})) } // this method returns an OK status when the wakka header exists. @@ -111,22 +120,23 @@ mod tests { req: Request, mut response: Option>, _params: Params, - _app: App, - ) -> HTTPResult { + _app: App, + _state: NoState, + ) -> 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, NoState {})); } else { let resp = Response::builder() .status(StatusCode::OK) .body(Body::default())?; response.replace(resp); - return Ok((req, response)); + return Ok((req, response, NoState {})); } } @@ -135,12 +145,12 @@ mod tests { // single stage handler that never yields a response let bh = super::Handler::new( - |req, resp, params, app| Box::pin(one(req, resp, params, app)), + |req, resp, params, app, state| Box::pin(one(req, resp, params, app, state)), None, ); let req = Request::default(); - let (req, response) = bh - .perform(req, None, Params::new(), App::new()) + let (req, response, _) = bh + .perform(req, None, Params::new(), App::new(), NoState {}) .await .unwrap(); @@ -149,22 +159,28 @@ mod tests { // two-stage handler; yields a response if the first one was good. let bh_two = super::Handler::new( - |req, resp, params, app| Box::pin(two(req, resp, params, app)), + |req, resp, params, app, state| Box::pin(two(req, resp, params, app, state)), None, ); let bh = super::Handler::new( - |req, resp, params, app| Box::pin(one(req, resp, params, app)), + |req, resp, params, app, state| Box::pin(one(req, resp, params, app, state)), Some(bh_two.clone()), ); - let (_, response) = bh - .perform(req, None, Params::new(), App::new()) + let (_, response, _) = bh + .perform(req, None, Params::new(), App::new(), NoState {}) .await .unwrap(); assert!(response.is_some() && response.unwrap().status() == StatusCode::OK); assert!(bh_two - .perform(Request::default(), None, Params::new(), App::new()) + .perform( + Request::default(), + None, + Params::new(), + App::new(), + NoState {} + ) .await .is_err()); diff --git a/src/lib.rs b/src/lib.rs index 9c8fc66..bca3bc4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -74,7 +74,34 @@ where /// returned. If you wish to return Err(), a [http::StatusCode] or [std::string::String] can be /// returned, the former is resolved to its status with an empty body, and the latter corresponds /// to a 500 Internal Server Error with the body set to the string. -pub type HTTPResult = Result<(Request, Option>), Error>; +pub type HTTPResult = Result< + ( + Request, + Option>, + TransientState, + ), + Error, +>; + +/// TransientState must be implemented to use state between handlers. +pub trait TransientState +where + Self: Clone + Send, +{ + /// initial prescribes an initial state for the trait, allowing it to be constructed at + /// dispatch time. + fn initial() -> Self; +} + +/// NoState is an empty [crate::TransientState]. +#[derive(Clone)] +pub struct NoState; + +impl TransientState for NoState { + fn initial() -> Self { + Self {} + } +} /// A convenience import to gather all of `ratpack`'s dependencies in one easy place. /// To use: @@ -83,7 +110,9 @@ pub type HTTPResult = Result<(Request, Option /// use ratpack::prelude::*; /// ``` pub mod prelude { - pub use crate::{app::App, compose_handler, Error, HTTPResult, Params, ServerError}; + pub use crate::{ + app::App, compose_handler, Error, HTTPResult, NoState, Params, ServerError, TransientState, + }; pub use http::{Request, Response, StatusCode}; pub use hyper::Body; } diff --git a/src/macros.rs b/src/macros.rs index 1f19c01..a16bf08 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -10,10 +10,10 @@ macro_rules! compose_handler { { use $crate::handler::{HandlerFunc, Handler}; { - let mut funcs: Vec> = Vec::new(); + let mut funcs: Vec> = Vec::new(); $( - funcs.push(|req, resp, params, app| Box::pin($x(req, resp, params, app))); + funcs.push(|req, resp, params, app, state| Box::pin($x(req, resp, params, app, state))); )* if funcs.len() == 0 { @@ -22,7 +22,7 @@ macro_rules! compose_handler { let mut handlers = Vec::new(); - let mut last: Option> = None; + let mut last: Option> = None; funcs.reverse(); for func in funcs { @@ -42,7 +42,7 @@ mod tests { use http::{HeaderValue, Request, Response, StatusCode}; use hyper::Body; - use crate::{app::App, Error, HTTPResult, Params}; + use crate::{app::App, Error, HTTPResult, NoState, Params}; #[derive(Clone)] struct State; @@ -54,11 +54,12 @@ mod tests { mut req: Request, _response: Option>, _params: Params, - _app: App, - ) -> HTTPResult { + _app: App, + _state: NoState, + ) -> HTTPResult { let headers = req.headers_mut(); headers.insert("wakka", HeaderValue::from_str("wakka wakka").unwrap()); - Ok((req, None)) + Ok((req, None, NoState {})) } // this method returns an OK status when the wakka header exists. @@ -66,22 +67,23 @@ mod tests { req: Request, mut response: Option>, _params: Params, - _app: App, - ) -> HTTPResult { + _app: App, + _state: NoState, + ) -> 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, NoState {})); } else { let resp = Response::builder() .status(StatusCode::OK) .body(Body::default())?; response.replace(resp); - return Ok((req, response)); + return Ok((req, response, NoState {})); } } @@ -90,8 +92,14 @@ mod tests { let handler = compose_handler!(one, two); - let (req, response) = handler - .perform(Request::default(), None, Params::new(), App::new()) + let (req, response, _) = handler + .perform( + Request::default(), + None, + Params::new(), + App::new(), + NoState {}, + ) .await .unwrap(); @@ -100,8 +108,14 @@ mod tests { let handler = compose_handler!(one); - let (req, response) = handler - .perform(Request::default(), None, Params::new(), App::new()) + let (req, response, _) = handler + .perform( + Request::default(), + None, + Params::new(), + App::new(), + NoState {}, + ) .await .unwrap(); @@ -111,7 +125,13 @@ mod tests { let handler = compose_handler!(two); assert!(handler - .perform(Request::default(), None, Params::new(), App::new()) + .perform( + Request::default(), + None, + Params::new(), + App::new(), + NoState {} + ) .await .is_err()); } diff --git a/src/router.rs b/src/router.rs index 033d264..6d2812f 100644 --- a/src/router.rs +++ b/src/router.rs @@ -1,30 +1,30 @@ use http::{Request, Response}; use hyper::Body; -use crate::{app::App, handler::Handler, path::Path, Error, HTTPResult}; +use crate::{app::App, handler::Handler, path::Path, Error, HTTPResult, TransientState}; #[derive(Clone)] -pub(crate) struct Route { +pub(crate) struct Route { method: http::Method, path: Path, - handler: Handler, + handler: Handler, } -impl PartialEq for Route { +impl PartialEq for Route { fn eq(&self, other: &Self) -> bool { self.method.to_string() == other.method.to_string() && self.path.eq(&other.path) } } -impl Eq for Route {} +impl Eq for Route {} -impl PartialOrd for Route { +impl PartialOrd for Route { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl Ord for Route { +impl Ord for Route { fn cmp(&self, other: &Self) -> std::cmp::Ordering { let left = self.method.to_string() + " " + &self.path.to_string(); let right = other.method.to_string() + " " + &other.path.to_string(); @@ -33,8 +33,8 @@ impl Ord for Route { } } -impl Route { - fn new(method: http::Method, path: String, handler: Handler) -> Self { +impl Route { + fn new(method: http::Method, path: String, handler: Handler) -> Self { Self { method, handler, @@ -46,27 +46,28 @@ impl Route { &self, provided: String, req: Request, - app: App, - ) -> HTTPResult { + app: App, + state: T, + ) -> HTTPResult { let params = self.path.extract(provided)?; if self.method != req.method() { return Err(Error::StatusCode(http::StatusCode::NOT_FOUND)); } - self.handler.perform(req, None, params, app).await + self.handler.perform(req, None, params, app, state).await } } #[derive(Clone)] -pub(crate) struct Router(Vec>); +pub(crate) struct Router(Vec>); -impl Router { +impl Router { pub fn new() -> Self { Self(Vec::new()) } - pub(crate) fn add(&mut self, method: http::Method, path: String, ch: Handler) -> Self { + pub(crate) fn add(&mut self, method: http::Method, path: String, ch: Handler) -> Self { self.0.push(Route::new(method, path, ch)); self.clone() } @@ -74,13 +75,15 @@ impl Router { pub(crate) async fn dispatch( &self, req: Request, - app: App, + app: App, ) -> Result, Error> { let path = req.uri().path().to_string(); for route in self.0.clone() { if route.path.matches(path.to_string()) && route.method.eq(req.method()) { - let (_, response) = route.dispatch(path.to_string(), req, app).await?; + let (_, response, _) = route + .dispatch(path.to_string(), req, app, T::initial()) + .await?; if response.is_none() { return Err(Error::StatusCode(http::StatusCode::INTERNAL_SERVER_ERROR)); } @@ -94,13 +97,12 @@ impl Router { } mod tests { - #[tokio::test] async fn test_route_dynamic() { use http::{Method, Request, Response}; use hyper::Body; - use crate::{app::App, handler::Handler, HTTPResult, Params}; + use crate::{app::App, handler::Handler, HTTPResult, NoState, Params}; use super::Route; @@ -111,14 +113,16 @@ mod tests { req: Request, _response: Option>, params: Params, - _app: App, - ) -> HTTPResult { + _app: App, + _state: NoState, + ) -> HTTPResult { return Ok(( req, Some(Response::builder().status(400).body(Body::from(format!( "hello, {}", *params.get("name").unwrap() )))?), + NoState {}, )); } @@ -126,13 +130,15 @@ mod tests { Method::GET, "/a/:name/c".to_string(), Handler::new( - |req, resp, params, app| Box::pin(handler_dynamic(req, resp, params, app)), + |req, resp, params, app, state| { + Box::pin(handler_dynamic(req, resp, params, app, state)) + }, None, ), ); assert!(route - .dispatch("/a".to_string(), Request::default(), App::new()) + .dispatch("/a".to_string(), Request::default(), App::new(), NoState {}) .await .is_err()); assert!(route @@ -143,6 +149,7 @@ mod tests { .body(Body::from("one=two".as_bytes())) .unwrap(), App::new(), + NoState {}, ) .await .is_err()); @@ -151,7 +158,12 @@ mod tests { "erik", "adam", "sean", "travis", "joseph", "grant", "joy", "steve", "marc", ] { assert!(route - .dispatch("/a/:name/c".to_string(), Request::default(), App::new()) + .dispatch( + "/a/:name/c".to_string(), + Request::default(), + App::new(), + NoState {} + ) .await .is_ok()); @@ -159,7 +171,7 @@ mod tests { let body = hyper::body::to_bytes( route - .dispatch(path.clone(), Request::default(), App::new()) + .dispatch(path.clone(), Request::default(), App::new(), NoState {}) .await .unwrap() .1 @@ -172,7 +184,7 @@ mod tests { assert_eq!(body, format!("hello, {}", name).as_bytes()); let status = route - .dispatch(path, Request::default(), App::new()) + .dispatch(path, Request::default(), App::new(), NoState {}) .await .unwrap() .1 @@ -188,7 +200,7 @@ mod tests { use http::{Method, Request, Response}; use hyper::Body; - use crate::{app::App, handler::Handler, HTTPResult, Params}; + use crate::{app::App, handler::Handler, HTTPResult, NoState, Params}; use super::Route; @@ -199,8 +211,9 @@ mod tests { req: Request, _response: Option>, _params: Params, - _app: App, - ) -> HTTPResult { + _app: App, + _state: NoState, + ) -> HTTPResult { return Ok(( req, Some( @@ -208,6 +221,7 @@ mod tests { .status(400) .body(Body::from("hello, world".as_bytes()))?, ), + NoState {}, )); } @@ -215,13 +229,15 @@ mod tests { Method::GET, "/a/b/c".to_string(), Handler::new( - |req, resp, params, app| Box::pin(handler_static(req, resp, params, app)), + |req, resp, params, app, state| { + Box::pin(handler_static(req, resp, params, app, state)) + }, None, ), ); assert!(route - .dispatch("/a".to_string(), Request::default(), App::new()) + .dispatch("/a".to_string(), Request::default(), App::new(), NoState {}) .await .is_err()); assert!(route @@ -232,18 +248,29 @@ mod tests { .body(Body::from("one=two".as_bytes())) .unwrap(), App::new(), + NoState {}, ) .await .is_err()); assert!(route - .dispatch("/a/b/c".to_string(), Request::default(), App::new()) + .dispatch( + "/a/b/c".to_string(), + Request::default(), + App::new(), + NoState {} + ) .await .is_ok()); let body = hyper::body::to_bytes( route - .dispatch("/a/b/c".to_string(), Request::default(), App::new()) + .dispatch( + "/a/b/c".to_string(), + Request::default(), + App::new(), + NoState {}, + ) .await .unwrap() .1 @@ -256,7 +283,12 @@ mod tests { assert_eq!(body, "hello, world".as_bytes()); let status = route - .dispatch("/a/b/c".to_string(), Request::default(), App::new()) + .dispatch( + "/a/b/c".to_string(), + Request::default(), + App::new(), + NoState {}, + ) .await .unwrap() .1 @@ -269,7 +301,7 @@ mod tests { #[tokio::test] async fn test_router() { use super::Router; - use crate::{app::App, handler::Handler, HTTPResult, Params}; + use crate::{app::App, handler::Handler, HTTPResult, NoState, Params}; use http::{Method, Request, Response}; use hyper::Body; @@ -280,14 +312,16 @@ mod tests { req: Request, _response: Option>, params: Params, - _app: App, - ) -> HTTPResult { + _app: App, + _state: NoState, + ) -> HTTPResult { return Ok(( req, Some(Response::builder().status(400).body(Body::from(format!( "hello, {}", *params.get("name").unwrap() )))?), + NoState {}, )); } @@ -295,8 +329,9 @@ mod tests { req: Request, _response: Option>, _params: Params, - _app: App, - ) -> HTTPResult { + _app: App, + _state: NoState, + ) -> HTTPResult { return Ok(( req, Some( @@ -304,6 +339,7 @@ mod tests { .status(400) .body(Body::from("hello, world".as_bytes()))?, ), + NoState {}, )); } @@ -313,7 +349,9 @@ mod tests { Method::GET, "/a/b/c".to_string(), Handler::new( - |req, resp, params, app| Box::pin(handler_static(req, resp, params, app)), + |req, resp, params, app, state| { + Box::pin(handler_static(req, resp, params, app, state)) + }, None, ), ); @@ -322,7 +360,9 @@ mod tests { Method::GET, "/c/b/a/:name".to_string(), Handler::new( - |req, resp, params, app| Box::pin(handler_dynamic(req, resp, params, app)), + |req, resp, params, app, state| { + Box::pin(handler_dynamic(req, resp, params, app, state)) + }, None, ), );