redirectionio 2.5.2

Redirection IO Library to handle matching rule, redirect and filtering headers and body.
mod config;
mod marker_string;
pub mod request_matcher;
mod route;
mod route_header;
mod route_ip;
mod trace;
mod transformer;

use crate::http::Request;
pub use config::RouterConfig;
pub use marker_string::{Marker, MarkerString, StaticOrDynamic};
pub use request_matcher::{HostMatcher, IpMatcher, MethodMatcher, PathAndQueryMatcher, RequestMatcher, SchemeMatcher};
pub use route::{Route, RouteData};
pub use route_header::{RouteHeader, RouteHeaderKind};
pub use route_ip::RouteIp;
pub use trace::{RouteTrace, Trace};
pub use transformer::{Camelize, Dasherize, Lowercase, Replace, Slice, Transform, Underscorize, Uppercase};

use core::cmp::Reverse;

#[derive(Debug, Clone)]
pub struct Router<T: RouteData> {
    matcher: SchemeMatcher<T>,
    pub config: RouterConfig,
}

impl<T: RouteData> Default for Router<T> {
    fn default() -> Self {
        Router {
            matcher: SchemeMatcher::new(RouterConfig::default()),
            config: RouterConfig::default(),
        }
    }
}

impl<T: RouteData> Router<T> {
    pub fn from_config(config: RouterConfig) -> Self {
        Self {
            matcher: SchemeMatcher::new(config.clone()),
            config,
        }
    }

    pub fn insert(&mut self, route: Route<T>) {
        self.matcher.insert(route);
    }

    pub fn remove(&mut self, id: &str) -> bool {
        self.matcher.remove(id)
    }

    pub fn match_request(&self, request: &Request) -> Vec<&Route<T>> {
        let request_rebuild = Request::rebuild_with_config(&self.config, request);

        self.matcher.match_request(&request_rebuild)
    }

    pub fn len(&self) -> usize {
        self.matcher.len()
    }

    pub fn is_empty(&self) -> bool {
        self.matcher.is_empty()
    }

    pub fn trace_request(&self, request: &Request) -> Vec<Trace<T>> {
        let request_rebuild = Request::rebuild_with_config(&self.config, request);

        self.matcher.trace(&request_rebuild)
    }

    pub fn get_route(&self, request: &Request) -> Option<&Route<T>> {
        let mut routes = self.match_request(request);

        if routes.is_empty() {
            return None;
        }

        routes.sort_by_key(|&b| Reverse(b.priority()));

        match routes.get(0) {
            None => None,
            Some(&route) => Some(route),
        }
    }

    pub fn get_trace(&self, request: &Request) -> RouteTrace<T> {
        let traces = self.trace_request(request);
        let mut routes_traces = Trace::get_routes_from_traces(&traces);
        let mut routes = Vec::new();

        for &route in &routes_traces {
            routes.push(route.clone());
        }

        routes_traces.sort_by(|&a, &b| b.priority().cmp(&a.priority()));

        let final_route = routes_traces.first().map(|&route| route.clone());

        RouteTrace::new(traces, routes, final_route)
    }

    pub fn cache(&mut self, limit: u64) {
        let mut prev_cache_limit = limit;
        let mut level = 0;

        while prev_cache_limit > 0 {
            let next_cache_limit = self.matcher.cache(prev_cache_limit, level);

            if next_cache_limit == prev_cache_limit && level > 5 {
                break;
            }

            level += 1;
            prev_cache_limit = next_cache_limit;
        }
    }
}