shio/router/
parameters.rs

1use std::ops::Index;
2use std::sync::Arc;
3use std::collections::HashMap;
4
5use util::typemap::Key;
6use regex::Captures;
7
8pub struct Parameters {
9    text: String,
10    matches: Vec<Option<(usize, usize)>>,
11    names: Arc<HashMap<String, usize>>,
12}
13
14impl Parameters {
15    pub(crate) fn new(names: Arc<HashMap<String, usize>>, text: &str, captures: Captures) -> Self {
16        Self {
17            names,
18            text: text.into(),
19            matches: captures
20                .iter()
21                .map(|capture| capture.map(|m| (m.start(), m.end())))
22                .collect(),
23        }
24    }
25
26    pub fn get(&self, index: usize) -> Option<&str> {
27        self.matches
28            // +1 is added as matches start at 1 in regex (with 0 referring to the
29            //  whole matched text)
30            .get(index + 1)
31            .and_then(|m| m.map(|(start, end)| &self.text[start..end]))
32    }
33
34    pub fn name(&self, name: &str) -> Option<&str> {
35        self.names.get(name).and_then(|&i| self.get(i - 1))
36    }
37}
38
39impl Key for Parameters {
40    type Value = Self;
41}
42
43impl Index<usize> for Parameters {
44    type Output = str;
45
46    /// Get a parameter by index.
47    ///
48    /// # Panics
49    ///
50    /// If there is no parameter at the given index.
51    fn index(&self, index: usize) -> &Self::Output {
52        self.get(index)
53            .unwrap_or_else(|| panic!("no parameter at index '{}'", index))
54    }
55}
56
57impl<'b> Index<&'b str> for Parameters {
58    type Output = str;
59
60    /// Get a parameter by name.
61    ///
62    /// # Panics
63    ///
64    /// If there is no parameter named by the given value.
65    fn index<'a>(&'a self, name: &str) -> &'a str {
66        self.name(name)
67            .unwrap_or_else(|| panic!("no parameter named '{}'", name))
68    }
69}