1
0
mirror of https://github.com/fafhrd91/actix-net synced 2025-02-07 21:24:23 +01:00
actix-net/router/src/router.rs

237 lines
7.6 KiB
Rust
Raw Normal View History

2019-03-08 12:33:44 -08:00
use crate::{Resource, ResourceDef, ResourcePath};
2019-01-05 13:19:25 -08:00
#[derive(Debug, Copy, Clone, PartialEq)]
2019-03-08 12:33:44 -08:00
pub struct ResourceId(pub u16);
2019-01-05 13:19:25 -08:00
/// Information about current resource
#[derive(Clone, Debug)]
pub struct ResourceInfo {
resource: ResourceId,
}
/// Resource router.
2019-03-08 12:33:44 -08:00
pub struct Router<T, U = ()>(Vec<(ResourceDef, T, Option<U>)>);
2019-01-05 13:19:25 -08:00
impl<T, U> Router<T, U> {
pub fn build() -> RouterBuilder<T, U> {
2019-01-05 13:19:25 -08:00
RouterBuilder {
resources: Vec::new(),
}
}
2019-03-08 12:33:44 -08:00
pub fn recognize<R, P>(&self, path: &mut R) -> Option<(&T, ResourceId)>
where
R: Resource<P>,
P: ResourcePath,
{
for item in self.0.iter() {
if item.0.match_path(path.resource_path()) {
return Some((&item.1, ResourceId(item.0.id())));
2019-01-05 13:19:25 -08:00
}
}
None
}
2019-03-08 12:33:44 -08:00
pub fn recognize_mut<R, P>(&mut self, res: &mut R) -> Option<(&mut T, ResourceId)>
where
R: Resource<P>,
P: ResourcePath,
{
for item in self.0.iter_mut() {
if item.0.match_path(res.resource_path()) {
return Some((&mut item.1, ResourceId(item.0.id())));
}
}
None
}
2019-03-08 12:33:44 -08:00
pub fn recognize_mut_checked<R, P, F>(
&mut self,
res: &mut R,
check: F,
2019-03-08 12:33:44 -08:00
) -> Option<(&mut T, ResourceId)>
where
F: Fn(&R, &Option<U>) -> bool,
2019-03-08 12:33:44 -08:00
R: Resource<P>,
P: ResourcePath,
{
2019-03-08 12:33:44 -08:00
for item in self.0.iter_mut() {
if item.0.match_path(res.resource_path()) && check(res, &item.2) {
return Some((&mut item.1, ResourceId(item.0.id())));
2019-01-05 13:19:25 -08:00
}
}
None
}
}
2019-03-04 14:03:46 -08:00
pub struct RouterBuilder<T, U = ()> {
2019-03-08 12:33:44 -08:00
resources: Vec<(ResourceDef, T, Option<U>)>,
2019-01-05 13:19:25 -08:00
}
impl<T, U> RouterBuilder<T, U> {
/// Register resource for specified path.
2019-03-08 12:33:44 -08:00
pub fn path(&mut self, path: &str, resource: T) -> &mut (ResourceDef, T, Option<U>) {
self.resources
.push((ResourceDef::new(path), resource, None));
self.resources.last_mut().unwrap()
2019-01-05 13:19:25 -08:00
}
/// Register resource for specified path prefix.
2019-03-08 12:33:44 -08:00
pub fn prefix(&mut self, prefix: &str, resource: T) -> &mut (ResourceDef, T, Option<U>) {
self.resources
.push((ResourceDef::prefix(prefix), resource, None));
self.resources.last_mut().unwrap()
2019-01-05 13:19:25 -08:00
}
/// Register resource for ResourceDef
2019-03-08 12:33:44 -08:00
pub fn rdef(&mut self, rdef: ResourceDef, resource: T) -> &mut (ResourceDef, T, Option<U>) {
self.resources.push((rdef, resource, None));
self.resources.last_mut().unwrap()
}
/// Finish configuration and create router instance.
pub fn finish(self) -> Router<T, U> {
2019-03-08 12:33:44 -08:00
Router(self.resources)
2019-01-05 13:19:25 -08:00
}
}
#[cfg(test)]
mod tests {
use crate::path::Path;
use crate::router::{ResourceId, Router};
#[test]
fn test_recognizer_1() {
let mut router = Router::<usize>::build();
2019-03-08 12:33:44 -08:00
router.path("/name", 10).0.set_id(0);
router.path("/name/{val}", 11).0.set_id(1);
router.path("/name/{val}/index.html", 12).0.set_id(2);
router.path("/file/{file}.{ext}", 13).0.set_id(3);
router.path("/v{val}/{val2}/index.html", 14).0.set_id(4);
router.path("/v/{tail:.*}", 15).0.set_id(5);
router.path("/test2/{test}.html", 16).0.set_id(6);
router.path("/{test}/index.html", 17).0.set_id(7);
2019-01-05 13:19:25 -08:00
let mut router = router.finish();
let mut path = Path::new("/unknown");
assert!(router.recognize_mut(&mut path).is_none());
let mut path = Path::new("/name");
let (h, info) = router.recognize_mut(&mut path).unwrap();
assert_eq!(*h, 10);
2019-03-08 12:33:44 -08:00
assert_eq!(info, ResourceId(0));
2019-01-05 13:19:25 -08:00
assert!(path.is_empty());
let mut path = Path::new("/name/value");
let (h, info) = router.recognize_mut(&mut path).unwrap();
assert_eq!(*h, 11);
2019-03-08 12:33:44 -08:00
assert_eq!(info, ResourceId(1));
2019-01-05 13:19:25 -08:00
assert_eq!(path.get("val").unwrap(), "value");
assert_eq!(&path["val"], "value");
let mut path = Path::new("/name/value2/index.html");
let (h, info) = router.recognize_mut(&mut path).unwrap();
assert_eq!(*h, 12);
2019-03-08 12:33:44 -08:00
assert_eq!(info, ResourceId(2));
2019-01-05 13:19:25 -08:00
assert_eq!(path.get("val").unwrap(), "value2");
let mut path = Path::new("/file/file.gz");
let (h, info) = router.recognize_mut(&mut path).unwrap();
assert_eq!(*h, 13);
2019-03-08 12:33:44 -08:00
assert_eq!(info, ResourceId(3));
2019-01-05 13:19:25 -08:00
assert_eq!(path.get("file").unwrap(), "file");
assert_eq!(path.get("ext").unwrap(), "gz");
let mut path = Path::new("/vtest/ttt/index.html");
let (h, info) = router.recognize_mut(&mut path).unwrap();
assert_eq!(*h, 14);
2019-03-08 12:33:44 -08:00
assert_eq!(info, ResourceId(4));
2019-01-05 13:19:25 -08:00
assert_eq!(path.get("val").unwrap(), "test");
assert_eq!(path.get("val2").unwrap(), "ttt");
let mut path = Path::new("/v/blah-blah/index.html");
let (h, info) = router.recognize_mut(&mut path).unwrap();
assert_eq!(*h, 15);
2019-03-08 12:33:44 -08:00
assert_eq!(info, ResourceId(5));
2019-01-05 13:19:25 -08:00
assert_eq!(path.get("tail").unwrap(), "blah-blah/index.html");
let mut path = Path::new("/test2/index.html");
let (h, info) = router.recognize_mut(&mut path).unwrap();
assert_eq!(*h, 16);
2019-03-08 12:33:44 -08:00
assert_eq!(info, ResourceId(6));
2019-01-05 13:19:25 -08:00
assert_eq!(path.get("test").unwrap(), "index");
let mut path = Path::new("/bbb/index.html");
let (h, info) = router.recognize_mut(&mut path).unwrap();
assert_eq!(*h, 17);
2019-03-08 12:33:44 -08:00
assert_eq!(info, ResourceId(7));
2019-01-05 13:19:25 -08:00
assert_eq!(path.get("test").unwrap(), "bbb");
}
#[test]
fn test_recognizer_2() {
let mut router = Router::<usize>::build();
router.path("/index.json", 10);
router.path("/{source}.json", 11);
let mut router = router.finish();
let mut path = Path::new("/index.json");
let (h, _) = router.recognize_mut(&mut path).unwrap();
assert_eq!(*h, 10);
let mut path = Path::new("/test.json");
let (h, _) = router.recognize_mut(&mut path).unwrap();
assert_eq!(*h, 11);
}
#[test]
fn test_recognizer_with_prefix() {
let mut router = Router::<usize>::build();
2019-03-08 12:33:44 -08:00
router.path("/name", 10).0.set_id(0);
router.path("/name/{val}", 11).0.set_id(1);
2019-01-05 13:19:25 -08:00
let mut router = router.finish();
let mut path = Path::new("/name");
path.skip(5);
assert!(router.recognize_mut(&mut path).is_none());
let mut path = Path::new("/test/name");
path.skip(5);
let (h, _) = router.recognize_mut(&mut path).unwrap();
assert_eq!(*h, 10);
let mut path = Path::new("/test/name/value");
path.skip(5);
2019-03-08 12:33:44 -08:00
let (h, id) = router.recognize_mut(&mut path).unwrap();
2019-01-05 13:19:25 -08:00
assert_eq!(*h, 11);
2019-03-08 12:33:44 -08:00
assert_eq!(id, ResourceId(1));
2019-01-05 13:19:25 -08:00
assert_eq!(path.get("val").unwrap(), "value");
assert_eq!(&path["val"], "value");
// same patterns
let mut router = Router::<usize>::build();
router.path("/name", 10);
router.path("/name/{val}", 11);
let mut router = router.finish();
let mut path = Path::new("/name");
path.skip(6);
assert!(router.recognize_mut(&mut path).is_none());
let mut path = Path::new("/test2/name");
path.skip(6);
let (h, _) = router.recognize_mut(&mut path).unwrap();
assert_eq!(*h, 10);
let mut path = Path::new("/test2/name-test");
path.skip(6);
assert!(router.recognize_mut(&mut path).is_none());
let mut path = Path::new("/test2/name/ttt");
path.skip(6);
let (h, _) = router.recognize_mut(&mut path).unwrap();
assert_eq!(*h, 11);
assert_eq!(&path["val"], "ttt");
}
}