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