routing-match 0.2.0

A simple route match utils
Documentation
use std::collections::HashMap;
use std::sync::{Arc, RwLock};

/// 路由器
/// 路由支持静态, 动态, 通配符三种匹配方式
/// 静态: /home/static
/// 动态:/home/{name}.jpg, 每个段只支持一个参数
/// 通配符:/home/{*all}, 参数all可以匹配多个段, *后面必须跟参数名,没有参数名不行
/// 第一段可以不使用/, 比如"home/static"
/// 通配符需要位于路径的末尾

/// 单线程版本
#[derive(Clone)]
pub struct Router<T: Clone> {
    r: matchit::Router<T>,
}

impl<T: Clone> Router<T> {
    pub fn new() -> Self {
        Self {
            r: matchit::Router::new(),
        }
    }

    /// 插入
    /// 失败:有可能是因为path不合法
    /// 成功:返回旧值
    pub fn insert(&mut self, path: &str, v: T) -> Result<Option<T>, ()> {
        let old = self.r.remove(path);
        match self.r.insert(path, v.clone()) {
            Ok(_) => Ok(old),
            Err(_) => Err(()),
        }
    }

    /// 删除
    pub fn remove(&mut self, path: &str) -> Option<T> {
        self.r.remove(path)
    }

    /// 查找
    pub fn at(&self, path: &str) -> Option<&T> {
        match self.r.at(path) {
            Err(_) => None,
            Ok(m) => Some(m.value),
        }
    }

    pub fn at_with_params<'a>(
        &'a self,
        path: &'a str,
    ) -> Option<(&'a T, HashMap<&'a str, &'a str>)> {
        match self.r.at(path) {
            Err(_) => None,
            Ok(m) => {
                let mut p = HashMap::new();
                for (k, v) in m.params.iter() {
                    p.insert(k, v);
                }
                Some((m.value, p))
            }
        }
    }
}

#[derive(Clone)]
pub struct ARouter<T: Clone> {
    r: Arc<RwLock<Router<T>>>,
}

impl<T: Clone> ARouter<T> {
    pub fn new() -> Self {
        Self {
            r: Arc::new(RwLock::new(Router::new())),
        }
    }

    pub fn insert(&self, path: &str, v: T) -> Result<Option<T>, ()> {
        let mut wg = self.r.write().unwrap();
        wg.insert(path, v)
    }

    pub fn remove(&mut self, path: &str) -> Option<T> {
        let mut wg = self.r.write().unwrap();
        wg.remove(path)
    }

    pub fn at(&self, path: &str) -> Option<T> {
        let g = self.r.read().unwrap();
        g.at(path).map(|v| v.clone())
    }

    pub fn at_with_params(&self, path: &str) -> Option<(T, HashMap<String, String>)> {
        let g = self.r.read().unwrap();
        g.at_with_params(path).map(|i| {
            (
                i.0.clone(),
                i.1.iter()
                    .map(|kv| (kv.0.to_string(), kv.1.to_string()))
                    .collect(),
            )
        })
    }
}

#[test]
fn test_router() {
    let mut r = ARouter::new();//Router::new();
    let mut r2 = r.clone();

    println!("{:?}", r.insert("/{service}/{method}", "http"));
    println!("{:?}", r.insert("/{service}/{method}", "http request"));
    println!("{:?}", r.at("/game/send"));
    println!("{:?}", r.at_with_params("/game/send"));
    println!("{:?}", r2.remove("/{service}/{method}"));
    println!("{:?}", r.at("/game/send"));
    println!("{:?}", r.remove("/{service}/{method}"));
}