rocket/form/name/
view.rs

1use crate::form::name::*;
2
3/// A sliding-prefix view into a [`Name`].
4///
5/// A [`NameView`] maintains a sliding key view into a [`Name`]. The current key
6/// ([`key()`]) can be [`shift()`ed](NameView::shift()) one key to the right.
7/// The `Name` prefix including the current key can be extracted via
8/// [`as_name()`] and the prefix _not_ including the current key via
9/// [`parent()`].
10///
11/// [`key()`]: NameView::key()
12/// [`as_name()`]: NameView::as_name()
13/// [`parent()`]: NameView::parent()
14///
15/// This is best illustrated via an example:
16///
17/// ```rust
18/// use rocket::form::name::NameView;
19///
20/// // The view begins at the first key. Illustrated: `(a).b[c:d]` where
21/// // parenthesis enclose the current key.
22/// let mut view = NameView::new("a.b[c:d]");
23/// assert_eq!(view.key().unwrap(), "a");
24/// assert_eq!(view.as_name(), "a");
25/// assert_eq!(view.parent(), None);
26///
27/// // Shifted once to the right views the second key: `a.(b)[c:d]`.
28/// view.shift();
29/// assert_eq!(view.key().unwrap(), "b");
30/// assert_eq!(view.as_name(), "a.b");
31/// assert_eq!(view.parent().unwrap(), "a");
32///
33/// // Shifting again now has predictable results: `a.b[(c:d)]`.
34/// view.shift();
35/// assert_eq!(view.key().unwrap(), "c:d");
36/// assert_eq!(view.as_name(), "a.b[c:d]");
37/// assert_eq!(view.parent().unwrap(), "a.b");
38///
39/// // Shifting past the end means we have no further keys.
40/// view.shift();
41/// assert_eq!(view.key(), None);
42/// assert_eq!(view.key_lossy(), "");
43/// assert_eq!(view.as_name(), "a.b[c:d]");
44/// assert_eq!(view.parent().unwrap(), "a.b[c:d]");
45///
46/// view.shift();
47/// assert_eq!(view.key(), None);
48/// assert_eq!(view.as_name(), "a.b[c:d]");
49/// assert_eq!(view.parent().unwrap(), "a.b[c:d]");
50/// ```
51///
52/// # Equality
53///
54/// `PartialEq`, `Eq`, and `Hash` all operate on the name prefix including the
55/// current key. Only key values are compared; delimiters are insignificant.
56/// Again, illustrated via examples:
57///
58/// ```rust
59/// use rocket::form::name::NameView;
60///
61/// let mut view = NameView::new("a.b[c:d]");
62/// assert_eq!(view, "a");
63///
64/// // Shifted once to the right views the second key: `a.(b)[c:d]`.
65/// view.shift();
66/// assert_eq!(view.key().unwrap(), "b");
67/// assert_eq!(view.as_name(), "a.b");
68/// assert_eq!(view, "a.b");
69/// assert_eq!(view, "a[b]");
70///
71/// // Shifting again now has predictable results: `a.b[(c:d)]`.
72/// view.shift();
73/// assert_eq!(view, "a.b[c:d]");
74/// assert_eq!(view, "a.b.c:d");
75/// assert_eq!(view, "a[b].c:d");
76/// assert_eq!(view, "a[b]c:d");
77/// ```
78#[derive(Copy, Clone)]
79pub struct NameView<'v> {
80    name: &'v Name,
81    start: usize,
82    end: usize,
83}
84
85impl<'v> NameView<'v> {
86    /// Initializes a new `NameView` at the first key of `name`.
87    ///
88    /// # Example
89    ///
90    /// ```rust
91    /// use rocket::form::name::NameView;
92    ///
93    /// let mut view = NameView::new("a.b[c:d]");
94    /// assert_eq!(view.key().unwrap(), "a");
95    /// assert_eq!(view.as_name(), "a");
96    /// assert_eq!(view.parent(), None);
97    /// ```
98    pub fn new<N: Into<&'v Name>>(name: N) -> Self {
99        let mut view = NameView { name: name.into(), start: 0, end: 0 };
100        view.shift();
101        view
102    }
103
104    /// Shifts the current key once to the right.
105    ///
106    /// # Examples
107    ///
108    /// ```rust
109    /// use rocket::form::name::NameView;
110    ///
111    /// let mut view = NameView::new("a.b[c:d][d.e]");
112    /// assert_eq!(view.key().unwrap(), "a");
113    ///
114    /// view.shift();
115    /// assert_eq!(view.key().unwrap(), "b");
116    ///
117    /// view.shift();
118    /// assert_eq!(view.key().unwrap(), "c:d");
119    ///
120    /// view.shift();
121    /// assert_eq!(view.key().unwrap(), "d.e");
122    /// ```
123    ///
124    /// Malformed strings can have interesting results:
125    ///
126    /// ```rust
127    /// use rocket::form::name::NameView;
128    ///
129    /// let mut view = NameView::new("a[c.d");
130    /// assert_eq!(view.key_lossy(), "a");
131    ///
132    /// view.shift();
133    /// assert_eq!(view.key_lossy(), "c.d");
134    ///
135    /// let mut view = NameView::new("a[c[.d]");
136    /// assert_eq!(view.key_lossy(), "a");
137    ///
138    /// view.shift();
139    /// assert_eq!(view.key_lossy(), "c[.d");
140    ///
141    /// view.shift();
142    /// assert_eq!(view.key(), None);
143    ///
144    /// let mut view = NameView::new("foo[c[.d]]");
145    /// assert_eq!(view.key_lossy(), "foo");
146    ///
147    /// view.shift();
148    /// assert_eq!(view.key_lossy(), "c[.d");
149    ///
150    /// view.shift();
151    /// assert_eq!(view.key_lossy(), "]");
152    ///
153    /// view.shift();
154    /// assert_eq!(view.key(), None);
155    /// ```
156    pub fn shift(&mut self) {
157        const START_DELIMS: &[char] = &['.', '['];
158
159        let string = &self.name[self.end..];
160        let bytes = string.as_bytes();
161        let shift = match bytes.get(0) {
162            None | Some(b'=') => 0,
163            Some(b'[') => match memchr::memchr(b']', bytes) {
164                Some(j) => j + 1,
165                None => bytes.len(),
166            },
167            Some(b'.') => match string[1..].find(START_DELIMS) {
168                Some(j) => j + 1,
169                None => bytes.len(),
170            },
171            _ => match string.find(START_DELIMS) {
172                Some(j) => j,
173                None => bytes.len()
174            }
175        };
176
177        debug_assert!(self.end + shift <= self.name.len());
178        *self = NameView {
179            name: self.name,
180            start: self.end,
181            end: self.end + shift,
182        };
183    }
184
185    /// Returns the key currently viewed by `self` if it is non-empty.
186    ///
187    /// ```text
188    ///                 food.bart[bar:foo].blam[0_0][][1000]=some-value
189    /// name            |----------------------------------|
190    /// non-empty key   |--| |--| |-----|  |--| |-|     |--|
191    /// empty key                                  |-|
192    /// ```
193    ///
194    /// # Example
195    ///
196    /// ```rust
197    /// use rocket::form::name::NameView;
198    ///
199    /// let mut view = NameView::new("a[b]");
200    /// assert_eq!(view.key().unwrap(), "a");
201    ///
202    /// view.shift();
203    /// assert_eq!(view.key().unwrap(), "b");
204    ///
205    /// view.shift();
206    /// assert_eq!(view.key(), None);
207    /// # view.shift(); assert_eq!(view.key(), None);
208    /// # view.shift(); assert_eq!(view.key(), None);
209    /// ```
210    pub fn key(&self) -> Option<&'v Key> {
211        let lossy_key = self.key_lossy();
212        if lossy_key.is_empty() {
213            return None;
214        }
215
216        Some(lossy_key)
217    }
218
219    /// Returns the key currently viewed by `self`, even if it is non-empty.
220    ///
221    /// ```text
222    ///                 food.bart[bar:foo].blam[0_0][][1000]=some-value
223    /// name            |----------------------------------|
224    /// non-empty key   |--| |--| |-----|  |--| |-|     |--|
225    /// empty key                                  |-|
226    /// ```
227    ///
228    /// # Example
229    ///
230    /// ```rust
231    /// use rocket::form::name::NameView;
232    ///
233    /// let mut view = NameView::new("a[b]");
234    /// assert_eq!(view.key_lossy(), "a");
235    ///
236    /// view.shift();
237    /// assert_eq!(view.key_lossy(), "b");
238    ///
239    /// view.shift();
240    /// assert_eq!(view.key_lossy(), "");
241    /// # view.shift(); assert_eq!(view.key_lossy(), "");
242    /// # view.shift(); assert_eq!(view.key_lossy(), "");
243    /// ```
244    pub fn key_lossy(&self) -> &'v Key {
245        let view = &self.name[self.start..self.end];
246        let key = match view.as_bytes().get(0) {
247            Some(b'.') => &view[1..],
248            Some(b'[') if view.ends_with(']') => &view[1..view.len() - 1],
249            Some(b'[') if self.is_at_last() => &view[1..],
250            _ => view
251        };
252
253        key.as_str().into()
254    }
255
256    /// Returns the `Name` _up to and including_ the current key.
257    ///
258    /// # Example
259    ///
260    /// ```rust
261    /// use rocket::form::name::NameView;
262    ///
263    /// let mut view = NameView::new("a[b]");
264    /// assert_eq!(view.as_name(), "a");
265    ///
266    /// view.shift();
267    /// assert_eq!(view.as_name(), "a[b]");
268    /// # view.shift(); assert_eq!(view.as_name(), "a[b]");
269    /// # view.shift(); assert_eq!(view.as_name(), "a[b]");
270    /// ```
271    pub fn as_name(&self) -> &'v Name {
272        &self.name[..self.end]
273    }
274
275    /// Returns the `Name` _prior to_ the current key.
276    ///
277    /// # Example
278    ///
279    /// ```rust
280    /// use rocket::form::name::NameView;
281    ///
282    /// let mut view = NameView::new("a[b]");
283    /// assert_eq!(view.parent(), None);
284    ///
285    /// view.shift();
286    /// assert_eq!(view.parent().unwrap(), "a");
287    ///
288    /// view.shift();
289    /// assert_eq!(view.parent().unwrap(), "a[b]");
290    /// # view.shift(); assert_eq!(view.parent().unwrap(), "a[b]");
291    /// # view.shift(); assert_eq!(view.parent().unwrap(), "a[b]");
292    /// ```
293    pub fn parent(&self) -> Option<&'v Name> {
294        if self.start > 0 {
295            Some(&self.name[..self.start])
296        } else {
297            None
298        }
299    }
300
301    /// Returns the underlying `Name`.
302    ///
303    /// # Example
304    ///
305    /// ```rust
306    /// use rocket::form::name::NameView;
307    ///
308    /// let mut view = NameView::new("a[b]");
309    /// assert_eq!(view.source(), "a[b]");
310    ///
311    /// view.shift();
312    /// assert_eq!(view.source(), "a[b]");
313    ///
314    /// view.shift();
315    /// assert_eq!(view.source(), "a[b]");
316    ///
317    /// # view.shift(); assert_eq!(view.source(), "a[b]");
318    /// # view.shift(); assert_eq!(view.source(), "a[b]");
319    /// ```
320    pub fn source(&self) -> &'v Name {
321        self.name
322    }
323
324    // This is the last key. The next `shift()` will exhaust `self`.
325    fn is_at_last(&self) -> bool {
326        self.end == self.name.len()
327    }
328
329    // There are no more keys. A `shift` will do nothing.
330    pub(crate) fn exhausted(&self) -> bool {
331        self.start == self.name.len()
332    }
333}
334
335impl std::fmt::Debug for NameView<'_> {
336    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
337        self.as_name().fmt(f)
338    }
339}
340
341impl std::fmt::Display for NameView<'_> {
342    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
343        self.as_name().fmt(f)
344    }
345}
346
347impl<'a, 'b> PartialEq<NameView<'b>> for NameView<'a> {
348    fn eq(&self, other: &NameView<'b>) -> bool {
349        self.as_name() == other.as_name()
350    }
351}
352
353impl<B: PartialEq<Name>> PartialEq<B> for NameView<'_> {
354    fn eq(&self, other: &B) -> bool {
355        other == self.as_name()
356    }
357}
358
359impl Eq for NameView<'_> {  }
360
361impl std::hash::Hash for NameView<'_> {
362    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
363        self.as_name().hash(state)
364    }
365}
366
367impl std::borrow::Borrow<Name> for NameView<'_> {
368    fn borrow(&self) -> &Name {
369        self.as_name()
370    }
371}