routefinder/
captures.rs

1use smartcow::SmartCow;
2use std::{
3    borrow::Cow,
4    iter::FromIterator,
5    ops::{Deref, DerefMut},
6};
7
8/// An individual key-value pair
9#[derive(Debug, Default)]
10pub struct Capture<'key, 'value> {
11    key: SmartCow<'key>,
12    value: SmartCow<'value>,
13}
14
15impl<'key, 'value> Capture<'key, 'value> {
16    /// Build a new Capture from the provided key and value. Passing a
17    /// &str here is preferable, but a String will also work.
18    pub fn new(key: impl Into<Cow<'key, str>>, value: impl Into<Cow<'value, str>>) -> Self {
19        Self {
20            key: key.into().into(),
21            value: value.into().into(),
22        }
23    }
24
25    /// returns the name of this capture
26    pub fn name(&self) -> &str {
27        &self.key
28    }
29
30    /// returns the value of this capture
31    pub fn value(&self) -> &str {
32        &self.value
33    }
34
35    /// transforms this potentially-borrowed Capture into a 'static
36    /// capture that can outlive the source data. This allocates new
37    /// strings if needed, and should be avoided unless necessary for
38    /// a particular application
39    pub fn into_owned(self) -> Capture<'static, 'static> {
40        Capture {
41            key: self.key.into_owned(),
42            value: self.value.into_owned(),
43        }
44    }
45}
46
47/// Captured params and a wildcard
48#[derive(Debug, Default)]
49pub struct Captures<'keys, 'values> {
50    pub(crate) params: Vec<Capture<'keys, 'values>>,
51    pub(crate) wildcard: Option<SmartCow<'values>>,
52}
53
54impl<'keys, 'values> Captures<'keys, 'values> {
55    /// Builds a new empty Captures
56    pub fn new() -> Self {
57        Self::default()
58    }
59
60    /// Transforms this Captures into a 'static Captures which can
61    /// outlive the source data. This allocates new strings if needed,
62    /// and should be avoided unless necessary for a particular
63    /// application
64    pub fn into_owned(self) -> Captures<'static, 'static> {
65        Captures {
66            params: self.params.into_iter().map(|c| c.into_owned()).collect(),
67            wildcard: self.wildcard.map(SmartCow::into_owned),
68        }
69    }
70
71    /// returns a slice of captures
72    pub fn params(&self) -> &[Capture] {
73        &self.params[..]
74    }
75
76    /// set the captured wildcard to the provided &str or
77    /// String. Prefer passing a &str if available.
78    pub fn set_wildcard(&mut self, wildcard: impl Into<Cow<'values, str>>) {
79        self.wildcard = Some(wildcard.into().into());
80    }
81
82    /// returns what the * wildcard matched, if any
83    pub fn wildcard(&self) -> Option<&str> {
84        self.wildcard.as_deref()
85    }
86
87    /// checks the list of params for a matching key
88    pub fn get(&self, key: &str) -> Option<&str> {
89        self.params.iter().find_map(|capture| {
90            if capture.key == key {
91                Some(&*capture.value)
92            } else {
93                None
94            }
95        })
96    }
97
98    /// Add the provided Capture (or capture-like) to the end of the params
99    pub fn push(&mut self, capture: impl Into<Capture<'keys, 'values>>) {
100        self.params.push(capture.into());
101    }
102
103    /// Combine two captures
104    pub fn append(&mut self, mut captures: Captures<'keys, 'values>) {
105        self.params.append(&mut captures.params);
106        self.wildcard = captures.wildcard;
107    }
108
109    /// Iterate over params as str pairs
110    pub fn iter(&self) -> Iter<'_, '_, '_> {
111        self.into()
112    }
113}
114
115impl<'keys, 'values> Deref for Captures<'keys, 'values> {
116    type Target = Vec<Capture<'keys, 'values>>;
117
118    fn deref(&self) -> &Self::Target {
119        &self.params
120    }
121}
122
123impl<'keys, 'values> DerefMut for Captures<'keys, 'values> {
124    fn deref_mut(&mut self) -> &mut Self::Target {
125        &mut self.params
126    }
127}
128
129impl<'key, 'value> From<(&'key str, &'value str)> for Capture<'key, 'value> {
130    fn from(kv: (&'key str, &'value str)) -> Self {
131        Self {
132            key: kv.0.into(),
133            value: kv.1.into(),
134        }
135    }
136}
137
138impl<'pair, 'key: 'pair, 'value: 'pair> From<&'pair (&'key str, &'value str)>
139    for Capture<'key, 'value>
140{
141    fn from(kv: &'pair (&'key str, &'value str)) -> Self {
142        Self {
143            key: kv.0.into(),
144            value: kv.1.into(),
145        }
146    }
147}
148
149impl<'keys, 'values, F> From<F> for Captures<'keys, 'values>
150where
151    F: IntoIterator<Item = (&'keys str, &'values str)>,
152{
153    fn from(f: F) -> Self {
154        f.into_iter().collect()
155    }
156}
157
158impl<'keys, 'values, I: Into<Capture<'keys, 'values>>> FromIterator<I>
159    for Captures<'keys, 'values>
160{
161    fn from_iter<T: IntoIterator<Item = I>>(iter: T) -> Self {
162        Self {
163            params: iter.into_iter().map(Into::into).collect(),
164            wildcard: None,
165        }
166    }
167}
168
169impl<'keys, 'values, I: Into<Capture<'keys, 'values>>> Extend<I> for Captures<'keys, 'values> {
170    fn extend<T: IntoIterator<Item = I>>(&mut self, iter: T) {
171        self.params.extend(iter.into_iter().map(Into::into));
172    }
173}
174
175impl<'keys, 'values> IntoIterator for Captures<'keys, 'values> {
176    type Item = Capture<'keys, 'values>;
177
178    type IntoIter = std::vec::IntoIter<Self::Item>;
179
180    fn into_iter(self) -> Self::IntoIter {
181        self.params.into_iter()
182    }
183}
184
185#[derive(Debug)]
186pub struct Iter<'captures: 'keys + 'values, 'keys, 'values>(
187    std::slice::Iter<'captures, Capture<'keys, 'values>>,
188);
189impl<'captures: 'keys + 'values, 'keys, 'values> Iterator for Iter<'captures, 'keys, 'values> {
190    type Item = (&'keys str, &'values str);
191
192    fn next(&mut self) -> Option<Self::Item> {
193        self.0.next().map(|c| (c.name(), c.value()))
194    }
195}
196
197impl<'captures: 'keys + 'values, 'keys, 'values> From<&'captures Captures<'keys, 'values>>
198    for Iter<'captures, 'keys, 'values>
199{
200    fn from(value: &'captures Captures<'keys, 'values>) -> Self {
201        Iter(value.params.iter())
202    }
203}
204
205impl<'captures: 'keys + 'values, 'keys, 'values> IntoIterator
206    for &'captures Captures<'keys, 'values>
207{
208    type Item = (&'keys str, &'values str);
209
210    type IntoIter = Iter<'captures, 'keys, 'values>;
211
212    fn into_iter(self) -> Self::IntoIter {
213        self.into()
214    }
215}