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