diff --git a/examples/session_example.rs b/examples/session_example.rs index 891c720323..c0b783cfcc 100644 --- a/examples/session_example.rs +++ b/examples/session_example.rs @@ -45,7 +45,7 @@ fn main() { (StatusCode::BadRequest, "Access denied.") }); - server.get("/secret", middleware! { |mut res| + server.get("/secret", middleware! { |mut res| match *res.session() { Some(ref user) if user == "foo" => (StatusCode::Ok, "Some hidden information!"), _ => (StatusCode::Forbidden, "Access denied.") diff --git a/src/macros/middleware.rs b/src/macros/middleware.rs index aaf924eeb3..8db1806e37 100644 --- a/src/macros/middleware.rs +++ b/src/macros/middleware.rs @@ -23,8 +23,27 @@ /// server.listen("127.0.0.1:6767"); /// # } /// ``` +/// +/// # Type hinting +/// Sometimes type inference is unable to determine the datatype for the server, +/// which can lead to a lot of extra type annotations. The `middleware!` macro +/// supports annotating the macro so as to drive the inference allowing the handler +/// code to remain with minimal annotations. +/// +/// ``` +/// # #[macro_use] extern crate nickel; +/// # fn main() { +/// # struct MyServerData; +/// middleware! { |_response| +/// // _response is of type Response +/// "Hello World" +/// } +/// # ; // This semicolon is required to satisfy returning `()` +/// # } +/// ``` #[macro_export] macro_rules! middleware { + (|mut $res:ident| <$data:path> $($b:tt)+) => { _middleware_inner!($res, mut $res, <$data> $($b)+) }; (|mut $res:ident| $($b:tt)+) => { _middleware_inner!($res, mut $res, $($b)+) }; (|$res:ident| $($b:tt)+) => { _middleware_inner!($res, $res, $($b)+) }; ($($b:tt)+) => { _middleware_inner!(_res, _res, $($b)+) }; @@ -33,6 +52,27 @@ macro_rules! middleware { #[doc(hidden)] #[macro_export] macro_rules! _middleware_inner { + ($res:ident, $res_binding:pat, <$data:path> $($b:tt)+) => {{ + use $crate::{MiddlewareResult,Responder, Response}; + + #[inline(always)] + fn restrict<'a, 'k, R: Responder<$data>>(r: R, res: Response<'a, 'k, $data>) + -> MiddlewareResult<'a, 'k, $data> { + res.send(r) + } + + // Inference fails due to thinking it's a (&Request, Response) with + // different mutability requirements + #[inline(always)] + fn restrict_closure(f: F) -> F + where F: for<'a, 'k> + Fn(Response<'a, 'k, $data>) + -> MiddlewareResult<'a, 'k, $data> + Send + Sync { f } + + restrict_closure(move |$res_binding| { + restrict(as_block!({$($b)+}), $res) + }) + }}; ($res:ident, $res_binding:pat, $($b:tt)+) => {{ use $crate::{MiddlewareResult,Responder, Response};