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}