1use crate::{IntoPattern, Resource, ResourceDef, ResourcePath};
2
3#[derive(Debug, Copy, Clone, PartialEq)]
4pub struct ResourceId(pub u16);
5
6#[derive(Clone, Debug)]
8pub struct ResourceInfo {
9 resource: ResourceId,
10}
11
12pub struct Router<T, U = ()>(Vec<(ResourceDef, T, Option<U>)>);
14
15impl<T, U> Router<T, U> {
16 pub fn build() -> RouterBuilder<T, U> {
17 RouterBuilder {
18 resources: Vec::new(),
19 }
20 }
21
22 pub fn recognize<R, P>(&self, resource: &mut R) -> Option<(&T, ResourceId)>
23 where
24 R: Resource<P>,
25 P: ResourcePath,
26 {
27 for item in self.0.iter() {
28 if item.0.match_path(resource.resource_path()) {
29 return Some((&item.1, ResourceId(item.0.id())));
30 }
31 }
32 None
33 }
34
35 pub fn recognize_mut<R, P>(&mut self, resource: &mut R) -> Option<(&mut T, ResourceId)>
36 where
37 R: Resource<P>,
38 P: ResourcePath,
39 {
40 for item in self.0.iter_mut() {
41 if item.0.match_path(resource.resource_path()) {
42 return Some((&mut item.1, ResourceId(item.0.id())));
43 }
44 }
45 None
46 }
47
48 pub fn recognize_mut_checked<R, P, F>(
49 &mut self,
50 resource: &mut R,
51 check: F,
52 ) -> Option<(&mut T, ResourceId)>
53 where
54 F: Fn(&R, &Option<U>) -> bool,
55 R: Resource<P>,
56 P: ResourcePath,
57 {
58 for item in self.0.iter_mut() {
59 if item.0.match_path_checked(resource, &check, &item.2) {
60 return Some((&mut item.1, ResourceId(item.0.id())));
61 }
62 }
63 None
64 }
65}
66
67pub struct RouterBuilder<T, U = ()> {
68 resources: Vec<(ResourceDef, T, Option<U>)>,
69}
70
71impl<T, U> RouterBuilder<T, U> {
72 pub fn path<P: IntoPattern>(
74 &mut self,
75 path: P,
76 resource: T,
77 ) -> &mut (ResourceDef, T, Option<U>) {
78 self.resources
79 .push((ResourceDef::new(path), resource, None));
80 self.resources.last_mut().unwrap()
81 }
82
83 pub fn prefix(&mut self, prefix: &str, resource: T) -> &mut (ResourceDef, T, Option<U>) {
85 self.resources
86 .push((ResourceDef::prefix(prefix), resource, None));
87 self.resources.last_mut().unwrap()
88 }
89
90 pub fn rdef(&mut self, rdef: ResourceDef, resource: T) -> &mut (ResourceDef, T, Option<U>) {
92 self.resources.push((rdef, resource, None));
93 self.resources.last_mut().unwrap()
94 }
95
96 pub fn finish(self) -> Router<T, U> {
98 Router(self.resources)
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use crate::path::Path;
105 use crate::router::{ResourceId, Router};
106
107 #[test]
108 fn test_recognizer_1() {
109 let mut router = Router::<usize>::build();
110 router.path("/name", 10).0.set_id(0);
111 router.path("/name/{val}", 11).0.set_id(1);
112 router.path("/name/{val}/index.html", 12).0.set_id(2);
113 router.path("/file/{file}.{ext}", 13).0.set_id(3);
114 router.path("/v{val}/{val2}/index.html", 14).0.set_id(4);
115 router.path("/v/{tail:.*}", 15).0.set_id(5);
116 router.path("/test2/{test}.html", 16).0.set_id(6);
117 router.path("/{test}/index.html", 17).0.set_id(7);
118 let mut router = router.finish();
119
120 let mut path = Path::new("/unknown");
121 assert!(router.recognize_mut(&mut path).is_none());
122
123 let mut path = Path::new("/name");
124 let (h, info) = router.recognize_mut(&mut path).unwrap();
125 assert_eq!(*h, 10);
126 assert_eq!(info, ResourceId(0));
127 assert!(path.is_empty());
128
129 let mut path = Path::new("/name/value");
130 let (h, info) = router.recognize_mut(&mut path).unwrap();
131 assert_eq!(*h, 11);
132 assert_eq!(info, ResourceId(1));
133 assert_eq!(path.get("val").unwrap(), "value");
134 assert_eq!(&path["val"], "value");
135
136 let mut path = Path::new("/name/value2/index.html");
137 let (h, info) = router.recognize_mut(&mut path).unwrap();
138 assert_eq!(*h, 12);
139 assert_eq!(info, ResourceId(2));
140 assert_eq!(path.get("val").unwrap(), "value2");
141
142 let mut path = Path::new("/file/file.gz");
143 let (h, info) = router.recognize_mut(&mut path).unwrap();
144 assert_eq!(*h, 13);
145 assert_eq!(info, ResourceId(3));
146 assert_eq!(path.get("file").unwrap(), "file");
147 assert_eq!(path.get("ext").unwrap(), "gz");
148
149 let mut path = Path::new("/vtest/ttt/index.html");
150 let (h, info) = router.recognize_mut(&mut path).unwrap();
151 assert_eq!(*h, 14);
152 assert_eq!(info, ResourceId(4));
153 assert_eq!(path.get("val").unwrap(), "test");
154 assert_eq!(path.get("val2").unwrap(), "ttt");
155
156 let mut path = Path::new("/v/blah-blah/index.html");
157 let (h, info) = router.recognize_mut(&mut path).unwrap();
158 assert_eq!(*h, 15);
159 assert_eq!(info, ResourceId(5));
160 assert_eq!(path.get("tail").unwrap(), "blah-blah/index.html");
161
162 let mut path = Path::new("/test2/index.html");
163 let (h, info) = router.recognize_mut(&mut path).unwrap();
164 assert_eq!(*h, 16);
165 assert_eq!(info, ResourceId(6));
166 assert_eq!(path.get("test").unwrap(), "index");
167
168 let mut path = Path::new("/bbb/index.html");
169 let (h, info) = router.recognize_mut(&mut path).unwrap();
170 assert_eq!(*h, 17);
171 assert_eq!(info, ResourceId(7));
172 assert_eq!(path.get("test").unwrap(), "bbb");
173 }
174
175 #[test]
176 fn test_recognizer_2() {
177 let mut router = Router::<usize>::build();
178 router.path("/index.json", 10);
179 router.path("/{source}.json", 11);
180 let mut router = router.finish();
181
182 let mut path = Path::new("/index.json");
183 let (h, _) = router.recognize_mut(&mut path).unwrap();
184 assert_eq!(*h, 10);
185
186 let mut path = Path::new("/test.json");
187 let (h, _) = router.recognize_mut(&mut path).unwrap();
188 assert_eq!(*h, 11);
189 }
190
191 #[test]
192 fn test_recognizer_with_prefix() {
193 let mut router = Router::<usize>::build();
194 router.path("/name", 10).0.set_id(0);
195 router.path("/name/{val}", 11).0.set_id(1);
196 let mut router = router.finish();
197
198 let mut path = Path::new("/name");
199 path.skip(5);
200 assert!(router.recognize_mut(&mut path).is_none());
201
202 let mut path = Path::new("/test/name");
203 path.skip(5);
204 let (h, _) = router.recognize_mut(&mut path).unwrap();
205 assert_eq!(*h, 10);
206
207 let mut path = Path::new("/test/name/value");
208 path.skip(5);
209 let (h, id) = router.recognize_mut(&mut path).unwrap();
210 assert_eq!(*h, 11);
211 assert_eq!(id, ResourceId(1));
212 assert_eq!(path.get("val").unwrap(), "value");
213 assert_eq!(&path["val"], "value");
214
215 let mut router = Router::<usize>::build();
217 router.path("/name", 10);
218 router.path("/name/{val}", 11);
219 let mut router = router.finish();
220
221 let mut path = Path::new("/name");
222 path.skip(6);
223 assert!(router.recognize_mut(&mut path).is_none());
224
225 let mut path = Path::new("/test2/name");
226 path.skip(6);
227 let (h, _) = router.recognize_mut(&mut path).unwrap();
228 assert_eq!(*h, 10);
229
230 let mut path = Path::new("/test2/name-test");
231 path.skip(6);
232 assert!(router.recognize_mut(&mut path).is_none());
233
234 let mut path = Path::new("/test2/name/ttt");
235 path.skip(6);
236 let (h, _) = router.recognize_mut(&mut path).unwrap();
237 assert_eq!(*h, 11);
238 assert_eq!(&path["val"], "ttt");
239 }
240}