#[macro_export]
macro_rules! router {
($request:expr, $(($method:ident) ($($pat:tt)+) => $value:block,)* _ => $def:expr) => {
{
let ref request = $request;
let request_url = request.url();
let request_url = {
let pos = request_url.find('?').unwrap_or(request_url.len());
&request_url[..pos]
};
let mut ret = None;
$({
if ret.is_none() && request.method() == stringify!($method) {
ret = router!(__check_pattern request_url $value $($pat)+);
}
})+
if let Some(ret) = ret {
ret
} else {
$def
}
}
};
(__check_pattern $url:ident $value:block /{$p:ident} $($rest:tt)*) => (
if !$url.starts_with('/') {
None
} else {
let url = &$url[1..];
let pat_end = url.find('/').unwrap_or(url.len());
let rest_url = &url[pat_end..];
if let Some($p) = url[0 .. pat_end].parse().ok() {
router!(__check_pattern rest_url $value $($rest)*)
} else {
None
}
}
);
(__check_pattern $url:ident $value:block /{$p:ident: $t:ty} $($rest:tt)*) => (
if !$url.starts_with('/') {
None
} else {
let url = &$url[1..];
let pat_end = url.find('/').unwrap_or(url.len());
let rest_url = &url[pat_end..];
if let Some($p) = url[0 .. pat_end].parse().ok() {
let $p: $t = $p;
router!(__check_pattern rest_url $value $($rest)*)
} else {
None
}
}
);
(__check_pattern $url:ident $value:block /$p:ident $($rest:tt)*) => (
{
let required = concat!("/", stringify!($p));
if $url.starts_with(required) {
let rest_url = &$url[required.len()..];
router!(__check_pattern rest_url $value $($rest)*)
} else {
None
}
}
);
(__check_pattern $url:ident $value:block - $($rest:tt)*) => (
{
if $url.starts_with('-') {
let rest_url = &$url[1..];
router!(__check_pattern rest_url $value $($rest)*)
} else {
None
}
}
);
(__check_pattern $url:ident $value:block) => (
if $url.len() == 0 { Some($value) } else { None }
);
(__check_pattern $url:ident $value:block /) => (
if $url == "/" { Some($value) } else { None }
);
(__check_pattern $url:ident $value:block $p:ident $($rest:tt)*) => (
{
let required = stringify!($p);
if $url.starts_with(required) {
let rest_url = &$url[required.len()..];
router!(__check_pattern rest_url $value $($rest)*)
} else {
None
}
}
);
}
#[cfg(test)]
mod tests {
use Request;
#[test]
fn basic() {
let request = Request::fake_http("GET", "/", vec![], vec![]);
assert_eq!(1, router!(request,
(GET) (/hello) => { 0 },
(GET) (/{val:u32}) => { 0 },
(GET) (/) => { 1 },
_ => 0
));
}
#[test]
fn dash() {
let request = Request::fake_http("GET", "/a-b", vec![], vec![]);
assert_eq!(1, router!(request,
(GET) (/a/b) => { 0 },
(GET) (/a_b) => { 0 },
(GET) (/a-b) => { 1 },
_ => 0
));
}
#[test]
fn params() {
let request = Request::fake_http("GET", "/hello/5", vec![], vec![]);
assert_eq!(1, router!(request,
(GET) (/hello/) => { 0 },
(GET) (/hello/{id:u32}) => { if id == 5 { 1 } else { 0 } },
(GET) (/hello/{id:String}) => { 0 },
_ => 0
));
}
#[test]
#[ignore] fn param_slash() {
let request = Request::fake_http("GET", "/hello%2F5", vec![], vec![]);
router!(request,
(GET) (/{a:String}) => { assert_eq!(a, "hello/5") },
_ => panic!()
);
}
}