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
use std::sync::Arc;

use regex::Regex;

use crate::controller::Controller;
use crate::http::*;
use crate::utils::ToRegex;

///
pub struct Builder {
    routes: Vec<(Regex, Box<Controller>)>
}

///
impl Builder {
    /// Create a new router builder
    pub fn new() -> Self {
        Builder {
            routes: Vec::new()
        }
    }

    /// Add a new controller with its route to the router
    /// # Example
    /// ```rust,no_run
    /// let u8_context = 1;
    /// let u8_controller = BasicController::new(u8_context);
    /// u8_controller.add(Method::Get, "^/test$", |ctx, req, res| { println!("this will handle Get request done on <your_host>/test")});
    ///
    /// let mut router = Router::new();
    /// router.add("/test", u8_controller);
    ///
    /// ```
    pub fn add<C: 'static + Controller>(mut self, controller: C) -> Self {
        self.routes.push((reg!(controller.base_path()), Box::new(controller)));

        self
    }

    /// Add a new controller with its route to the router
    /// # Example
    /// ```rust,no_run
    /// let u8_context = 1;
    /// let u8_controller = BasicController::new(u8_context);
    /// u8_controller.add(Method::Get, "^/test$", |ctx, req, res| { println!("this will handle Get request done on <your_host>/test")});
    ///
    /// let mut router = Router::new();
    /// router.add("/test", u8_controller);
    ///
    /// ```
    pub fn route<C: 'static + Controller, R: ToRegex>(mut self, route: R, controller: C) -> Self {
        let mut cont_base_path = controller.base_path().to_string();
        if cont_base_path.starts_with('^') {
            cont_base_path.remove(0);
        }
        let mut route_str = route.as_str().to_string();
        route_str.push_str(&cont_base_path);
        self.routes.push((reg!(route_str), Box::new(controller)));

        self
    }

    /// Builds the router
    pub fn build(self) -> Router {
        let Builder {
            routes
        } = self;

        Router {
            routes: Arc::new(routes),
        }
    }
}

/// A Struct responsible of dispatching request towards controllers
pub struct Router {
    ///
    routes: Arc<Vec<(Regex, Box<Controller>)>>
}

impl Router {
    ///
    pub fn new() -> Self {
        Router {
            routes: Arc::new(Vec::new()),
        }
    }

    ///
    pub fn dispatch(&self, req: &mut SyncRequest, res: &mut SyncResponse) {
        let h: Option<(usize, &(Regex, Box<Controller>))> = self.routes.iter().enumerate().find(
            |&(_, &(ref re, _))| {
                req.current_path_match(re)
            }
        );

        if let Some((_, &(_, ref controller))) = h {
            controller.handle(req, res);
        } else {
            res.status(StatusCode::NOT_FOUND);
        }
    }
}

impl Clone for Router {
    fn clone(&self) -> Self {
        Router {
            routes: self.routes.clone(),
        }
    }
}