use std::collections::HashMap;
use std::iter::{Iterator, FlatMap, Peekable};
use std::slice::Split;
use std::ops::Deref;
use std::marker::PhantomData;
use hyper::method::Method;
use handler::Handler;
use context::MaybeUtf8Owned;
use context::hypermedia::Link;
pub use self::tree_router::TreeRouter;
pub use self::method_router::MethodRouter;
pub use self::variables::Variables;
mod tree_router;
mod method_router;
mod variables;
pub struct Endpoint<'a, T: 'a> {
pub handler: Option<&'a T>,
pub variables: HashMap<MaybeUtf8Owned, MaybeUtf8Owned>,
pub hyperlinks: Vec<Link<'a>>
}
impl<'a, T> From<Option<&'a T>> for Endpoint<'a, T> {
fn from(handler: Option<&'a T>) -> Endpoint<'a, T> {
Endpoint {
handler: handler,
variables: HashMap::new(),
hyperlinks: vec![]
}
}
}
pub trait Router: Send + Sync + 'static {
type Handler: Handler;
fn build<'a, R: Into<InsertState<'a, I>>, I: Iterator<Item = &'a [u8]>>(method: Method, route: R, item: Self::Handler) -> Self;
fn insert<'a, R: Into<InsertState<'a, I>>, I: Iterator<Item = &'a [u8]>>(&mut self, method: Method, route: R, item: Self::Handler);
fn insert_router<'a, R: Into<InsertState<'a, I>>, I: Clone + Iterator<Item = &'a [u8]>>(&mut self, route: R, router: Self);
fn prefix<'a, R: Into<InsertState<'a, I>>, I: Clone + Iterator<Item = &'a [u8]>>(&mut self, route: R);
fn merge(&mut self, other: Self) where Self: Sized {
self.insert_router("", other);
}
fn find<'a>(&'a self, method: &Method, route: &mut RouteState) -> Endpoint<'a, Self::Handler>;
fn hyperlinks<'a>(&'a self, base: Link<'a>) -> Vec<Link<'a>>;
}
impl<H: Handler> Router for H {
type Handler = H;
fn build<'a, R: Into<InsertState<'a, I>>, I: Iterator<Item = &'a [u8]>>(_method: Method, _route: R, item: H) -> H {
item
}
fn insert<'a, R: Into<InsertState<'a, I>>, I: Iterator<Item = &'a [u8]>>(&mut self, _method: Method, _route: R, item: H) {
*self = item;
}
fn insert_router<'a, R: Into<InsertState<'a, I>>, I: Clone + Iterator<Item = &'a [u8]>>(&mut self, _route: R, router: H) {
*self = router;
}
fn prefix<'a, R: Into<InsertState<'a, I>>, I: Clone + Iterator<Item = &'a [u8]>>(&mut self, _route: R) {}
fn find<'a>(&'a self, _method: &Method, _route: &mut RouteState) -> Endpoint<'a, H> {
Some(self).into()
}
fn hyperlinks<'a>(&'a self, mut base: Link<'a>) -> Vec<Link<'a>> {
base.handler = Some(self);
vec![base]
}
}
impl<T: Router> Router for Option<T> {
type Handler = T::Handler;
fn build<'a, R: Into<InsertState<'a, I>>, I: Iterator<Item = &'a [u8]>>(method: Method, route: R, item: Self::Handler) -> Option<T> {
Some(T::build(method, route, item))
}
fn insert<'a, R: Into<InsertState<'a, I>>, I: Iterator<Item = &'a [u8]>>(&mut self, method: Method, route: R, item: Self::Handler) {
match *self {
Some(ref mut r) => r.insert(method, route, item),
ref mut s @ None => *s = Some(T::build(method, route, item)),
}
}
fn insert_router<'a, R: Into<InsertState<'a, I>>, I: Clone + Iterator<Item = &'a [u8]>>(&mut self, route: R, router: Option<T>) {
if let Some(mut other) = router {
match *self {
Some(ref mut r) => r.insert_router(route, other),
ref mut s @ None => {
other.prefix(route);
*s = Some(other)
}
}
}
}
fn prefix<'a, R: Into<InsertState<'a, I>>, I: Clone + Iterator<Item = &'a [u8]>>(&mut self, route: R) {
self.as_mut().map(|r| r.prefix(route));
}
fn find<'a>(&'a self, method: &Method, route: &mut RouteState) -> Endpoint<'a, Self::Handler> {
if let Some(ref router) = *self {
router.find(method, route)
} else {
None.into()
}
}
fn hyperlinks<'a>(&'a self, base: Link<'a>) -> Vec<Link<'a>> {
if let Some(ref router) = *self {
router.hyperlinks(base)
} else {
vec![]
}
}
}
pub trait Route<'a> {
type Segments: Iterator<Item=&'a [u8]>;
fn segments(&'a self) -> <Self as Route<'a>>::Segments;
}
fn is_slash(c: &u8) -> bool {
*c == b'/'
}
const IS_SLASH: &'static fn(&u8) -> bool = & (is_slash as fn(&u8) -> bool);
impl<'a> Route<'a> for str {
type Segments = RouteIter<Split<'a, u8, &'static fn(&u8) -> bool>>;
fn segments(&'a self) -> <Self as Route<'a>>::Segments {
self.as_bytes().segments()
}
}
impl<'a> Route<'a> for [u8] {
type Segments = RouteIter<Split<'a, u8, &'static fn(&u8) -> bool>>;
fn segments(&'a self) -> <Self as Route<'a>>::Segments {
let s = if self.starts_with(b"/") {
&self[1..]
} else {
self
};
let s = if s.ends_with(b"/") {
&s[..s.len() - 1]
} else {
s
};
if s.len() == 0 {
RouteIter::Root
} else {
RouteIter::Path(s.split(IS_SLASH))
}
}
}
impl<'a, 'b: 'a, I: 'a, T: 'a> Route<'a> for I where
&'a I: IntoIterator<Item=&'a T>,
T: Deref,
<T as Deref>::Target: Route<'a> + 'b
{
type Segments = FlatMap<<&'a I as IntoIterator>::IntoIter, <<T as Deref>::Target as Route<'a>>::Segments, fn(&'a T) -> <<T as Deref>::Target as Route<'a>>::Segments>;
fn segments(&'a self) -> Self::Segments {
fn segments<'a, 'b: 'a, T: Deref<Target=R> + 'b, R: ?Sized + Route<'a, Segments=S> + 'b, S: Iterator<Item=&'a[u8]>>(s: &'a T) -> S {
s.segments()
}
self.into_iter().flat_map(segments)
}
}
#[derive(Clone)]
pub enum RouteIter<I: Iterator> {
Root,
Path(I)
}
impl<I: Iterator> Iterator for RouteIter<I> {
type Item = <I as Iterator>::Item;
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
match *self {
RouteIter::Path(ref mut i) => i.next(),
RouteIter::Root => None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
match *self {
RouteIter::Path(ref i) => i.size_hint(),
RouteIter::Root => (0, Some(0))
}
}
}
#[derive(Clone)]
pub struct InsertState<'a, I: Iterator<Item=&'a [u8]>> {
route: Peekable<I>,
variables: Vec<MaybeUtf8Owned>,
_p: PhantomData<&'a [u8]>,
}
impl<'a, I: Iterator<Item=&'a [u8]>> InsertState<'a, I> {
pub fn variables(self) -> Vec<MaybeUtf8Owned> {
self.variables
}
pub fn is_empty(&mut self) -> bool {
self.route.peek().is_none()
}
}
impl<'a, I: Iterator<Item=&'a [u8]>> Iterator for InsertState<'a, I> {
type Item = &'a [u8];
fn next(&mut self) -> Option<&'a [u8]> {
self.route.next().map(|segment| {
match segment.get(0) {
Some(&b'*') | Some(&b':') => self.variables.push(segment[1..].to_owned().into()),
_ => {}
}
segment
})
}
}
impl<'a, R: Route<'a> + ?Sized> From<&'a R> for InsertState<'a, R::Segments> {
fn from(route: &'a R) -> InsertState<'a, R::Segments> {
InsertState {
route: route.segments().peekable(),
variables: vec![],
_p: PhantomData,
}
}
}
pub struct RouteState<'a> {
route: Vec<&'a [u8]>,
variables: Vec<Option<usize>>,
index: usize,
var_index: usize,
}
impl<'a> RouteState<'a> {
pub fn get(&self) -> Option<&'a [u8]> {
self.route.get(self.index).cloned()
}
pub fn skip(&mut self) {
self.variables.get_mut(self.index).map(|v| *v = None);
self.index += 1;
}
pub fn keep(&mut self) {
let v_i = self.var_index;
self.variables.get_mut(self.index).map(|v| *v = Some(v_i));
self.index += 1;
self.var_index += 1;
}
pub fn fuse(&mut self) {
let v_i = self.var_index;
self.variables.get_mut(self.index).map(|v| *v = Some(v_i));
self.index += 1;
}
pub fn variables(&self, names: &[MaybeUtf8Owned]) -> HashMap<MaybeUtf8Owned, MaybeUtf8Owned> {
let values = self.route.iter().zip(self.variables.iter()).filter_map(|(v, keep)| {
if let Some(index) = *keep {
Some((index, *v))
} else {
None
}
});
let mut var_map = HashMap::<MaybeUtf8Owned, MaybeUtf8Owned>::with_capacity(names.len());
for (name, value) in VariableIter::new(names, values) {
var_map.insert(name, value);
}
var_map
}
pub fn snapshot(&self) -> (usize, usize) {
(self.index, self.var_index)
}
pub fn go_to(&mut self, snapshot: (usize, usize)) {
let (index, var_index) = snapshot;
self.index = index;
self.var_index = var_index;
}
pub fn is_empty(&self) -> bool {
self.index == self.route.len()
}
}
impl<'a, R: Route<'a> + ?Sized> From<&'a R> for RouteState<'a> {
fn from(route: &'a R) -> RouteState<'a> {
let route: Vec<_> = route.segments().collect();
RouteState {
variables: vec![None; route.len()],
route: route,
index: 0,
var_index: 0,
}
}
}
struct VariableIter<'a, I> {
iter: I,
names: &'a [MaybeUtf8Owned],
current: Option<(usize, MaybeUtf8Owned, MaybeUtf8Owned)>
}
impl<'a, I: Iterator<Item=(usize, &'a [u8])>> VariableIter<'a, I> {
fn new(names: &'a [MaybeUtf8Owned], iter: I) -> VariableIter<'a, I> {
VariableIter {
iter: iter,
names: names,
current: None
}
}
}
impl<'a, I: Iterator<Item=(usize, &'a [u8])>> Iterator for VariableIter<'a, I> {
type Item=(MaybeUtf8Owned, MaybeUtf8Owned);
fn next(&mut self) -> Option<Self::Item> {
for (next_index, next_segment) in &mut self.iter {
debug_assert!(next_index < self.names.len(), format!("invalid variable name index! variable_names.len(): {}, index: {}", self.names.len(), next_index));
let next_name = match self.names.get(next_index) {
None => continue,
Some(n) if n.is_empty() => continue,
Some(n) => n
};
if let Some((index, name, mut segment)) = self.current.take() {
if index == next_index {
segment.push_char('/');
segment.push_bytes(next_segment);
self.current = Some((index, name, segment));
} else {
self.current = Some((next_index, (*next_name).clone(), next_segment.to_owned().into()));
return Some((name, segment));
}
} else {
self.current = Some((next_index, (*next_name).clone(), next_segment.to_owned().into()));
}
}
self.current.take().map(|(_, name, segment)| (name, segment))
}
}