1use std::collections::HashMap;
29use std::str::FromStr;
30
31pub mod err {
33 #[derive(Debug)]
35 pub enum Error {
36 Captures,
37 Unmatched(String),
38 Regex(regex::Error),
39 }
40
41 impl std::fmt::Display for Error {
42 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
43 use Error::*;
44 match self {
45 Captures => "Could not parse captures".fmt(f),
46 Unmatched(ref path) => write!(f, "Could not match path: {}", path),
47 Regex(ref inner) => inner.fmt(f),
48 }
49 }
50 }
51
52 impl std::error::Error for Error {
53 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
54 use Error::*;
55 match self {
56 Regex(ref inner) => Some(inner),
57 _ => None,
58 }
59 }
60 }
61
62 pub type Result<T> = std::result::Result<T, Error>;
64}
65
66pub struct Captures {
68 path: Box<str>,
69 locs: Option<regex::CaptureLocations>,
70 capture_names: Option<CaptureNames>,
71}
72
73impl Captures {
74 fn new(
75 path: Box<str>,
76 regex: ®ex::Regex,
77 mut locs: regex::CaptureLocations,
78 capture_names: Option<CaptureNames>,
79 ) -> Self {
80 let locs = regex.captures_read(&mut locs, &path).map(|_| locs);
81
82 Self { path, locs, capture_names }
83 }
84
85 pub fn name(&self, name: &str) -> Option<&str> {
87 self.capture_names.as_ref().and_then(|map| map.0.get(name)).and_then(|i| self.get(*i))
88 }
89
90 pub fn get(&self, i: usize) -> Option<&str> {
92 self.locs
93 .as_ref()
94 .and_then(|loc| loc.get(i))
95 .and_then(|(start, end)| self.path.get(start..end) )
96 }
97
98 pub fn parsed<C: FromCaptures>(&self) -> err::Result<C> {
100 Ok(C::from_captures(&self)?)
101 }
102
103 pub fn iter(&self) -> CapturesIter {
105 let iter = self
106 .locs
107 .as_ref()
108 .map(|locs| (0..locs.len()).into_iter().filter_map(move |i| locs.get(i)))
109 .into_iter()
110 .flatten();
111
112 CapturesIter(Box::new(iter), &self.path)
113 }
114}
115
116#[doc(hidden)]
117pub struct CapturesIter<'a>(Box<dyn Iterator<Item=(usize, usize)> + 'a>, &'a str);
118
119impl<'a> Iterator for CapturesIter<'a> {
120 type Item = &'a str;
121
122 fn next(&mut self) -> Option<&'a str> {
123 self.0.next().and_then(|(start, end)| self.1.get(start..end) )
124 }
125}
126
127pub struct Match<'a, T> {
129 pub handler: &'a T,
130 pub captures: Captures,
131}
132
133#[derive(Debug)]
134struct RouteParts<T> {
135 regex: String,
136 priority: i8,
137 handler: T,
138}
139
140#[derive(Default)]
142pub struct RouterBuilder<T> {
143 parts: Vec<RouteParts<T>>,
144}
145
146impl<T> RouterBuilder<T> {
147 fn new() -> Self {
148 RouterBuilder {
149 parts: Vec::new(),
150 }
151 }
152
153 pub fn add<I: Into<String>>(self, regex: I, handler: T) -> Self {
155 self.add_with_priority(regex, 0, handler)
156 }
157
158 pub fn add_with_priority<I: Into<String>>(
160 mut self,
161 regex: I,
162 priority: i8,
163 handler: T,
164 ) -> Self {
165 self.parts.push(RouteParts { regex: regex.into(), priority, handler });
166
167 self
168 }
169
170 pub fn finish(self) -> err::Result<Router<T>> {
172 let (regex_strs, priorities, handlers) = self.parts.into_iter().fold(
173 (Vec::new(), Vec::new(), Vec::new()),
174 |(mut regex_strs, mut priorities, mut handlers),
175 RouteParts { regex, priority, handler }| {
176 regex_strs.push(regex);
177 priorities.push(priority);
178 handlers.push(handler);
179 (regex_strs, priorities, handlers)
180 },
181 );
182
183 let regex_set = regex::RegexSet::new(regex_strs.iter()).map_err(err::Error::Regex)?;
184
185 let mut regexes = Vec::new();
186 let mut capture_names = Vec::new();
187 let mut capture_locations = Vec::new();
188
189 for regex_str in regex_strs.iter() {
190 let regex = regex::Regex::new(regex_str).map_err(err::Error::Regex)?;
191 capture_names.push(CaptureNames::build(®ex));
192 capture_locations.push(regex.capture_locations());
193 regexes.push(regex);
194 }
195
196 Ok(Router { regex_set, regexes, capture_names, capture_locations, priorities, handlers })
197 }
198}
199
200#[derive(Clone)]
201struct CaptureNames(std::sync::Arc<HashMap<String, usize>>);
202
203impl CaptureNames {
204 fn build(regex: ®ex::Regex) -> Option<Self> {
205 let map = regex
206 .capture_names()
207 .enumerate()
208 .filter_map(|(i, opt_name)| opt_name.map(|name| (String::from(name), i)))
209 .collect::<HashMap<_, _>>();
210 if map.is_empty() {
211 None
212 } else {
213 Some(Self(std::sync::Arc::new(map)))
214 }
215 }
216}
217
218pub struct Router<T> {
220 regex_set: regex::RegexSet,
221 regexes: Vec<regex::Regex>,
222 capture_locations: Vec<regex::CaptureLocations>,
223 capture_names: Vec<Option<CaptureNames>>,
224 priorities: Vec<i8>,
225 handlers: Vec<T>,
226}
227
228impl<T> Router<T> {
229 pub fn build() -> RouterBuilder<T> {
231 RouterBuilder::new()
232 }
233
234 pub fn recognize<'a>(&'a self, path: &str) -> err::Result<Match<'a, T>> {
236 if let Some(i) = self
237 .regex_set
238 .matches(path)
239 .iter()
240 .max_by(|x, y| self.priorities[*x].cmp(&self.priorities[*y]))
241 {
242 let handler = &self.handlers[i];
243 let regex = &self.regexes[i];
244 let capture_names = &self.capture_names[i];
245 let capture_locations = &self.capture_locations[i];
246 Ok(Match {
247 handler,
248 captures: Captures::new(
249 path.into(),
250 regex,
251 capture_locations.clone(),
252 capture_names.clone(),
253 ),
254 })
255 } else {
256 Err(err::Error::Unmatched(String::from(path)))
257 }
258 }
259}
260
261pub trait FromCaptures: Sized {
263 fn from_captures(caps: &Captures) -> err::Result<Self>;
264}
265
266impl<U: FromStr> FromCaptures for (U,) {
267 fn from_captures(caps: &Captures) -> err::Result<Self> {
268 let out_1 = caps.get(1).and_then(|x| x.parse().ok()).ok_or(err::Error::Captures)?;
269 Ok((out_1,))
270 }
271}
272
273impl<U1: FromStr, U2: FromStr> FromCaptures for (U1, U2) {
274 fn from_captures(caps: &Captures) -> err::Result<Self> {
275 let out_1 = caps.get(1).and_then(|x| x.parse().ok()).ok_or(err::Error::Captures)?;
276 let out_2 = caps.get(2).and_then(|x| x.parse().ok()).ok_or(err::Error::Captures)?;
277 Ok((out_1, out_2))
278 }
279}
280
281impl<U1: FromStr, U2: FromStr, U3: FromStr> FromCaptures for (U1, U2, U3) {
282 fn from_captures(caps: &Captures) -> err::Result<Self> {
283 let out_1 = caps.get(1).and_then(|x| x.parse().ok()).ok_or(err::Error::Captures)?;
284 let out_2 = caps.get(2).and_then(|x| x.parse().ok()).ok_or(err::Error::Captures)?;
285 let out_3 = caps.get(3).and_then(|x| x.parse().ok()).ok_or(err::Error::Captures)?;
286 Ok((out_1, out_2, out_3))
287 }
288}
289
290impl<U1: FromStr, U2: FromStr, U3: FromStr, U4: FromStr> FromCaptures for (U1, U2, U3, U4) {
291 fn from_captures(caps: &Captures) -> err::Result<Self> {
292 let out_1 = caps.get(1).and_then(|x| x.parse().ok()).ok_or(err::Error::Captures)?;
293 let out_2 = caps.get(2).and_then(|x| x.parse().ok()).ok_or(err::Error::Captures)?;
294 let out_3 = caps.get(3).and_then(|x| x.parse().ok()).ok_or(err::Error::Captures)?;
295 let out_4 = caps.get(4).and_then(|x| x.parse().ok()).ok_or(err::Error::Captures)?;
296 Ok((out_1, out_2, out_3, out_4))
297 }
298}