From 852120e23a3d88fc25d229690b7a78c8fba4f5b2 Mon Sep 17 00:00:00 2001 From: Sergio Benitez Date: Thu, 17 Mar 2016 19:43:58 -0700 Subject: [PATCH] Forgot a file, it seems. --- lib/src/router.rs | 99 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 lib/src/router.rs diff --git a/lib/src/router.rs b/lib/src/router.rs new file mode 100644 index 00000000..33c03496 --- /dev/null +++ b/lib/src/router.rs @@ -0,0 +1,99 @@ +use method::Method; +use std::path::{Path, PathBuf, Component}; +use std::collections::hash_map::HashMap; + +pub struct Router { + paths: Vec // for now, to check for collisions +} + +fn is_variadic(c: &Component) -> bool { + match c { + &Component::Normal(ref comp) => comp.to_str().unwrap().starts_with("<"), + _ => false + } +} + +#[inline] +fn routes_collide(n: usize, a: &Path, b: &Path) -> bool { + let mut matches = 0; + + let mut a_components = a.components(); + let mut b_components = b.components(); + + while let Some(ref c1) = a_components.next() { + if let Some(ref c2) = b_components.next() { + if c1 == c2 { + matches += 1; + } else if is_variadic(c1) || is_variadic(c2) { + matches += 1; + } + } + } + + // println!("Checked {:?} against {:?}: {}/{}", a, b, matches, n); + matches == n +} + +// TODO: Are /hello and /hello/ the same? Or not? Currently, they're treated as +// such by Path, which is passed on to the collisions stuff. +impl Router { + pub fn new() -> Router { + Router { + paths: Vec::new() + } + } + + pub fn add_route(&mut self, method: Method, base: &str, route: &str) { + // Allocate enough space for the worst case. + let mut deduped = String::with_capacity(base.len() + route.len() + 1); + + let mut last = '\0'; + for c in base.chars().chain("/".chars()).chain(route.chars()) { + if !(last == '/' && c == '/') { + deduped.push(c); + } + + last = c; + } + + let mut path = PathBuf::from(deduped); + println!("Mounted: {:?}", path); + self.paths.push(path); + } + + pub fn has_collisions(&self) -> bool { + let mut map: HashMap> = HashMap::new(); + + for route in &self.paths { + let num_components = route.components().count(); + println!("Found {} for {:?}", num_components, route); + + let mut list = if map.contains_key(&num_components) { + map.get_mut(&num_components).unwrap() + } else { + map.insert(num_components, Vec::new()); + map.get_mut(&num_components).unwrap() + }; + + list.push(route.as_path()); + } + + let mut result = false; + for (num_components, routes) in map.iter() { + for i in 0..routes.len() { + for j in 0..routes.len() { + if i == j { continue } + + let a_route = &routes[i]; + let b_route = &routes[j]; + if routes_collide(*num_components, a_route, b_route) { + result = true; + println!("{:?} and {:?} collide!", a_route, b_route); + } + } + } + } + + result + } +}