serde_querystring/parsers/
urlencoded.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 parse(slice: &'a [u8]) -> Option<Self> {
33 if *slice.first()? == b'&' {
34 return None;
35 }
36
37 let mut index = 1;
38 while index < slice.len() {
39 match slice[index] {
40 b'&' => break,
41 _ => index += 1,
42 }
43 }
44
45 Some(Self(&slice[1..index]))
46 }
47
48 fn len(&self) -> usize {
49 self.0.len()
50 }
51
52 fn decode_to<'s>(&self, scratch: &'s mut Vec<u8>) -> Reference<'a, 's, [u8]> {
53 parse_bytes(self.0, scratch)
54 }
55}
56
57struct Pair<'a>(Key<'a>, Option<Value<'a>>);
58
59impl<'a> Pair<'a> {
60 fn parse(slice: &'a [u8]) -> Self {
61 let key = Key::parse(slice);
62 let value = Value::parse(&slice[key.len()..]);
63
64 Self(key, value)
65 }
66
67 fn skip_len(&self) -> usize {
71 match &self.1 {
72 Some(v) => self.0.len() + v.len() + 2,
74 None => self.0.len() + 1,
76 }
77 }
78}
79
80pub struct UrlEncodedQS<'a> {
104 pairs: BTreeMap<Cow<'a, [u8]>, Pair<'a>>,
105}
106
107impl<'a> UrlEncodedQS<'a> {
108 pub fn parse(slice: &'a [u8]) -> Self {
110 let mut pairs = BTreeMap::new();
111 let mut scratch = Vec::new();
112
113 let mut index = 0;
114
115 while index < slice.len() {
116 let pair = Pair::parse(&slice[index..]);
117 index += pair.skip_len();
118
119 let decoded_key = pair.0.decode(&mut scratch);
120
121 if let Some(old_pair) = pairs.get_mut(decoded_key.as_ref()) {
122 *old_pair = pair;
123 } else {
124 pairs.insert(decoded_key.into_cow(), pair);
125 }
126 }
127
128 Self { pairs }
129 }
130
131 pub fn keys(&self) -> Vec<&Cow<'a, [u8]>> {
133 self.pairs.keys().collect()
134 }
135
136 pub fn value(&self, key: &'a [u8]) -> Option<Option<Cow<'a, [u8]>>> {
144 let mut scratch = Vec::new();
145 self.pairs
146 .get(key)
147 .map(|p| p.1.as_ref().map(|v| v.decode_to(&mut scratch).into_cow()))
148 }
149}
150
151#[cfg(feature = "serde")]
152mod de {
153 use _serde::Deserialize;
154
155 use crate::de::{
156 Error, QSDeserializer,
157 __implementors::{DecodedSlice, RawSlice},
158 };
159
160 use super::UrlEncodedQS;
161
162 impl<'a> UrlEncodedQS<'a> {
163 pub fn deserialize<T: Deserialize<'a>>(self) -> Result<T, Error> {
165 T::deserialize(QSDeserializer::new(self.into_iter()))
166 }
167
168 pub(crate) fn into_iter(
169 self,
170 ) -> impl Iterator<Item = (DecodedSlice<'a>, Option<RawSlice<'a>>)> {
171 self.pairs
172 .into_iter()
173 .map(|(key, pair)| (DecodedSlice(key), pair.1.map(|v| RawSlice(v.0))))
174 }
175 }
176}
177
178#[cfg(test)]
179mod tests {
180 use std::borrow::Cow;
181
182 use super::UrlEncodedQS;
183
184 #[test]
185 fn parse_pair() {
186 let slice = b"key=value";
187
188 let parser = UrlEncodedQS::parse(slice);
189
190 assert_eq!(parser.keys(), vec![&Cow::Borrowed(b"key")]);
191 assert_eq!(
192 parser.value(b"key"),
193 Some(Some(Cow::Borrowed("value".as_bytes())))
194 );
195 }
196
197 #[test]
198 fn parse_multiple_pairs() {
199 let slice = b"foo=bar&foobar=baz&qux=box";
200
201 let parser = UrlEncodedQS::parse(slice);
202
203 assert_eq!(parser.value(b"foo"), Some(Some("bar".as_bytes().into())));
204 assert_eq!(parser.value(b"foobar"), Some(Some("baz".as_bytes().into())));
205 assert_eq!(parser.value(b"qux"), Some(Some("box".as_bytes().into())));
206 }
207
208 #[test]
209 fn parse_no_value() {
210 let slice = b"foo&foobar=&foo2";
211
212 let parser = UrlEncodedQS::parse(slice);
213
214 assert_eq!(parser.value(b"foo3"), None);
215 assert_eq!(parser.value(b"foo2"), Some(None));
216 assert_eq!(parser.value(b"foo"), Some(None));
217 assert_eq!(parser.value(b"foobar"), Some(Some("".as_bytes().into())));
218 }
219
220 #[test]
221 fn parse_multiple_values() {
222 let slice = b"foo=bar&foo=baz&foo=foobar&foo&foo=";
223
224 let parser = UrlEncodedQS::parse(slice);
225
226 assert_eq!(parser.value(b"foo"), Some(Some("".as_bytes().into())));
227 }
228}