use super::{PartialPathMatch, PathSegment, PossibleRouteMatch};
macro_rules! tuples {
($first:ident => $($ty:ident),*) => {
impl<$first, $($ty),*> PossibleRouteMatch for ($first, $($ty,)*)
where
$first: PossibleRouteMatch,
$($ty: PossibleRouteMatch),*,
{
fn optional(&self) -> bool {
#[allow(non_snake_case)]
let ($first, $($ty,)*) = &self;
[$first.optional(), $($ty.optional()),*].into_iter().any(|n| n)
}
fn test<'a>(&self, path: &'a str) -> Option<PartialPathMatch<'a>> {
#[allow(non_snake_case)]
let ($first, $($ty,)*) = &self;
let mut include_optionals = {
[$first.optional(), $($ty.optional()),*].into_iter().filter(|n| *n).count()
};
loop {
let mut nth_field = 0;
let mut matched_len = 0;
let mut r = path;
let mut p = Vec::new();
let mut m = String::new();
if $first.optional() {
nth_field += 1;
}
if !$first.optional() || nth_field <= include_optionals {
match $first.test(r) {
None => {
return None;
},
Some(PartialPathMatch { remaining, matched, params }) => {
p.extend(params.into_iter());
m.push_str(matched);
r = remaining;
},
}
}
matched_len += m.len();
$(
if $ty.optional() {
nth_field += 1;
}
if !$ty.optional() || nth_field <= include_optionals {
let PartialPathMatch {
remaining,
matched,
params
} = match $ty.test(r) {
None => if $ty.optional() {
return None;
} else {
if include_optionals == 0 {
return None;
}
include_optionals -= 1;
continue;
},
Some(v) => v,
};
r = remaining;
matched_len += matched.len();
p.extend(params);
}
)*
return Some(PartialPathMatch {
remaining: r,
matched: &path[0..matched_len],
params: p
});
}
}
fn generate_path(&self, path: &mut Vec<PathSegment>) {
#[allow(non_snake_case)]
let ($first, $($ty,)*) = &self;
$first.generate_path(path);
$(
$ty.generate_path(path);
)*
}
}
};
}
impl<A> PossibleRouteMatch for (A,)
where
Self: core::fmt::Debug,
A: PossibleRouteMatch,
{
fn optional(&self) -> bool {
self.0.optional()
}
fn test<'a>(&self, path: &'a str) -> Option<PartialPathMatch<'a>> {
let remaining = path;
let PartialPathMatch {
remaining,
matched,
params,
} = self.0.test(remaining)?;
Some(PartialPathMatch {
remaining,
matched: &path[0..matched.len()],
params,
})
}
fn generate_path(&self, path: &mut Vec<PathSegment>) {
self.0.generate_path(path);
}
}
tuples!(A => B);
tuples!(A => B, C);
tuples!(A => B, C, D);
tuples!(A => B, C, D, E);
tuples!(A => B, C, D, E, F);
tuples!(A => B, C, D, E, F, G);
tuples!(A => B, C, D, E, F, G, H);
tuples!(A => B, C, D, E, F, G, H, I);
tuples!(A => B, C, D, E, F, G, H, I, J);
tuples!(A => B, C, D, E, F, G, H, I, J, K);
tuples!(A => B, C, D, E, F, G, H, I, J, K, L);
tuples!(A => B, C, D, E, F, G, H, I, J, K, L, M);
tuples!(A => B, C, D, E, F, G, H, I, J, K, L, M, N);
tuples!(A => B, C, D, E, F, G, H, I, J, K, L, M, N, O);
tuples!(A => B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
tuples!(A => B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q);
tuples!(A => B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R);
tuples!(A => B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S);
tuples!(A => B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T);
tuples!(A => B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U);
tuples!(A => B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V);
tuples!(A => B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W);
tuples!(A => B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X);