1#[derive(Debug, Clone, PartialEq, Eq)]
5pub struct Router<R> {
6 stack: Vec<R>,
7}
8
9impl<R: Clone> Router<R> {
10 pub fn new(initial: R) -> Self {
12 Self { stack: vec![initial] }
13 }
14
15 pub fn current(&self) -> &R {
17 self.stack.last().expect("router stack must never be empty")
18 }
19
20 pub fn push(&mut self, route: R) {
22 self.stack.push(route);
23 }
24
25 pub fn pop(&mut self) -> bool {
28 if self.stack.len() > 1 {
29 self.stack.pop();
30 true
31 } else {
32 false
33 }
34 }
35
36 pub fn replace(&mut self, route: R) {
38 *self.stack.last_mut().expect("router stack must never be empty") = route;
39 }
40
41 pub fn len(&self) -> usize {
43 self.stack.len()
44 }
45
46 pub fn is_empty(&self) -> bool {
48 self.stack.is_empty()
49 }
50
51 pub fn stack(&self) -> &[R] {
53 &self.stack
54 }
55
56 pub fn push_uri<F>(&mut self, uri: &str, parser: F) -> bool
59 where
60 F: FnOnce(&str) -> Option<R>,
61 {
62 if let Some(route) = parser(uri) {
63 self.push(route);
64 true
65 } else {
66 false
67 }
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74
75 #[derive(Debug, Clone, PartialEq, Eq)]
76 enum TestRoute {
77 Home,
78 Settings,
79 User { id: String },
80 }
81
82 impl TestRoute {
83 fn from_uri(uri: &str) -> Option<Self> {
84 match uri {
85 "/" | "/home" => Some(TestRoute::Home),
86 "/settings" => Some(TestRoute::Settings),
87 s if s.starts_with("/user/") => Some(TestRoute::User {
88 id: s.trim_start_matches("/user/").to_string(),
89 }),
90 _ => None,
91 }
92 }
93 }
94
95 #[test]
96 fn test_router_initial_state() {
97 let router = Router::new(TestRoute::Home);
98 assert_eq!(router.current(), &TestRoute::Home);
99 assert_eq!(router.len(), 1);
100 assert!(!router.is_empty());
101 }
102
103 #[test]
104 fn test_router_push() {
105 let mut router = Router::new(TestRoute::Home);
106 router.push(TestRoute::Settings);
107 assert_eq!(router.current(), &TestRoute::Settings);
108 assert_eq!(router.len(), 2);
109 }
110
111 #[test]
112 fn test_router_pop() {
113 let mut router = Router::new(TestRoute::Home);
114 router.push(TestRoute::Settings);
115
116 assert!(router.pop());
117 assert_eq!(router.current(), &TestRoute::Home);
118 assert_eq!(router.len(), 1);
119
120 assert!(!router.pop());
122 assert_eq!(router.current(), &TestRoute::Home);
123 }
124
125 #[test]
126 fn test_router_replace() {
127 let mut router = Router::new(TestRoute::Home);
128 router.replace(TestRoute::Settings);
129 assert_eq!(router.current(), &TestRoute::Settings);
130 assert_eq!(router.len(), 1);
131 }
132
133 #[test]
134 fn test_router_push_uri() {
135 let mut router = Router::new(TestRoute::Home);
136
137 assert!(router.push_uri("/settings", TestRoute::from_uri));
138 assert_eq!(router.current(), &TestRoute::Settings);
139
140 assert!(router.push_uri("/user/42", TestRoute::from_uri));
141 assert_eq!(router.current(), &TestRoute::User { id: "42".to_string() });
142
143 assert!(!router.push_uri("/invalid", TestRoute::from_uri));
144 assert_eq!(router.current(), &TestRoute::User { id: "42".to_string() });
145 }
146}