deser_urlencoded/lib.rs
1//! Query strings and form data (`application/x-www-form-urlencoded`) for
2//! deser.
3//!
4//! ```rust
5//! use deser::{Deserialize, Serialize};
6//!
7//! #[derive(Debug, Deserialize, Serialize)]
8//! struct Search {
9//! q: String,
10//! page: Option<u32>,
11//! #[deser(default)]
12//! tags: Vec<String>,
13//! }
14//!
15//! let search: Search =
16//! deser_urlencoded::from_str("q=rust+serde&tags=a&tags=b").unwrap();
17//! assert_eq!(search.q, "rust serde");
18//! assert_eq!(search.page, None);
19//! assert_eq!(search.tags, ["a", "b"]);
20//!
21//! let query = deser_urlencoded::to_string(&search).unwrap();
22//! assert_eq!(query, "q=rust+serde&tags=a&tags=b");
23//! ```
24//!
25//! # Data Model
26//!
27//! Everything in a query string is text, the type of a value is only known
28//! to the type it's deserialized into. Keys and values are therefore
29//! passed on as [lexical atoms](deser_core::Atom::Lexical) which are parsed by
30//! the types they are delivered to: numbers parse them, strings take them
31//! as they are. Lexical atoms are retained when values are buffered, so
32//! flattened structs and internally tagged and untagged enums work as well:
33//!
34//! ```rust
35//! use deser::Deserialize;
36//!
37//! #[derive(Debug, Deserialize, PartialEq)]
38//! struct Paginate {
39//! limit: u32,
40//! offset: u32,
41//! }
42//!
43//! #[derive(Debug, Deserialize, PartialEq)]
44//! #[deser(tag = "type", rename_all = "lowercase")]
45//! enum Query {
46//! Users {
47//! active: bool,
48//! #[deser(flatten)]
49//! paginate: Paginate,
50//! },
51//! }
52//!
53//! let query: Query = deser_urlencoded::from_str(
54//! "limit=10&offset=20&active=yes&type=users",
55//! )
56//! .unwrap();
57//! assert_eq!(
58//! query,
59//! Query::Users {
60//! active: true,
61//! paginate: Paginate { limit: 10, offset: 20 },
62//! }
63//! );
64//! ```
65//!
66//! The input is a map whose keys can repeat (a [multimap]). Keys can be
67//! nested (see [`Nesting`]):
68//!
69//! | query string | deser |
70//! |----------------------------|-----------------------------------------------------|
71//! | `a=1` | `{"a": "1"}` |
72//! | `a=1&a=2` | `{"a": "1", "a": "2"}` (a repeated key) |
73//! | `a[]=1&a[]=2` | `{"a": ["1", "2"]}` |
74//! | `a[0]=1&a[1]=2` | `{"a": ["1", "2"]}` |
75//! | `a[1]=1&a[3]=2` | `{"a": {"1": "1", "3": "2"}}` |
76//! | `a[b]=1&a[c][]=2` | `{"a": {"b": "1", "c": ["2"]}}` |
77//! | `a[0][b]=1&a[1][b]=2` | `{"a": [{"b": "1"}, {"b": "2"}]}` |
78//!
79//! Fields and map values that are collections (like `Vec<T>` or
80//! `HashSet<T>`) collect the values of all occurrences of their key, also
81//! if other keys are between them. A key given once is a collection of one
82//! value and a missing key an empty collection. Types that expect a single
83//! value receive the last one unless the [`Context`](deser_core::Context) has
84//! another [`DuplicateKeys`](deser_core::de::DuplicateKeys) policy:
85//!
86//! ```
87//! use deser::de::DuplicateKeys;
88//! use deser::Context;
89//!
90//! #[derive(deser::Deserialize)]
91//! struct Query {
92//! page: u32,
93//! }
94//!
95//! let query: Query = deser_urlencoded::from_str("page=1&page=2").unwrap();
96//! assert_eq!(query.page, 2);
97//!
98//! let strict = deser_urlencoded::DeserializerConfig::builder()
99//! .context(Context::with(DuplicateKeys::Error))
100//! .build();
101//! assert!(strict.from_str::<Query>("page=1&page=2").is_err());
102//! ```
103//!
104//! `a[]=1` is always a sequence. Indexes that start at `0` and have no
105//! gaps are sequences, other indexes are map keys.
106//!
107//! ```rust
108//! #[derive(deser::Deserialize, Debug, PartialEq)]
109//! struct Filter {
110//! tag: Vec<String>,
111//! page: u32,
112//! user: Vec<String>,
113//! }
114//!
115//! assert_eq!(
116//! deser_urlencoded::from_str::<Filter>("tag=a&page=2&tag=b").unwrap(),
117//! Filter { tag: vec!["a".into(), "b".into()], page: 2, user: vec![] },
118//! );
119//! ```
120//!
121//! The URL standard makes no difference between `a` and `a=`, both are the
122//! empty value. Empty values are `None` for optionals if the type does not
123//! accept them (`page=` is `None` for an `Option<u32>` and `Some("")` for an
124//! `Option<String>`). Booleans accept `true`, `yes`, `on` and `1` and
125//! `false`, `no`, `off` and `0` (HTML checkboxes send `on`). Flags which
126//! are switched on by giving their key (like `?recursive`) use the
127//! [`Flag`](deser_core::adapters::Flag) adapter:
128//!
129//! ```rust
130//! use deser::adapters::Flag;
131//!
132//! #[derive(deser::Deserialize)]
133//! struct Tree {
134//! #[deser(as = Flag)]
135//! recursive: bool,
136//! }
137//!
138//! assert!(
139//! deser_urlencoded::from_str::<Tree>("recursive").unwrap().recursive
140//! );
141//! assert!(
142//! deser_urlencoded::from_str::<Tree>("recursive=").unwrap().recursive
143//! );
144//! assert!(
145//! !deser_urlencoded::from_str::<Tree>("recursive=0").unwrap().recursive
146//! );
147//! assert!(!deser_urlencoded::from_str::<Tree>("").unwrap().recursive);
148//! ```
149//!
150//! Keys and values are percent-decoded (`+` is a space) before the keys are
151//! split, so `a%5B%5D=1` (as sent by browsers) is the same as `a[]=1`.
152//! Values which are not UTF-8 after decoding are passed on as bytes. A
153//! leading `?` is ignored. Keys which do not follow the syntax of the
154//! nesting (like `a[b`) are taken as they are. A key that has a value and
155//! nested keys (`a=1&a[b]=2`) is an error.
156//!
157//! Serializing works the other way around (see [`SerializerConfig`]), how
158//! sequences are written can be configured (see [`ArrayFormat`]).
159//!
160//! [multimap]: deser_core::ContainerShape::set_multimap
161//!
162//! # Streams
163//!
164//! Form data is read from a [`Read`](std::io::Read) with [`from_reader`]
165//! and written to a [`Write`](std::io::Write) with [`to_writer`]. The
166//! configurations also create readers and writers of
167//! [`deser::io`](deser_core::io) ([`DeserializerConfig::reader`] and
168//! [`SerializerConfig::writer`]), the stream serializer ([`Serializer`])
169//! and deserializer ([`StreamDeserializer`]) work with other kinds of IO
170//! too (for instance async runtimes with `deser-tokio`). The whole stream
171//! is read before it's parsed.
172//!
173//! # Features
174//!
175//! * `io` (enabled by default): reading and writing streams of the
176//! standard library, see [streams](#streams).
177//! * `speedups` (enabled by default): has no effect yet, it exists so
178//! that all formats have it.
179#![doc(html_logo_url = "https://raw.githubusercontent.com/mitsuhiko/deser/main/artwork/logo.svg")]
180
181mod de;
182mod encoding;
183mod ser;
184mod stream;
185
186pub use self::de::{Deserializer, DeserializerConfig, DeserializerConfigBuilder};
187#[cfg(feature = "io")]
188pub use self::ser::to_writer;
189pub use self::ser::{
190 ArrayFormat, Serializer, SerializerConfig, SerializerConfigBuilder, to_string,
191};
192pub use self::stream::StreamDeserializer;
193#[cfg(feature = "io")]
194pub use self::stream::from_reader;
195
196use deser_core::Error;
197use deser_core::de::Deserialize;
198
199/// How keys are nested.
200///
201/// ```
202/// use std::collections::BTreeMap;
203/// use deser_urlencoded::{DeserializerConfig, Nesting};
204///
205/// type Nested = BTreeMap<String, BTreeMap<String, u32>>;
206///
207/// let value: Nested = deser_urlencoded::from_str("a[b]=1").unwrap();
208/// assert_eq!(value["a"]["b"], 1);
209///
210/// let dots = DeserializerConfig::builder().nesting(Nesting::Dots).build();
211/// let value: Nested = dots.from_str("a.b=1").unwrap();
212/// assert_eq!(value["a"]["b"], 1);
213///
214/// let flat = DeserializerConfig::builder().nesting(Nesting::Flat).build();
215/// let value: BTreeMap<String, u32> = flat.from_str("a[b]=1").unwrap();
216/// assert_eq!(value["a[b]"], 1);
217/// ```
218#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
219#[non_exhaustive]
220pub enum Nesting {
221 /// Keys are not nested, they are taken as they are.
222 Flat,
223 /// Nested keys are in brackets: `a[b][0]=1` and `a[]=1`.
224 ///
225 /// This is how Rails, PHP and the `qs` library of Node write nested
226 /// keys.
227 #[default]
228 Brackets,
229 /// Nested keys are separated with dots: `a.b.0=1`.
230 Dots,
231}
232
233/// Deserializes a value from a query string.
234///
235/// This uses the default [`DeserializerConfig`], see the [crate
236/// documentation](crate) for how query strings map onto deser.
237///
238/// ```
239/// use std::collections::BTreeMap;
240///
241/// let value: BTreeMap<String, Vec<u32>> =
242/// deser_urlencoded::from_str("a=1&a=2&b=3").unwrap();
243/// assert_eq!(value["a"], [1, 2]);
244/// assert_eq!(value["b"], [3]);
245/// ```
246pub fn from_str<'de, T: Deserialize<'de>>(s: &'de str) -> Result<T, Error> {
247 DeserializerConfig::new().from_str(s)
248}
249
250/// Deserializes a value from a query string in a byte slice.
251///
252/// The input has to be UTF-8.
253///
254/// ```
255/// use std::collections::BTreeMap;
256///
257/// let value: BTreeMap<String, String> =
258/// deser_urlencoded::from_slice(b"a=%C3%A4").unwrap();
259/// assert_eq!(value["a"], "\u{e4}");
260/// ```
261pub fn from_slice<'de, T: Deserialize<'de>>(bytes: &'de [u8]) -> Result<T, Error> {
262 DeserializerConfig::new().from_slice(bytes)
263}