serde_querystring/parsers/
delimiter.rs

1use std::{borrow::Cow, collections::BTreeMap};
2
3use crate::decode::{parse_bytes, Reference};
4
5struct Key<'a>(&'a [u8]);
6
7impl<'a> Key<'a> {
8    fn parse(slice: &'a [u8]) -> Self {
9        let mut index = 0;
10        while index < slice.len() {
11            match slice[index] {
12                b'&' | b'=' => break,
13                _ => index += 1,
14            }
15        }
16
17        Self(&slice[..index])
18    }
19
20    fn len(&self) -> usize {
21        self.0.len()
22    }
23
24    fn decode<'s>(&self, scratch: &'s mut Vec<u8>) -> Reference<'a, 's, [u8]> {
25        parse_bytes(self.0, scratch)
26    }
27}
28
29struct Value<'a>(&'a [u8]);
30
31impl<'a> Value<'a> {
32    fn decode<'s>(&self, scratch: &'s mut Vec<u8>) -> Reference<'a, 's, [u8]> {
33        parse_bytes(self.0, scratch)
34    }
35}
36
37#[derive(Default)]
38struct Values<'a>(&'a [u8]);
39
40impl<'a> Values<'a> {
41    fn parse(slice: &'a [u8]) -> Option<Self> {
42        if *slice.first()? == b'&' {
43            return None;
44        }
45
46        let mut index = 1;
47        while index < slice.len() {
48            match slice[index] {
49                b'&' => break,
50                _ => index += 1,
51            }
52        }
53
54        Some(Self(&slice[1..index]))
55    }
56
57    fn len(&self) -> usize {
58        self.0.len()
59    }
60
61    fn values(&self, delimiter: u8) -> impl Iterator<Item = Value<'a>> {
62        self.0.split(move |c| *c == delimiter).map(Value)
63    }
64
65    fn decode_to<'s>(&self, scratch: &'s mut Vec<u8>) -> Reference<'a, 's, [u8]> {
66        parse_bytes(self.0, scratch)
67    }
68}
69
70struct Pair<'a>(Key<'a>, Option<Values<'a>>);
71
72impl<'a> Pair<'a> {
73    fn parse(slice: &'a [u8]) -> Self {
74        let key = Key::parse(slice);
75        let value = Values::parse(&slice[key.len()..]);
76
77        Self(key, value)
78    }
79
80    /// It report how many chars we should move forward after this pair, to see a new one.
81    /// It might report invalid result at the end of the slice,
82    /// so calling site should check the validity of resulting index
83    fn skip_len(&self) -> usize {
84        match &self.1 {
85            Some(v) => self.0.len() + v.len() + 2,
86            None => self.0.len() + 1,
87        }
88    }
89}
90
91/// A querystring parser with support for vectors/lists of values by the use of a delimiter(ex: `|`).
92///
93/// # Note
94/// Keys are decoded when calling the `parse` method, but values are lazily decoded when you
95/// call the `value` method for their keys.
96///
97/// # Example
98/// ```rust
99///# use std::borrow::Cow;
100/// use serde_querystring::DelimiterQS;
101///
102/// let slice = b"foo=bar|baz||";
103/// let parser = DelimiterQS::parse(slice, b'|');
104///
105/// // `values` method returns ALL the values as a vector.
106/// assert_eq!(
107///     parser.values(b"foo"),
108///     Some(Some(vec![
109///         "bar".as_bytes().into(),
110///         "baz".as_bytes().into(),
111///         "".as_bytes().into(),
112///         "".as_bytes().into()
113///     ]))
114/// );
115///
116/// // `value` method returns the whole slice as the value without parsing by delimiter.
117/// assert_eq!(parser.value(b"foo"), Some(Some("bar|baz||".as_bytes().into())));
118/// ```
119pub struct DelimiterQS<'a> {
120    pairs: BTreeMap<Cow<'a, [u8]>, Pair<'a>>,
121    delimiter: u8,
122}
123
124impl<'a> DelimiterQS<'a> {
125    /// Parse a slice of bytes into a `DelimiterQS`
126    pub fn parse(slice: &'a [u8], delimiter: u8) -> Self {
127        let mut pairs: BTreeMap<Cow<'a, [u8]>, Pair<'a>> = BTreeMap::new();
128        let mut scratch = Vec::new();
129
130        let mut index = 0;
131
132        while index < slice.len() {
133            let pair = Pair::parse(&slice[index..]);
134            index += pair.skip_len();
135
136            let decoded_key = pair.0.decode(&mut scratch);
137
138            if let Some(old_pair) = pairs.get_mut(decoded_key.as_ref()) {
139                *old_pair = pair;
140            } else {
141                pairs.insert(decoded_key.into_cow(), pair);
142            }
143        }
144
145        Self { pairs, delimiter }
146    }
147
148    /// Returns a vector containing all the keys in querystring.
149    pub fn keys(&self) -> Vec<&Cow<'a, [u8]>> {
150        self.pairs.keys().collect()
151    }
152
153    /// Returns the values assigned to a key(only the last assignment) parsed using delimiter.
154    ///
155    /// It returns `None` if the **key doesn't exist** in the querystring,
156    /// and returns `Some(None)` if the last assignment to a **key doesn't have a value**, ex `"&key&"`
157    ///
158    /// # Note
159    /// Percent decoding the value is done on-the-fly **every time** this function is called.
160    pub fn values(&self, key: &'a [u8]) -> Option<Option<Vec<Cow<'a, [u8]>>>> {
161        let delimiter = self.delimiter;
162        let mut scratch = Vec::new();
163
164        Some(self.pairs.get(key)?.1.as_ref().map(|values| {
165            values
166                .values(delimiter)
167                .map(|v| v.decode(&mut scratch).into_cow())
168                .collect()
169        }))
170    }
171
172    /// Returns the last value assigned to a key without taking delimiters into account
173    ///
174    /// It returns `None` if the **key doesn't exist** in the querystring,
175    /// and returns `Some(None)` if the last assignment to a **key doesn't have a value**, ex `"&key&"`
176    ///
177    /// # Note
178    /// Percent decoding the value is done on-the-fly **every time** this function is called.
179    pub fn value(&self, key: &'a [u8]) -> Option<Option<Cow<'a, [u8]>>> {
180        let mut scratch = Vec::new();
181
182        Some(
183            self.pairs
184                .get(key)?
185                .1
186                .as_ref()
187                .map(|values| values.decode_to(&mut scratch).into_cow()),
188        )
189    }
190}
191
192#[cfg(feature = "serde")]
193mod de {
194    use _serde::Deserialize;
195
196    use crate::de::{
197        Error, QSDeserializer,
198        __implementors::{DecodedSlice, IntoRawSlices, RawSlice},
199    };
200
201    use super::DelimiterQS;
202
203    impl<'a> DelimiterQS<'a> {
204        /// Deserialize the parsed slice into T
205        pub fn deserialize<T: Deserialize<'a>>(self) -> Result<T, Error> {
206            T::deserialize(QSDeserializer::new(self.into_iter()))
207        }
208
209        pub(crate) fn into_iter(
210            self,
211        ) -> impl Iterator<Item = (DecodedSlice<'a>, SeparatorValues<'a>)> {
212            let delimiter = self.delimiter;
213            self.pairs.into_iter().map(move |(key, pair)| {
214                (
215                    DecodedSlice(key),
216                    SeparatorValues::from_slice(pair.1.map(|v| v.0).unwrap_or_default(), delimiter),
217                )
218            })
219        }
220    }
221
222    pub(crate) struct SeparatorValues<'a> {
223        slice: &'a [u8],
224        delimiter: u8,
225    }
226
227    impl<'a> SeparatorValues<'a> {
228        fn from_slice(slice: &'a [u8], delimiter: u8) -> Self {
229            Self { slice, delimiter }
230        }
231    }
232
233    impl<'a> IntoRawSlices<'a> for SeparatorValues<'a> {
234        type SizedIterator = SizedValuesIterator<'a>;
235
236        type UnSizedIterator = SizedValuesIterator<'a>;
237
238        #[inline]
239        fn into_sized_iterator(self, size: usize) -> Result<Self::SizedIterator, crate::de::Error> {
240            Ok(SizedValuesIterator::new(
241                self.slice,
242                self.delimiter,
243                Some(size),
244            ))
245        }
246
247        #[inline]
248        fn into_unsized_iterator(self) -> Self::UnSizedIterator {
249            SizedValuesIterator::new(self.slice, self.delimiter, None)
250        }
251
252        #[inline]
253        fn into_single_slice(self) -> RawSlice<'a> {
254            RawSlice(self.slice)
255        }
256    }
257
258    pub struct SizedValuesIterator<'a> {
259        slice: &'a [u8],
260        delimiter: u8,
261        remaining: Option<usize>,
262        index: usize,
263    }
264
265    impl<'a> SizedValuesIterator<'a> {
266        fn new(slice: &'a [u8], delimiter: u8, size: Option<usize>) -> Self {
267            Self {
268                slice,
269                delimiter,
270                remaining: size,
271                index: 0,
272            }
273        }
274
275        #[inline]
276        fn decrease_remaining(&mut self) {
277            if let Some(remaining) = self.remaining {
278                self.remaining = Some(remaining - 1);
279            }
280        }
281    }
282
283    impl<'a> Iterator for SizedValuesIterator<'a> {
284        type Item = RawSlice<'a>;
285
286        fn next(&mut self) -> Option<Self::Item> {
287            if self.index >= self.slice.len() {
288                return None;
289            }
290
291            if let Some(remaining) = self.remaining {
292                match remaining {
293                    0 => {
294                        return None;
295                    }
296                    1 => {
297                        self.remaining = Some(0);
298                        return Some(RawSlice(&self.slice[self.index..]));
299                    }
300                    _ => {}
301                }
302            }
303
304            let start = self.index;
305            for c in &self.slice[self.index..] {
306                if *c == self.delimiter {
307                    let end = self.index;
308                    self.index += 1;
309
310                    self.decrease_remaining();
311                    return Some(RawSlice(&self.slice[start..end]));
312                }
313                self.index += 1;
314            }
315
316            self.decrease_remaining();
317            Some(RawSlice(&self.slice[start..]))
318        }
319    }
320}
321
322#[cfg(test)]
323mod tests {
324    use std::borrow::Cow;
325
326    use super::DelimiterQS;
327
328    #[test]
329    fn parse_pair() {
330        let slice = b"key=value";
331
332        let parser = DelimiterQS::parse(slice, b'|');
333
334        assert_eq!(parser.keys(), vec![&Cow::Borrowed(b"key")]);
335        assert_eq!(
336            parser.values(b"key"),
337            Some(Some(vec![Cow::Borrowed("value".as_bytes())]))
338        );
339        assert_eq!(
340            parser.value(b"key"),
341            Some(Some(Cow::Borrowed("value".as_bytes())))
342        );
343
344        assert_eq!(parser.values(b"test"), None);
345    }
346
347    #[test]
348    fn parse_multiple_pairs() {
349        let slice = b"foo=bar&foobar=baz&qux=box";
350
351        let parser = DelimiterQS::parse(slice, b'|');
352
353        assert_eq!(
354            parser.values(b"foo"),
355            Some(Some(vec!["bar".as_bytes().into()]))
356        );
357        assert_eq!(
358            parser.values(b"foobar"),
359            Some(Some(vec!["baz".as_bytes().into()]))
360        );
361        assert_eq!(
362            parser.values(b"qux"),
363            Some(Some(vec!["box".as_bytes().into()]))
364        );
365    }
366
367    #[test]
368    fn parse_no_value() {
369        let slice = b"foo&foobar=";
370
371        let parser = DelimiterQS::parse(slice, b'|');
372
373        // Expecting a vector of values
374        assert_eq!(parser.values(b"foo"), Some(None));
375        assert_eq!(
376            parser.values(b"foobar"),
377            Some(Some(vec!["".as_bytes().into()]))
378        );
379
380        // Expecting a single value
381        assert_eq!(parser.value(b"foo"), Some(None));
382        assert_eq!(parser.value(b"foobar"), Some(Some("".as_bytes().into())));
383    }
384
385    #[test]
386    fn parse_multiple_values() {
387        let slice = b"foo=bar|baz|foobar||";
388
389        let parser = DelimiterQS::parse(slice, b'|');
390
391        assert_eq!(
392            parser.values(b"foo"),
393            Some(Some(vec![
394                "bar".as_bytes().into(),
395                "baz".as_bytes().into(),
396                "foobar".as_bytes().into(),
397                "".as_bytes().into(),
398                "".as_bytes().into()
399            ]))
400        );
401
402        let slice = b"foo=bar,baz,foobar,,";
403
404        let parser = DelimiterQS::parse(slice, b',');
405
406        assert_eq!(
407            parser.values(b"foo"),
408            Some(Some(vec![
409                "bar".as_bytes().into(),
410                "baz".as_bytes().into(),
411                "foobar".as_bytes().into(),
412                "".as_bytes().into(),
413                "".as_bytes().into()
414            ]))
415        );
416    }
417}