1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
mod node;

use std::collections::HashMap;

pub use self::node::Node;
use crate::context::Context;
use thruster_core_async_await::MiddlewareChain;

pub enum Method {
    DELETE,
    GET,
    OPTIONS,
    POST,
    PUT,
    UPDATE,
}

pub struct RouteTree<T: 'static + Context + Send> {
    pub root_node: Node<T>,
    pub generic_root_node: Node<T>,
    pub specific_root_node: Node<T>,
}

fn method_to_prefix<'a>(method: &Method) -> &'a str {
    match method {
        Method::DELETE => "__DELETE__",
        Method::GET => "__GET__",
        Method::OPTIONS => "__OPTIONS__",
        Method::POST => "__POST__",
        Method::PUT => "__PUT__",
        Method::UPDATE => "__UPDATE__",
    }
}

impl<T: 'static + Context + Send> RouteTree<T> {
    pub fn new() -> RouteTree<T> {
        RouteTree {
            root_node: Node::new(""),
            generic_root_node: Node::new(""),
            specific_root_node: Node::new(""),
        }
    }

    ///
    /// Updates the `root_node` of the tree by merging the generic tree into the specific tree. This
    /// is necessary after adding any routes to ensure that the matching functions of the tree are
    /// up to date.
    ///
    pub fn update_root_node(&mut self) {
        let mut root_node = self.specific_root_node.clone();

        root_node
            .push_middleware_to_populated_nodes(&self.generic_root_node, &MiddlewareChain::new());

        self.root_node = root_node;
    }

    pub fn add_use_node(&mut self, route: &str, middleware: MiddlewareChain<T>) {
        self.generic_root_node.add_route(route, middleware);
        self.update_root_node();
    }

    pub fn add_route_with_method(
        &mut self,
        method: &Method,
        route: &str,
        middleware: MiddlewareChain<T>,
    ) {
        let prefix = method_to_prefix(&method);

        let full_route = format!("{}{}", prefix, route);

        self.specific_root_node.add_route(&full_route, middleware);
        self.update_root_node();
    }

    pub fn add_route(&mut self, route: &str, middleware: MiddlewareChain<T>) {
        self.specific_root_node.add_route(route, middleware);
        self.update_root_node();
    }

    fn _adopt_sub_app_method_to_self(
        &mut self,
        route: &str,
        mut route_tree: RouteTree<T>,
        method: &Method,
    ) -> RouteTree<T> {
        let method_prefix = method_to_prefix(&method);

        let mut self_routes = self
            .specific_root_node
            .children
            .remove(method_prefix)
            .unwrap_or_else(|| Node::new(method_prefix));

        if let Some(tree_routes) = route_tree.root_node.children.remove(method_prefix) {
            self_routes.add_subtree(route, tree_routes);
        }

        self.specific_root_node
            .children
            .insert(method_prefix.to_owned(), self_routes);

        // Return ownership
        route_tree
    }

    pub fn add_route_tree(&mut self, route: &str, mut route_tree: RouteTree<T>) {
        route_tree = self._adopt_sub_app_method_to_self(route, route_tree, &Method::DELETE);
        route_tree = self._adopt_sub_app_method_to_self(route, route_tree, &Method::GET);
        route_tree = self._adopt_sub_app_method_to_self(route, route_tree, &Method::OPTIONS);
        route_tree = self._adopt_sub_app_method_to_self(route, route_tree, &Method::POST);
        route_tree = self._adopt_sub_app_method_to_self(route, route_tree, &Method::PUT);
        self._adopt_sub_app_method_to_self(route, route_tree, &Method::UPDATE);
        self.update_root_node();
    }

    pub fn match_route(&self, route: &str) -> (HashMap<String, String>, &MiddlewareChain<T>) {
        let results = self.root_node.match_route(route.split('/'));

        (results.0, results.2)
    }

    pub fn match_route_with_params(
        &self,
        route: &str,
        params: HashMap<String, String>,
    ) -> (HashMap<String, String>, &MiddlewareChain<T>) {
        let results = self
            .root_node
            .match_route_with_params(route.split('/'), params);

        (results.0, results.2)
    }
}

impl<T: 'static + Context + Send> Default for RouteTree<T> {
    fn default() -> RouteTree<T> {
        RouteTree::new()
    }
}