Skip to content

Commit

Permalink
feat(macros): allow hinting the server data type in middleware macro
Browse files Browse the repository at this point in the history
This can sometimes be required when using some middleware which are
predicated on the datatype of the Server. An alternative would be to
litter the handler with extra type annotations (which is awkward without
type ascription), or to use explicit type-annotated functions as middleware.

Example usage:
```
middleware! { |res| <ServerData>
   // res is of type Response<ServerData>
}
```
  • Loading branch information
Ryman committed Aug 1, 2015
1 parent 4fb224d commit edea3ab
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 1 deletion.
2 changes: 1 addition & 1 deletion examples/session_example.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ fn main() {
(StatusCode::BadRequest, "Access denied.")
});

server.get("/secret", middleware! { |mut res|
server.get("/secret", middleware! { |mut res| <ServerData>
match *res.session() {
Some(ref user) if user == "foo" => (StatusCode::Ok, "Some hidden information!"),
_ => (StatusCode::Forbidden, "Access denied.")
Expand Down
40 changes: 40 additions & 0 deletions src/macros/middleware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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| <MyServerData>
/// // _response is of type Response<MyServerData>
/// "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)+) };
Expand All @@ -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) -> 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};

Expand Down

0 comments on commit edea3ab

Please sign in to comment.