matchit/
params.rs

1use std::{fmt, iter, mem, slice};
2
3/// A single URL parameter, consisting of a key and a value.
4#[derive(PartialEq, Eq, Ord, PartialOrd, Default, Copy, Clone)]
5struct Param<'k, 'v> {
6    // Keys and values are stored as byte slices internally by the router
7    // to avoid UTF8 checks when slicing, but UTF8 is still respected,
8    // so these slices are valid strings.
9    key: &'k [u8],
10    value: &'v [u8],
11}
12
13impl<'k, 'v> Param<'k, 'v> {
14    const EMPTY: Param<'static, 'static> = Param {
15        key: b"",
16        value: b"",
17    };
18
19    // Returns the parameter key as a string.
20    fn key_str(&self) -> &'k str {
21        std::str::from_utf8(self.key).unwrap()
22    }
23
24    // Returns the parameter value as a string.
25    fn value_str(&self) -> &'v str {
26        std::str::from_utf8(self.value).unwrap()
27    }
28}
29
30/// A list of parameters returned by a route match.
31///
32/// ```rust
33/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
34/// # let mut router = matchit::Router::new();
35/// # router.insert("/users/{id}", true).unwrap();
36/// let matched = router.at("/users/1")?;
37///
38/// // Iterate through the keys and values.
39/// for (key, value) in matched.params.iter() {
40///     println!("key: {}, value: {}", key, value);
41/// }
42///
43/// // Get a specific value by name.
44/// let id = matched.params.get("id");
45/// assert_eq!(id, Some("1"));
46/// # Ok(())
47/// # }
48/// ```
49#[derive(PartialEq, Eq, Ord, PartialOrd, Clone)]
50pub struct Params<'k, 'v> {
51    kind: ParamsKind<'k, 'v>,
52}
53
54impl Default for Params<'_, '_> {
55    fn default() -> Self {
56        Self::new()
57    }
58}
59
60// Most routes have a small number of dynamic parameters, so we can avoid
61// heap allocations in the common case.
62const SMALL: usize = 3;
63
64// A list of parameters, optimized to avoid allocations when possible.
65#[derive(PartialEq, Eq, Ord, PartialOrd, Clone)]
66enum ParamsKind<'k, 'v> {
67    Small([Param<'k, 'v>; SMALL], usize),
68    Large(Vec<Param<'k, 'v>>),
69}
70
71impl<'k, 'v> Params<'k, 'v> {
72    /// Create an empty list of parameters.
73    pub fn new() -> Self {
74        Self {
75            kind: ParamsKind::Small([Param::EMPTY; 3], 0),
76        }
77    }
78
79    /// Returns the number of parameters.
80    pub fn len(&self) -> usize {
81        match self.kind {
82            ParamsKind::Small(_, len) => len,
83            ParamsKind::Large(ref vec) => vec.len(),
84        }
85    }
86
87    // Truncates the parameter list to the given length.
88    pub(crate) fn truncate(&mut self, n: usize) {
89        match &mut self.kind {
90            ParamsKind::Small(_, len) => *len = n,
91            ParamsKind::Large(vec) => vec.truncate(n),
92        }
93    }
94
95    /// Returns the value of the first parameter registered under the given key.
96    pub fn get(&self, key: impl AsRef<str>) -> Option<&'v str> {
97        let key = key.as_ref().as_bytes();
98
99        match &self.kind {
100            ParamsKind::Small(arr, len) => arr
101                .iter()
102                .take(*len)
103                .find(|param| param.key == key)
104                .map(Param::value_str),
105            ParamsKind::Large(vec) => vec
106                .iter()
107                .find(|param| param.key == key)
108                .map(Param::value_str),
109        }
110    }
111
112    /// Returns an iterator over the parameters in the list.
113    pub fn iter(&self) -> ParamsIter<'_, 'k, 'v> {
114        ParamsIter::new(self)
115    }
116
117    /// Returns `true` if there are no parameters in the list.
118    pub fn is_empty(&self) -> bool {
119        match self.kind {
120            ParamsKind::Small(_, len) => len == 0,
121            ParamsKind::Large(ref vec) => vec.is_empty(),
122        }
123    }
124
125    /// Inserts a key value parameter pair into the list.
126    pub(crate) fn push(&mut self, key: &'k [u8], value: &'v [u8]) {
127        #[cold]
128        fn drain_to_vec<T: Default>(len: usize, elem: T, arr: &mut [T; SMALL]) -> Vec<T> {
129            let mut vec = Vec::with_capacity(len + 1);
130            vec.extend(arr.iter_mut().map(mem::take));
131            vec.push(elem);
132            vec
133        }
134
135        let param = Param { key, value };
136        match &mut self.kind {
137            ParamsKind::Small(arr, len) => {
138                if *len == SMALL {
139                    self.kind = ParamsKind::Large(drain_to_vec(*len, param, arr));
140                    return;
141                }
142
143                arr[*len] = param;
144                *len += 1;
145            }
146            ParamsKind::Large(vec) => vec.push(param),
147        }
148    }
149
150    // Applies a transformation function to each key.
151    pub(crate) fn for_each_key_mut(&mut self, f: impl Fn((usize, &mut &'k [u8]))) {
152        match &mut self.kind {
153            ParamsKind::Small(arr, len) => arr
154                .iter_mut()
155                .take(*len)
156                .map(|param| &mut param.key)
157                .enumerate()
158                .for_each(f),
159            ParamsKind::Large(vec) => vec
160                .iter_mut()
161                .map(|param| &mut param.key)
162                .enumerate()
163                .for_each(f),
164        }
165    }
166}
167
168impl fmt::Debug for Params<'_, '_> {
169    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170        f.debug_list().entries(self.iter()).finish()
171    }
172}
173
174/// An iterator over the keys and values of a route's [parameters](crate::Params).
175pub struct ParamsIter<'ps, 'k, 'v> {
176    kind: ParamsIterKind<'ps, 'k, 'v>,
177}
178
179impl<'ps, 'k, 'v> ParamsIter<'ps, 'k, 'v> {
180    fn new(params: &'ps Params<'k, 'v>) -> Self {
181        let kind = match &params.kind {
182            ParamsKind::Small(arr, len) => ParamsIterKind::Small(arr.iter().take(*len)),
183            ParamsKind::Large(vec) => ParamsIterKind::Large(vec.iter()),
184        };
185        Self { kind }
186    }
187}
188
189enum ParamsIterKind<'ps, 'k, 'v> {
190    Small(iter::Take<slice::Iter<'ps, Param<'k, 'v>>>),
191    Large(slice::Iter<'ps, Param<'k, 'v>>),
192}
193
194impl<'ps, 'k, 'v> Iterator for ParamsIter<'ps, 'k, 'v> {
195    type Item = (&'k str, &'v str);
196
197    fn next(&mut self) -> Option<Self::Item> {
198        match self.kind {
199            ParamsIterKind::Small(ref mut iter) => {
200                iter.next().map(|p| (p.key_str(), p.value_str()))
201            }
202            ParamsIterKind::Large(ref mut iter) => {
203                iter.next().map(|p| (p.key_str(), p.value_str()))
204            }
205        }
206    }
207}
208
209impl ExactSizeIterator for ParamsIter<'_, '_, '_> {
210    fn len(&self) -> usize {
211        match self.kind {
212            ParamsIterKind::Small(ref iter) => iter.len(),
213            ParamsIterKind::Large(ref iter) => iter.len(),
214        }
215    }
216}
217
218#[cfg(test)]
219mod tests {
220    use super::*;
221
222    #[test]
223    fn heap_alloc() {
224        let vec = vec![
225            ("hello", "hello"),
226            ("world", "world"),
227            ("foo", "foo"),
228            ("bar", "bar"),
229            ("baz", "baz"),
230        ];
231
232        let mut params = Params::new();
233        for (key, value) in vec.clone() {
234            params.push(key.as_bytes(), value.as_bytes());
235            assert_eq!(params.get(key), Some(value));
236        }
237
238        match params.kind {
239            ParamsKind::Large(..) => {}
240            _ => panic!(),
241        }
242
243        assert!(params.iter().eq(vec.clone()));
244    }
245
246    #[test]
247    fn stack_alloc() {
248        let vec = vec![("hello", "hello"), ("world", "world"), ("baz", "baz")];
249
250        let mut params = Params::new();
251        for (key, value) in vec.clone() {
252            params.push(key.as_bytes(), value.as_bytes());
253            assert_eq!(params.get(key), Some(value));
254        }
255
256        match params.kind {
257            ParamsKind::Small(..) => {}
258            _ => panic!(),
259        }
260
261        assert!(params.iter().eq(vec.clone()));
262    }
263
264    #[test]
265    fn ignore_array_default() {
266        let params = Params::new();
267        assert!(params.get("").is_none());
268    }
269}