├── .github └── workflows │ └── CI.yml ├── .gitignore ├── .rustfmt.toml ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md ├── benches └── upstream_comparison │ ├── benches.rs │ └── main.rs └── src ├── de.rs ├── de ├── part.rs ├── tests.rs └── val_or_vec.rs ├── lib.rs ├── ser.rs └── ser ├── error.rs ├── key.rs ├── pair.rs ├── part.rs ├── tests.rs └── value.rs /.github/workflows/CI.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | 8 | env: 9 | CARGO_TERM_COLOR: always 10 | RUST_BACKTRACE: 1 11 | 12 | jobs: 13 | style: 14 | name: Check Style 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v3 18 | - uses: dtolnay/rust-toolchain@stable 19 | with: 20 | components: rustfmt 21 | - uses: Swatinem/rust-cache@v2 22 | - run: cargo fmt --check --all -- --check 23 | 24 | test: 25 | name: Test ${{ matrix.rust }} on ${{ matrix.os }} 26 | needs: [style] 27 | strategy: 28 | matrix: 29 | rust: 30 | - stable 31 | - beta 32 | - nightly 33 | os: 34 | - ubuntu-latest 35 | - windows-latest 36 | - macOS-latest 37 | runs-on: ${{ matrix.os }} 38 | steps: 39 | - uses: actions/checkout@v3 40 | - uses: dtolnay/rust-toolchain@master 41 | with: 42 | toolchain: ${{ matrix.rust }} 43 | - uses: Swatinem/rust-cache@v1 44 | - run: cargo test 45 | 46 | test-no-default-features: 47 | name: Test without default features 48 | runs-on: ubuntu-latest 49 | steps: 50 | - uses: actions/checkout@v3 51 | - uses: dtolnay/rust-toolchain@stable 52 | - uses: Swatinem/rust-cache@v1 53 | - run: cargo test --no-default-features 54 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | format_code_in_doc_comments = true 2 | imports_granularity = "Crate" 3 | use_small_heuristics = "Max" 4 | newline_style = "Unix" 5 | reorder_imports = true 6 | use_try_shorthand = true 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.2.7 2 | 3 | Add `Deserializer::from_bytes`. 4 | 5 | # 0.2.6 6 | 7 | Fix deserialization of optional sequences of a single non-string element. 8 | 9 | # 0.2.5 10 | 11 | Add `push_to_string` for serializing a struct to the end of an existing `String` 12 | buffer (instead of allocating a fresh one for the serialized output). 13 | 14 | # 0.2.4 15 | 16 | Fix deserialization of optional sequences of a single element. 17 | 18 | # 0.2.3 19 | 20 | Improve README and crate documentation (now the exact same, instead of just a 21 | single-line description). 22 | 23 | # 0.2.2 24 | 25 | This release only upgrades one of the crates' dev-dependencies. 26 | 27 | # 0.2.1 28 | 29 | This release only upgrades one of the crates' private dependencies. 30 | 31 | # 0.2.0 32 | 33 | Support deserialization of sequences with duplicate keys. 34 | This used to fail, but passes now: 35 | 36 | ```rust 37 | let result = vec![("foo".to_owned(), 1), ("bar".to_owned(), 2), ("foo".to_owned(), 3)]; 38 | assert_eq!(super::from_str("foo=1&bar=2&foo=3"), Ok(result)); 39 | ``` 40 | 41 | This should mainly affect deserialization to a type that's explicitly a sequence, like arrays or `Vec`, 42 | but some other things were changed too so if you are getting unexpected deserialization errors, please open an issue. 43 | 44 | This release has a minimum Rust version of 1.56. 45 | 46 | # 0.1.1 47 | 48 | Support deserialization of `Option`al values to better support forms with optional inputs of non-string types: 49 | 50 | ```rust 51 | #[derive(Deserialize, PartialEq)] 52 | struct MyForm { 53 | field: Option, 54 | } 55 | 56 | // What browsers send when a value is given 57 | assert_eq!(serde_html_form::from_str("field=5").unwrap(), MyForm { field: Some(5) }); 58 | // What browsers send when no value is given 59 | assert_eq!(serde_html_form::from_str("field=").unwrap(), MyForm { field: None }); 60 | // This also works 61 | assert_eq!(serde_html_form::from_str("").unwrap(), MyForm { field: None }); 62 | ``` 63 | 64 | # 0.1.0 65 | 66 | Initial release. 67 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "serde_html_form" 3 | version = "0.2.7" 4 | license = "MIT" 5 | repository = "https://github.com/jplatte/serde_html_form" 6 | description = "(De-)serialization support for the `application/x-www-form-urlencoded` format" 7 | categories = ["encoding", "web-programming"] 8 | keywords = ["serde", "serialization", "urlencoded"] 9 | exclude = ["/.github"] 10 | edition = "2021" 11 | rust-version = "1.56" 12 | 13 | [lib] 14 | bench = false 15 | 16 | [features] 17 | default = ["ryu"] 18 | 19 | [dependencies] 20 | # Percent encoding and mapping of query string to pair of key-values 21 | form_urlencoded = "1.0.1" 22 | # Used for internal buffering during deserialization 23 | indexmap = "2.0.0" 24 | # Fast integer serialization 25 | itoa = "1.0.1" 26 | # Fast and better-looking float serialization 27 | ryu = { version = "1.0.9", optional = true } 28 | # Contains the Serializer and Deserializer traits 29 | serde = "1.0.136" 30 | 31 | [dev-dependencies] 32 | # For the assert_matches! macro 33 | assert_matches2 = "0.1.0" 34 | # Some tests use structs that derive Serialize / Deserialize 35 | serde = { version = "1.0.136", features = ["derive"] } 36 | 37 | # For benchmarks 38 | divan = "0.1.11" 39 | serde_urlencoded = "0.7.1" 40 | 41 | [lints.rust] 42 | unexpected_cfgs = { level = "warn", check-cfg = ['cfg(rust_analyzer)'] } 43 | 44 | [[bench]] 45 | name = "upstream_comparison" 46 | harness = false 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `serde_html_form` 2 | 3 | (De-)serialization support for the `application/x-www-form-urlencoded` format. 4 | 5 | This crate is a Rust library for serialising to and deserialising from 6 | the [`application/x-www-form-urlencoded`][urlencoded] format. It is built 7 | upon [Serde], a high performance generic serialization framework and [rust-url], 8 | a URL parser for Rust. 9 | 10 | It is a fork of [`serde_urlencoded`], with additional support for maps or 11 | structs with fields of sequence type (e.g. `Vec`). It also supports 12 | `Option` in values, treating `foo=` as `foo: None`. 13 | 14 | [rust-url]: https://github.com/servo/rust-url 15 | [Serde]: https://github.com/serde-rs/serde 16 | [urlencoded]: https://url.spec.whatwg.org/#application/x-www-form-urlencoded 17 | [`serde_urlencoded`]: https://github.com/nox/serde_urlencoded 18 | 19 | ## Examples 20 | 21 | Sequences like `value=x&value=y`: 22 | 23 | ```rust 24 | use serde::Deserialize; 25 | 26 | #[derive(Debug, PartialEq, Deserialize)] 27 | struct Form { 28 | // By default, at least one occurrence of this field must be present (this 29 | // is mandated by how serde works). 30 | // 31 | // Since this is usually not desired, use `serde(default)` to instantiate 32 | // this struct's field with a `Default` value if input doesn't contain that 33 | // field. 34 | #[serde(default)] 35 | value: Vec, 36 | } 37 | 38 | assert_eq!( 39 | serde_html_form::from_str("value=&value=abc"), 40 | Ok(Form { value: vec!["".to_owned(), "abc".to_owned()] }) 41 | ); 42 | assert_eq!( 43 | serde_html_form::from_str(""), 44 | Ok(Form { value: vec![] }) 45 | ); 46 | ``` 47 | 48 | Sequences like `value[]=x&value[]=y`: 49 | 50 | ```rust 51 | use serde::Deserialize; 52 | 53 | #[derive(Debug, PartialEq, Deserialize)] 54 | struct Form { 55 | // If you want to support `value[]=x&value[]=y`, you can use 56 | // `serde(rename)`. You could even use `serde(alias)` instead to allow both, 57 | // but note that mixing both in one input string would also be allowed then. 58 | #[serde(default, rename = "value[]")] 59 | value: Vec, 60 | } 61 | 62 | assert_eq!( 63 | serde_html_form::from_str("value[]=x&value[]=y"), 64 | Ok(Form { value: vec!["x".to_owned(), "y".to_owned()] }) 65 | ); 66 | assert_eq!( 67 | serde_html_form::from_str("value[]=hello"), 68 | Ok(Form { value: vec!["hello".to_owned()] }) 69 | ); 70 | ``` 71 | 72 | Optional values: 73 | 74 | ```rust 75 | use serde::Deserialize; 76 | 77 | #[derive(Debug, PartialEq, Deserialize)] 78 | struct Form { 79 | // Finally, this crate also supports deserializing empty values as `None` 80 | // if your values are `Option`s. 81 | // Note that serde's `Deserialize` derive implicitly allows omission of 82 | // `Option`-typed fields (except when combined with some other attributes). 83 | single: Option, 84 | // Not using `serde(default)` here to require at least one occurrence. 85 | at_least_one: Vec>, 86 | } 87 | 88 | assert_eq!( 89 | serde_html_form::from_str("at_least_one=5"), 90 | Ok(Form { 91 | // Implicit `serde(default)` in action. 92 | single: None, 93 | // `serde_html_form`'s support for optional values being used. 94 | at_least_one: vec![Some(5)], 95 | }) 96 | ); 97 | assert_eq!( 98 | serde_html_form::from_str("at_least_one=&single=1&at_least_one=5"), 99 | Ok(Form { 100 | single: Some(1), 101 | at_least_one: vec![ 102 | // Empty strings get deserialized as `None`. 103 | None, 104 | // It's no problem that the `at_least_one` field repetitions are 105 | // not consecutive (single comes in between). 106 | Some(5), 107 | ] 108 | }) 109 | ); 110 | assert!( 111 | serde_html_form::from_str::
("").is_err(), 112 | "at_least_one is not part of the input" 113 | ); 114 | ``` 115 | 116 | ## License 117 | 118 | This crate is licensed under the MIT license ([LICENSE](LICENSE) or 119 | ). 120 | -------------------------------------------------------------------------------- /benches/upstream_comparison/benches.rs: -------------------------------------------------------------------------------- 1 | use std::collections::BTreeMap; 2 | 3 | // For rust-analyzer, this file is included as a regular module. Make IDE 4 | // functionality work by pretending that the symbols being tested always come 5 | // from `serde_html_form`. 6 | #[cfg(rust_analyzer)] 7 | use serde_html_form::from_str; 8 | 9 | use crate::{SimpleEnum, StructForm, StructForm2}; 10 | 11 | #[divan::bench] 12 | fn deserialize_list_enum() { 13 | from_str::>("10=VariantB&5=VariantC&2=VariantA&1=VariantA").unwrap(); 14 | } 15 | 16 | #[divan::bench] 17 | fn deserialize_list_duplicate_keys() { 18 | from_str::>("a=test&b=test&a=test&b=test").unwrap(); 19 | } 20 | 21 | #[divan::bench] 22 | fn deserialize_map() { 23 | from_str::>("a=0&bb=1&ccc=123").unwrap(); 24 | } 25 | 26 | #[divan::bench] 27 | fn deserialize_map_many_entries() { 28 | from_str::>( 29 | "0=0&1=1&2=2&3=3&4=4&5=5&6=6&7=7&8=8&\ 30 | 200=0&201=1&202=2&203=3&204=4&205=5&206=6&207=7&208=8&\ 31 | 50=0&51=1&52=2&53=3&54=4&55=5&56=6&57=7&58=8&\ 32 | 1230=0&1231=1&1232=2&1233=3&1234=4&1235=5&1236=6&1237=7&1238=8&\ 33 | 80=0&81=1&82=2&83=3&84=4&85=5&86=6&87=7&88=8", 34 | ) 35 | .unwrap(); 36 | } 37 | 38 | #[divan::bench] 39 | fn deserialize_struct_simple() { 40 | from_str::("foo=value").unwrap(); 41 | } 42 | 43 | #[divan::bench] 44 | fn deserialize_struct_long_parameters() { 45 | from_str::("float_needs_more_complex_parsing_and_has_very_long_field_name=10") 46 | .unwrap(); 47 | } 48 | 49 | #[divan::bench] 50 | fn deserialize_struct_long_parameters_2() { 51 | from_str::( 52 | "float_needs_more_complex_parsing_and_has_very_long_field_name=1.0000000000123&\ 53 | optional_field=12300000000000000", 54 | ) 55 | .unwrap(); 56 | } 57 | -------------------------------------------------------------------------------- /benches/upstream_comparison/main.rs: -------------------------------------------------------------------------------- 1 | use serde::Deserialize; 2 | 3 | fn main() { 4 | divan::main(); 5 | } 6 | 7 | #[derive(Deserialize)] 8 | #[allow(dead_code)] 9 | struct StructForm { 10 | foo: String, 11 | } 12 | 13 | #[derive(Deserialize)] 14 | #[allow(dead_code)] 15 | struct StructForm2 { 16 | optional_field: Option, 17 | float_needs_more_complex_parsing_and_has_very_long_field_name: f64, 18 | } 19 | 20 | #[derive(Deserialize)] 21 | enum SimpleEnum { 22 | VariantA, 23 | VariantB, 24 | VariantC, 25 | } 26 | 27 | // For rust-analyzer, treat `benches.rs` as a regular module. 28 | // The module itself also contains some `cfg(rust_analyzer)` code to include 29 | // the symbols otherwise introduced through the inline modules below. 30 | #[cfg(rust_analyzer)] 31 | mod benches; 32 | 33 | // For actual execution, treat `benches.rs` as two modules, one where `from_str` 34 | // from `serde_html_form` is benchmarked, one where `from_str` from 35 | // `serde_urlencoded` is benchmarked. 36 | #[cfg(not(rust_analyzer))] 37 | mod serde_html_form { 38 | use serde_html_form::from_str; 39 | include!("benches.rs"); 40 | } 41 | 42 | #[cfg(not(rust_analyzer))] 43 | mod serde_urlencoded { 44 | use serde_html_form::from_str; 45 | include!("benches.rs"); 46 | } 47 | -------------------------------------------------------------------------------- /src/de.rs: -------------------------------------------------------------------------------- 1 | //! Deserialization support for the `application/x-www-form-urlencoded` format. 2 | 3 | use std::io::Read; 4 | 5 | use form_urlencoded::{parse, Parse as UrlEncodedParse}; 6 | use indexmap::map::{self, IndexMap}; 7 | use serde::{ 8 | de::{self, value::MapDeserializer}, 9 | forward_to_deserialize_any, 10 | }; 11 | 12 | #[doc(inline)] 13 | pub use serde::de::value::Error; 14 | 15 | mod part; 16 | mod val_or_vec; 17 | 18 | use self::{part::Part, val_or_vec::ValOrVec}; 19 | 20 | /// Deserializes a `application/x-www-form-urlencoded` value from a `&[u8]`. 21 | /// 22 | /// ``` 23 | /// let meal = vec![ 24 | /// ("bread".to_owned(), "baguette".to_owned()), 25 | /// ("cheese".to_owned(), "comté".to_owned()), 26 | /// ("meat".to_owned(), "ham".to_owned()), 27 | /// ("fat".to_owned(), "butter".to_owned()), 28 | /// ]; 29 | /// 30 | /// assert_eq!( 31 | /// serde_html_form::from_bytes::>( 32 | /// b"bread=baguette&cheese=comt%C3%A9&meat=ham&fat=butter" 33 | /// ), 34 | /// Ok(meal) 35 | /// ); 36 | /// ``` 37 | pub fn from_bytes<'de, T>(input: &'de [u8]) -> Result 38 | where 39 | T: de::Deserialize<'de>, 40 | { 41 | T::deserialize(Deserializer::from_bytes(input)) 42 | } 43 | 44 | /// Deserializes a `application/x-www-form-urlencoded` value from a `&str`. 45 | /// 46 | /// ``` 47 | /// let meal = vec![ 48 | /// ("bread".to_owned(), "baguette".to_owned()), 49 | /// ("cheese".to_owned(), "comté".to_owned()), 50 | /// ("meat".to_owned(), "ham".to_owned()), 51 | /// ("fat".to_owned(), "butter".to_owned()), 52 | /// ]; 53 | /// 54 | /// assert_eq!( 55 | /// serde_html_form::from_str::>( 56 | /// "bread=baguette&cheese=comt%C3%A9&meat=ham&fat=butter" 57 | /// ), 58 | /// Ok(meal) 59 | /// ); 60 | /// ``` 61 | pub fn from_str<'de, T>(input: &'de str) -> Result 62 | where 63 | T: de::Deserialize<'de>, 64 | { 65 | from_bytes(input.as_bytes()) 66 | } 67 | 68 | /// Convenience function that reads all bytes from `reader` and deserializes 69 | /// them with `from_bytes`. 70 | pub fn from_reader(mut reader: R) -> Result 71 | where 72 | T: de::DeserializeOwned, 73 | R: Read, 74 | { 75 | let mut buf = vec![]; 76 | reader 77 | .read_to_end(&mut buf) 78 | .map_err(|e| de::Error::custom(format_args!("could not read input: {}", e)))?; 79 | from_bytes(&buf) 80 | } 81 | 82 | /// A deserializer for the `application/x-www-form-urlencoded` format. 83 | /// 84 | /// * Supported top-level outputs are structs, maps and sequences of pairs, 85 | /// with or without a given length. 86 | /// 87 | /// * Main `deserialize` methods defers to `deserialize_map`. 88 | /// 89 | /// * Everything else but `deserialize_seq` and `deserialize_seq_fixed_size` 90 | /// defers to `deserialize`. 91 | pub struct Deserializer<'de> { 92 | inner: UrlEncodedParse<'de>, 93 | } 94 | 95 | impl<'de> Deserializer<'de> { 96 | /// Returns a new `Deserializer`. 97 | pub fn new(parse: UrlEncodedParse<'de>) -> Self { 98 | Deserializer { inner: parse } 99 | } 100 | 101 | /// Returns a new `Deserializer` from a `&[u8]`. 102 | pub fn from_bytes(input: &'de [u8]) -> Self { 103 | Self::new(parse(input)) 104 | } 105 | } 106 | 107 | impl<'de> de::Deserializer<'de> for Deserializer<'de> { 108 | type Error = Error; 109 | 110 | fn deserialize_any(self, visitor: V) -> Result 111 | where 112 | V: de::Visitor<'de>, 113 | { 114 | self.deserialize_seq(visitor) 115 | } 116 | 117 | fn deserialize_map(self, visitor: V) -> Result 118 | where 119 | V: de::Visitor<'de>, 120 | { 121 | visitor.visit_map(MapDeserializer::new(group_entries(self.inner).into_iter())) 122 | } 123 | 124 | fn deserialize_seq(self, visitor: V) -> Result 125 | where 126 | V: de::Visitor<'de>, 127 | { 128 | visitor.visit_seq(MapDeserializer::new(PartIterator(self.inner))) 129 | } 130 | 131 | fn deserialize_unit(self, visitor: V) -> Result 132 | where 133 | V: de::Visitor<'de>, 134 | { 135 | let deserializer = MapDeserializer::new(PartIterator(self.inner)); 136 | deserializer.end()?; 137 | visitor.visit_unit() 138 | } 139 | 140 | fn deserialize_newtype_struct(self, _name: &str, visitor: V) -> Result 141 | where 142 | V: de::Visitor<'de>, 143 | { 144 | visitor.visit_newtype_struct(self) 145 | } 146 | 147 | fn deserialize_struct( 148 | self, 149 | _name: &'static str, 150 | _fields: &'static [&'static str], 151 | visitor: V, 152 | ) -> Result 153 | where 154 | V: de::Visitor<'de>, 155 | { 156 | self.deserialize_map(visitor) 157 | } 158 | 159 | forward_to_deserialize_any! { 160 | bool 161 | u8 162 | u16 163 | u32 164 | u64 165 | i8 166 | i16 167 | i32 168 | i64 169 | f32 170 | f64 171 | char 172 | str 173 | string 174 | option 175 | bytes 176 | byte_buf 177 | unit_struct 178 | tuple_struct 179 | identifier 180 | tuple 181 | enum 182 | ignored_any 183 | } 184 | } 185 | 186 | struct PartIterator<'de>(UrlEncodedParse<'de>); 187 | 188 | impl<'de> Iterator for PartIterator<'de> { 189 | type Item = (Part<'de>, Part<'de>); 190 | 191 | fn next(&mut self) -> Option { 192 | self.0.next().map(|(k, v)| (Part(k), Part(v))) 193 | } 194 | } 195 | 196 | fn group_entries(parse: UrlEncodedParse<'_>) -> IndexMap, ValOrVec>> { 197 | use map::Entry::*; 198 | 199 | let mut res = IndexMap::new(); 200 | 201 | for (key, value) in parse { 202 | match res.entry(Part(key)) { 203 | Vacant(v) => { 204 | v.insert(ValOrVec::Val(Part(value))); 205 | } 206 | Occupied(mut o) => { 207 | o.get_mut().push(Part(value)); 208 | } 209 | } 210 | } 211 | 212 | res 213 | } 214 | 215 | #[cfg(test)] 216 | mod tests; 217 | -------------------------------------------------------------------------------- /src/de/part.rs: -------------------------------------------------------------------------------- 1 | use std::borrow::Cow; 2 | 3 | use serde::{ 4 | de::{self, Error as _, IntoDeserializer}, 5 | forward_to_deserialize_any, 6 | }; 7 | 8 | use super::Error; 9 | 10 | #[derive(PartialEq, PartialOrd, Eq, Ord, Hash)] 11 | pub(super) struct Part<'de>(pub Cow<'de, str>); 12 | 13 | impl<'de> IntoDeserializer<'de> for Part<'de> { 14 | type Deserializer = Self; 15 | 16 | fn into_deserializer(self) -> Self::Deserializer { 17 | self 18 | } 19 | } 20 | 21 | macro_rules! forward_parsed_value { 22 | ($($ty:ident => $method:ident,)*) => { 23 | $( 24 | fn $method(self, visitor: V) -> Result 25 | where V: de::Visitor<'de> 26 | { 27 | match self.0.parse::<$ty>() { 28 | Ok(val) => val.into_deserializer().$method(visitor), 29 | Err(e) => Err(de::Error::custom(e)) 30 | } 31 | } 32 | )* 33 | } 34 | } 35 | 36 | impl<'de> de::Deserializer<'de> for Part<'de> { 37 | type Error = Error; 38 | 39 | fn deserialize_any(self, visitor: V) -> Result 40 | where 41 | V: de::Visitor<'de>, 42 | { 43 | match self.0 { 44 | Cow::Borrowed(value) => visitor.visit_borrowed_str(value), 45 | Cow::Owned(value) => visitor.visit_string(value), 46 | } 47 | } 48 | 49 | fn deserialize_option(self, visitor: V) -> Result 50 | where 51 | V: de::Visitor<'de>, 52 | { 53 | if self.0.is_empty() { 54 | visitor.visit_none() 55 | } else { 56 | visitor.visit_some(self) 57 | } 58 | } 59 | 60 | fn deserialize_enum( 61 | self, 62 | _name: &'static str, 63 | _variants: &'static [&'static str], 64 | visitor: V, 65 | ) -> Result 66 | where 67 | V: de::Visitor<'de>, 68 | { 69 | visitor.visit_enum(self) 70 | } 71 | 72 | fn deserialize_newtype_struct( 73 | self, 74 | _name: &'static str, 75 | visitor: V, 76 | ) -> Result 77 | where 78 | V: de::Visitor<'de>, 79 | { 80 | visitor.visit_newtype_struct(self) 81 | } 82 | 83 | fn deserialize_seq(self, visitor: V) -> Result 84 | where 85 | V: de::Visitor<'de>, 86 | { 87 | visitor.visit_seq(PartSeqAccess(Some(self))) 88 | } 89 | 90 | forward_to_deserialize_any! { 91 | char 92 | str 93 | string 94 | unit 95 | bytes 96 | byte_buf 97 | unit_struct 98 | tuple_struct 99 | struct 100 | identifier 101 | tuple 102 | ignored_any 103 | map 104 | } 105 | 106 | forward_parsed_value! { 107 | bool => deserialize_bool, 108 | u8 => deserialize_u8, 109 | u16 => deserialize_u16, 110 | u32 => deserialize_u32, 111 | u64 => deserialize_u64, 112 | i8 => deserialize_i8, 113 | i16 => deserialize_i16, 114 | i32 => deserialize_i32, 115 | i64 => deserialize_i64, 116 | f32 => deserialize_f32, 117 | f64 => deserialize_f64, 118 | } 119 | } 120 | 121 | impl<'de> de::EnumAccess<'de> for Part<'de> { 122 | type Error = Error; 123 | type Variant = UnitOnlyVariantAccess; 124 | 125 | fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error> 126 | where 127 | V: de::DeserializeSeed<'de>, 128 | { 129 | let variant = seed.deserialize(self.0.into_deserializer())?; 130 | Ok((variant, UnitOnlyVariantAccess)) 131 | } 132 | } 133 | 134 | struct PartSeqAccess<'de>(Option>); 135 | 136 | impl<'de> de::SeqAccess<'de> for PartSeqAccess<'de> { 137 | type Error = Error; 138 | 139 | fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> 140 | where 141 | T: de::DeserializeSeed<'de>, 142 | { 143 | match self.0.take() { 144 | Some(value) => seed.deserialize(value).map(Some), 145 | None => Ok(None), 146 | } 147 | } 148 | 149 | fn size_hint(&self) -> Option { 150 | Some(self.0.is_some() as usize) 151 | } 152 | } 153 | 154 | pub(crate) struct UnitOnlyVariantAccess; 155 | 156 | impl<'de> de::VariantAccess<'de> for UnitOnlyVariantAccess { 157 | type Error = Error; 158 | 159 | fn unit_variant(self) -> Result<(), Self::Error> { 160 | Ok(()) 161 | } 162 | 163 | fn newtype_variant_seed(self, _seed: T) -> Result 164 | where 165 | T: de::DeserializeSeed<'de>, 166 | { 167 | Err(Error::custom("expected unit variant")) 168 | } 169 | 170 | fn tuple_variant(self, _len: usize, _visitor: V) -> Result 171 | where 172 | V: de::Visitor<'de>, 173 | { 174 | Err(Error::custom("expected unit variant")) 175 | } 176 | 177 | fn struct_variant( 178 | self, 179 | _fields: &'static [&'static str], 180 | _visitor: V, 181 | ) -> Result 182 | where 183 | V: de::Visitor<'de>, 184 | { 185 | Err(Error::custom("expected unit variant")) 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /src/de/tests.rs: -------------------------------------------------------------------------------- 1 | use std::collections::BTreeMap; 2 | 3 | use serde::Deserialize; 4 | 5 | #[derive(Deserialize, Debug, PartialEq)] 6 | struct NewType(T); 7 | 8 | #[test] 9 | fn deserialize_newtype_i32() { 10 | let result = vec![("field".to_owned(), NewType(11))]; 11 | 12 | assert_eq!(super::from_str("field=11"), Ok(result)); 13 | } 14 | 15 | #[test] 16 | fn deserialize_bytes() { 17 | let result = vec![("first".to_owned(), 23), ("last".to_owned(), 42)]; 18 | 19 | assert_eq!(super::from_bytes(b"first=23&last=42"), Ok(result)); 20 | } 21 | 22 | #[test] 23 | fn deserialize_str() { 24 | let result = vec![("first".to_owned(), 23), ("last".to_owned(), 42)]; 25 | 26 | assert_eq!(super::from_str("first=23&last=42"), Ok(result)); 27 | } 28 | 29 | #[test] 30 | fn deserialize_borrowed_str() { 31 | let result = vec![("first", 23), ("last", 42)]; 32 | 33 | assert_eq!(super::from_str("first=23&last=42"), Ok(result)); 34 | } 35 | 36 | #[test] 37 | fn deserialize_reader() { 38 | let result = vec![("first".to_owned(), 23), ("last".to_owned(), 42)]; 39 | 40 | assert_eq!(super::from_reader(b"first=23&last=42" as &[_]), Ok(result)); 41 | } 42 | 43 | #[test] 44 | fn deserialize_option() { 45 | let result = vec![("first".to_owned(), Some(23)), ("last".to_owned(), Some(42))]; 46 | assert_eq!(super::from_str("first=23&last=42"), Ok(result)); 47 | } 48 | 49 | #[test] 50 | fn deserialize_empty_string() { 51 | let result = vec![("first".to_owned(), "")]; 52 | assert_eq!(super::from_str("first="), Ok(result)); 53 | } 54 | 55 | #[test] 56 | fn deserialize_map() { 57 | let result = BTreeMap::from_iter([("first".to_owned(), 23), ("second".to_owned(), 42)]); 58 | assert_eq!(super::from_str("first=23&second=42"), Ok(result)); 59 | } 60 | 61 | #[test] 62 | fn deserialize_map_vec() { 63 | let result = 64 | BTreeMap::from_iter([("first".to_owned(), vec![23, 1]), ("second".to_owned(), vec![42])]); 65 | assert_eq!(super::from_str("first=23&second=42&first=1"), Ok(result)); 66 | } 67 | 68 | #[test] 69 | fn deserialize_tuple_list() { 70 | let result = vec![("foo".to_owned(), 1), ("bar".to_owned(), 2), ("foo".to_owned(), 3)]; 71 | assert_eq!(super::from_str("foo=1&bar=2&foo=3"), Ok(result)); 72 | } 73 | 74 | #[test] 75 | fn deserialize_vec_strings() { 76 | #[derive(Deserialize, PartialEq, Debug)] 77 | struct Form { 78 | value: Vec, 79 | } 80 | 81 | assert_eq!( 82 | super::from_str("value=&value=abc"), 83 | Ok(Form { value: vec!["".to_owned(), "abc".to_owned()] }) 84 | ); 85 | } 86 | 87 | #[test] 88 | fn deserialize_option_vec() { 89 | #[derive(Deserialize, PartialEq, Debug)] 90 | struct Form { 91 | value: Option>, 92 | } 93 | 94 | assert_eq!(super::from_str(""), Ok(Form { value: None })); 95 | assert_eq!(super::from_str("value=abc"), Ok(Form { value: Some(vec!["abc".to_owned()]) })); 96 | assert_eq!( 97 | super::from_str("value=abc&value=def"), 98 | Ok(Form { value: Some(vec!["abc".to_owned(), "def".to_owned()]) }) 99 | ); 100 | } 101 | 102 | #[test] 103 | fn deserialize_option_vec_int() { 104 | #[derive(Deserialize, PartialEq, Debug)] 105 | struct Form { 106 | value: Option>, 107 | } 108 | 109 | assert_eq!(super::from_str(""), Ok(Form { value: None })); 110 | assert_eq!(super::from_str("value=0"), Ok(Form { value: Some(vec![0]) })); 111 | assert_eq!(super::from_str("value=3&value=-1"), Ok(Form { value: Some(vec![3, -1]) })); 112 | } 113 | 114 | #[test] 115 | fn deserialize_option_no_value() { 116 | #[derive(Deserialize, PartialEq, Debug)] 117 | struct Form { 118 | value: Option, 119 | } 120 | 121 | assert_eq!(super::from_str("value="), Ok(Form { value: None })); 122 | } 123 | 124 | #[test] 125 | fn deserialize_vec_options_no_value() { 126 | #[derive(Deserialize, PartialEq, Debug)] 127 | struct Form { 128 | value: Vec>, 129 | } 130 | 131 | assert_eq!(super::from_str("value=&value=&value="), Ok(Form { value: vec![None, None, None] })); 132 | } 133 | 134 | #[test] 135 | fn deserialize_vec_options_some_values() { 136 | #[derive(Deserialize, PartialEq, Debug)] 137 | struct Form { 138 | value: Vec>, 139 | } 140 | 141 | assert_eq!( 142 | super::from_str("value=&value=4&value="), 143 | Ok(Form { value: vec![None, Some(4.0), None] }) 144 | ); 145 | } 146 | 147 | #[test] 148 | fn deserialize_option_vec_no_value() { 149 | #[derive(Deserialize, PartialEq, Debug)] 150 | struct Form { 151 | value: Option>, 152 | } 153 | 154 | assert_eq!( 155 | super::from_str::("value=&value=&value=").unwrap_err().to_string(), 156 | "cannot parse float from empty string" 157 | ); 158 | } 159 | 160 | #[test] 161 | fn deserialize_option_vec_with_values() { 162 | #[derive(Deserialize, PartialEq, Debug)] 163 | struct Form { 164 | value: Option>, 165 | } 166 | 167 | assert_eq!( 168 | super::from_str("value=3&value=4&value=5"), 169 | Ok(Form { value: Some(vec![3.0, 4.0, 5.0]) }) 170 | ); 171 | } 172 | 173 | #[test] 174 | fn deserialize_no_value_err() { 175 | #[derive(Deserialize, PartialEq, Debug)] 176 | struct Form { 177 | value: f64, 178 | } 179 | 180 | assert_eq!( 181 | super::from_str::("value=").unwrap_err().to_string(), 182 | "cannot parse float from empty string" 183 | ); 184 | } 185 | 186 | #[test] 187 | fn deserialize_unit() { 188 | assert_eq!(super::from_str(""), Ok(())); 189 | assert_eq!(super::from_str("&"), Ok(())); 190 | assert_eq!(super::from_str("&&"), Ok(())); 191 | assert!(super::from_str::<()>("first=23").is_err()); 192 | } 193 | 194 | #[derive(Deserialize, Debug, PartialEq, Eq)] 195 | enum X { 196 | A, 197 | B, 198 | C, 199 | } 200 | 201 | #[test] 202 | fn deserialize_unit_enum() { 203 | let result = 204 | vec![("one".to_owned(), X::A), ("two".to_owned(), X::B), ("three".to_owned(), X::C)]; 205 | 206 | assert_eq!(super::from_str("one=A&two=B&three=C"), Ok(result)); 207 | } 208 | 209 | #[test] 210 | fn deserialize_unit_type() { 211 | assert_eq!(super::from_str(""), Ok(())); 212 | } 213 | -------------------------------------------------------------------------------- /src/de/val_or_vec.rs: -------------------------------------------------------------------------------- 1 | use std::{hint::unreachable_unchecked, iter, mem, vec}; 2 | 3 | use serde::de::{ 4 | self, 5 | value::{Error, SeqDeserializer}, 6 | Deserializer, IntoDeserializer, 7 | }; 8 | 9 | #[derive(Debug)] 10 | pub(crate) enum ValOrVec { 11 | Val(T), 12 | Vec(Vec), 13 | } 14 | 15 | impl ValOrVec { 16 | pub fn push(&mut self, new_val: T) { 17 | match self { 18 | Self::Val(_) => { 19 | // Change self to a Vec variant and take ownership of the previous value 20 | let old_self = mem::replace(self, ValOrVec::Vec(Vec::with_capacity(2))); 21 | 22 | let old_val = match old_self { 23 | Self::Val(v) => v, 24 | // Safety: We would not be in the outer branch otherwise 25 | _ => unsafe { unreachable_unchecked() }, 26 | }; 27 | 28 | let vec = match self { 29 | ValOrVec::Vec(v) => v, 30 | // Safety: We set self to Vec with the mem::replace above 31 | _ => unsafe { unreachable_unchecked() }, 32 | }; 33 | 34 | vec.push(old_val); 35 | vec.push(new_val); 36 | } 37 | Self::Vec(vec) => vec.push(new_val), 38 | } 39 | } 40 | 41 | fn deserialize_val(self, f: F) -> Result 42 | where 43 | F: FnOnce(T) -> Result, 44 | E: de::Error, 45 | { 46 | match self { 47 | ValOrVec::Val(val) => f(val), 48 | ValOrVec::Vec(_) => Err(de::Error::custom("unsupported value")), 49 | } 50 | } 51 | } 52 | 53 | impl IntoIterator for ValOrVec { 54 | type Item = T; 55 | type IntoIter = IntoIter; 56 | 57 | fn into_iter(self) -> Self::IntoIter { 58 | IntoIter::new(self) 59 | } 60 | } 61 | 62 | pub enum IntoIter { 63 | Val(iter::Once), 64 | Vec(vec::IntoIter), 65 | } 66 | 67 | impl IntoIter { 68 | fn new(vv: ValOrVec) -> Self { 69 | match vv { 70 | ValOrVec::Val(val) => IntoIter::Val(iter::once(val)), 71 | ValOrVec::Vec(vec) => IntoIter::Vec(vec.into_iter()), 72 | } 73 | } 74 | } 75 | 76 | impl Iterator for IntoIter { 77 | type Item = T; 78 | 79 | fn next(&mut self) -> Option { 80 | match self { 81 | IntoIter::Val(iter) => iter.next(), 82 | IntoIter::Vec(iter) => iter.next(), 83 | } 84 | } 85 | } 86 | 87 | impl<'de, T> IntoDeserializer<'de> for ValOrVec 88 | where 89 | T: IntoDeserializer<'de> + Deserializer<'de, Error = Error>, 90 | { 91 | type Deserializer = Self; 92 | 93 | fn into_deserializer(self) -> Self::Deserializer { 94 | self 95 | } 96 | } 97 | 98 | macro_rules! forward_to_part { 99 | ($($method:ident,)*) => { 100 | $( 101 | fn $method(self, visitor: V) -> Result 102 | where V: de::Visitor<'de> 103 | { 104 | self.deserialize_val(move |val| val.$method(visitor)) 105 | } 106 | )* 107 | } 108 | } 109 | 110 | impl<'de, T> Deserializer<'de> for ValOrVec 111 | where 112 | T: IntoDeserializer<'de> + Deserializer<'de, Error = Error>, 113 | { 114 | type Error = Error; 115 | 116 | fn deserialize_any(self, visitor: V) -> Result 117 | where 118 | V: de::Visitor<'de>, 119 | { 120 | match self { 121 | Self::Val(val) => val.deserialize_any(visitor), 122 | Self::Vec(_) => self.deserialize_seq(visitor), 123 | } 124 | } 125 | 126 | fn deserialize_seq(self, visitor: V) -> Result 127 | where 128 | V: de::Visitor<'de>, 129 | { 130 | visitor.visit_seq(SeqDeserializer::new(self.into_iter())) 131 | } 132 | 133 | fn deserialize_enum( 134 | self, 135 | name: &'static str, 136 | variants: &'static [&'static str], 137 | visitor: V, 138 | ) -> Result 139 | where 140 | V: de::Visitor<'de>, 141 | { 142 | self.deserialize_val(move |val| val.deserialize_enum(name, variants, visitor)) 143 | } 144 | 145 | fn deserialize_tuple(self, len: usize, visitor: V) -> Result 146 | where 147 | V: de::Visitor<'de>, 148 | { 149 | self.deserialize_val(move |val| val.deserialize_tuple(len, visitor)) 150 | } 151 | 152 | fn deserialize_struct( 153 | self, 154 | name: &'static str, 155 | fields: &'static [&'static str], 156 | visitor: V, 157 | ) -> Result 158 | where 159 | V: de::Visitor<'de>, 160 | { 161 | self.deserialize_val(move |val| val.deserialize_struct(name, fields, visitor)) 162 | } 163 | 164 | fn deserialize_unit_struct( 165 | self, 166 | name: &'static str, 167 | visitor: V, 168 | ) -> Result 169 | where 170 | V: de::Visitor<'de>, 171 | { 172 | self.deserialize_val(move |val| val.deserialize_unit_struct(name, visitor)) 173 | } 174 | 175 | fn deserialize_tuple_struct( 176 | self, 177 | name: &'static str, 178 | len: usize, 179 | visitor: V, 180 | ) -> Result 181 | where 182 | V: de::Visitor<'de>, 183 | { 184 | self.deserialize_val(move |val| val.deserialize_tuple_struct(name, len, visitor)) 185 | } 186 | 187 | fn deserialize_newtype_struct( 188 | self, 189 | name: &'static str, 190 | visitor: V, 191 | ) -> Result 192 | where 193 | V: de::Visitor<'de>, 194 | { 195 | self.deserialize_val(move |val| val.deserialize_newtype_struct(name, visitor)) 196 | } 197 | 198 | fn deserialize_ignored_any(self, visitor: V) -> Result 199 | where 200 | V: de::Visitor<'de>, 201 | { 202 | visitor.visit_unit() 203 | } 204 | 205 | fn deserialize_option(self, visitor: V) -> Result 206 | where 207 | V: de::Visitor<'de>, 208 | { 209 | match self { 210 | ValOrVec::Val(val) => val.deserialize_option(visitor), 211 | ValOrVec::Vec(_) => visitor.visit_some(self), 212 | } 213 | } 214 | 215 | forward_to_part! { 216 | deserialize_bool, 217 | deserialize_char, 218 | deserialize_str, 219 | deserialize_string, 220 | deserialize_bytes, 221 | deserialize_byte_buf, 222 | deserialize_unit, 223 | deserialize_u8, 224 | deserialize_u16, 225 | deserialize_u32, 226 | deserialize_u64, 227 | deserialize_i8, 228 | deserialize_i16, 229 | deserialize_i32, 230 | deserialize_i64, 231 | deserialize_f32, 232 | deserialize_f64, 233 | deserialize_identifier, 234 | deserialize_map, 235 | } 236 | } 237 | 238 | #[cfg(test)] 239 | mod tests { 240 | use std::borrow::Cow; 241 | 242 | use assert_matches2::assert_matches; 243 | 244 | use super::ValOrVec; 245 | 246 | #[test] 247 | fn cow_borrowed() { 248 | let mut x = ValOrVec::Val(Cow::Borrowed("a")); 249 | x.push(Cow::Borrowed("b")); 250 | x.push(Cow::Borrowed("c")); 251 | assert_matches!(x, ValOrVec::Vec(v)); 252 | assert_eq!(v, vec!["a", "b", "c"]); 253 | } 254 | 255 | #[test] 256 | fn cow_owned() { 257 | let mut x = ValOrVec::Val(Cow::from("a".to_owned())); 258 | x.push(Cow::from("b".to_owned())); 259 | x.push(Cow::from("c".to_owned())); 260 | assert_matches!(x, ValOrVec::Vec(v)); 261 | assert_eq!(v, vec!["a".to_owned(), "b".to_owned(), "c".to_owned()]); 262 | } 263 | } 264 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc = include_str!("../README.md")] 2 | #![warn( 3 | rust_2018_idioms, 4 | unused_qualifications, 5 | clippy::branches_sharing_code, 6 | clippy::cloned_instead_of_copied, 7 | clippy::empty_line_after_outer_attr, 8 | clippy::inefficient_to_string, 9 | clippy::mut_mut, 10 | clippy::nonstandard_macro_braces, 11 | clippy::semicolon_if_nothing_returned, 12 | clippy::str_to_string, 13 | clippy::unreadable_literal, 14 | clippy::unseparated_literal_suffix, 15 | clippy::wildcard_imports 16 | )] 17 | 18 | pub mod de; 19 | pub mod ser; 20 | 21 | #[doc(inline)] 22 | pub use crate::de::{from_bytes, from_reader, from_str, Deserializer}; 23 | #[doc(inline)] 24 | pub use crate::ser::{push_to_string, to_string, Serializer}; 25 | -------------------------------------------------------------------------------- /src/ser.rs: -------------------------------------------------------------------------------- 1 | //! Serialization support for the `application/x-www-form-urlencoded` format. 2 | 3 | mod error; 4 | mod key; 5 | mod pair; 6 | mod part; 7 | mod value; 8 | 9 | use std::{borrow::Cow, str}; 10 | 11 | use form_urlencoded::{Serializer as UrlEncodedSerializer, Target as UrlEncodedTarget}; 12 | use serde::ser; 13 | 14 | pub use self::error::Error; 15 | 16 | /// Serializes a value into a `application/x-www-form-urlencoded` `String` buffer. 17 | /// 18 | /// ``` 19 | /// let meal = &[("bread", "baguette"), ("cheese", "comté"), ("meat", "ham"), ("fat", "butter")]; 20 | /// 21 | /// assert_eq!( 22 | /// serde_html_form::to_string(meal), 23 | /// Ok("bread=baguette&cheese=comt%C3%A9&meat=ham&fat=butter".to_owned()) 24 | /// ); 25 | /// ``` 26 | pub fn to_string(input: T) -> Result { 27 | let mut target = String::new(); 28 | push_to_string(&mut target, input)?; 29 | Ok(target) 30 | } 31 | 32 | /// Serializes a value into the provided `application/x-www-form-urlencoded` `String` buffer. 33 | /// 34 | /// ``` 35 | /// let meal = &[("bread", "baguette"), ("cheese", "comté"), ("meat", "ham"), ("fat", "butter")]; 36 | /// 37 | /// let mut target = "/cook?".to_owned(); 38 | /// 39 | /// serde_html_form::ser::push_to_string(&mut target, meal).unwrap(); 40 | /// 41 | /// assert_eq!(target, "/cook?bread=baguette&cheese=comt%C3%A9&meat=ham&fat=butter"); 42 | /// ``` 43 | pub fn push_to_string(target: &mut String, input: T) -> Result<(), Error> { 44 | let start_position = target.len(); 45 | let mut urlencoder = UrlEncodedSerializer::for_suffix(target, start_position); 46 | input.serialize(Serializer::new(&mut urlencoder))?; 47 | urlencoder.finish(); 48 | Ok(()) 49 | } 50 | 51 | /// A serializer for the `application/x-www-form-urlencoded` format. 52 | /// 53 | /// * Supported top-level inputs are structs, maps and sequences of pairs, 54 | /// with or without a given length. 55 | /// 56 | /// * Supported keys and values are integers, bytes (if convertible to strings), 57 | /// unit structs and unit variants. 58 | /// 59 | /// * Newtype structs defer to their inner values. 60 | pub struct Serializer<'input, 'output, Target: UrlEncodedTarget> { 61 | urlencoder: &'output mut UrlEncodedSerializer<'input, Target>, 62 | } 63 | 64 | impl<'input, 'output, Target: 'output + UrlEncodedTarget> Serializer<'input, 'output, Target> { 65 | /// Returns a new `Serializer`. 66 | pub fn new(urlencoder: &'output mut UrlEncodedSerializer<'input, Target>) -> Self { 67 | Serializer { urlencoder } 68 | } 69 | } 70 | 71 | /// Sequence serializer. 72 | pub struct SeqSerializer<'input, 'output, Target: UrlEncodedTarget> { 73 | urlencoder: &'output mut UrlEncodedSerializer<'input, Target>, 74 | } 75 | 76 | /// Tuple serializer. 77 | /// 78 | /// Mostly used for arrays. 79 | pub struct TupleSerializer<'input, 'output, Target: UrlEncodedTarget> { 80 | urlencoder: &'output mut UrlEncodedSerializer<'input, Target>, 81 | } 82 | 83 | /// Tuple struct serializer. 84 | /// 85 | /// Never instantiated, tuple structs are not supported. 86 | pub struct TupleStructSerializer<'input, 'output, T: UrlEncodedTarget> { 87 | inner: ser::Impossible<&'output mut UrlEncodedSerializer<'input, T>, Error>, 88 | } 89 | 90 | /// Tuple variant serializer. 91 | /// 92 | /// Never instantiated, tuple variants are not supported. 93 | pub struct TupleVariantSerializer<'input, 'output, T: UrlEncodedTarget> { 94 | inner: ser::Impossible<&'output mut UrlEncodedSerializer<'input, T>, Error>, 95 | } 96 | 97 | /// Map serializer. 98 | pub struct MapSerializer<'input, 'output, Target: UrlEncodedTarget> { 99 | urlencoder: &'output mut UrlEncodedSerializer<'input, Target>, 100 | key: Option>, 101 | } 102 | 103 | /// Struct serializer. 104 | pub struct StructSerializer<'input, 'output, Target: UrlEncodedTarget> { 105 | urlencoder: &'output mut UrlEncodedSerializer<'input, Target>, 106 | } 107 | 108 | /// Struct variant serializer. 109 | /// 110 | /// Never instantiated, struct variants are not supported. 111 | pub struct StructVariantSerializer<'input, 'output, T: UrlEncodedTarget> { 112 | inner: ser::Impossible<&'output mut UrlEncodedSerializer<'input, T>, Error>, 113 | } 114 | 115 | impl<'input, 'output, Target> ser::Serializer for Serializer<'input, 'output, Target> 116 | where 117 | Target: 'output + UrlEncodedTarget, 118 | { 119 | type Ok = &'output mut UrlEncodedSerializer<'input, Target>; 120 | type Error = Error; 121 | type SerializeSeq = SeqSerializer<'input, 'output, Target>; 122 | type SerializeTuple = TupleSerializer<'input, 'output, Target>; 123 | type SerializeTupleStruct = TupleStructSerializer<'input, 'output, Target>; 124 | type SerializeTupleVariant = TupleVariantSerializer<'input, 'output, Target>; 125 | type SerializeMap = MapSerializer<'input, 'output, Target>; 126 | type SerializeStruct = StructSerializer<'input, 'output, Target>; 127 | type SerializeStructVariant = StructVariantSerializer<'input, 'output, Target>; 128 | 129 | /// Returns an error. 130 | fn serialize_bool(self, _v: bool) -> Result { 131 | Err(Error::top_level()) 132 | } 133 | 134 | /// Returns an error. 135 | fn serialize_i8(self, _v: i8) -> Result { 136 | Err(Error::top_level()) 137 | } 138 | 139 | /// Returns an error. 140 | fn serialize_i16(self, _v: i16) -> Result { 141 | Err(Error::top_level()) 142 | } 143 | 144 | /// Returns an error. 145 | fn serialize_i32(self, _v: i32) -> Result { 146 | Err(Error::top_level()) 147 | } 148 | 149 | /// Returns an error. 150 | fn serialize_i64(self, _v: i64) -> Result { 151 | Err(Error::top_level()) 152 | } 153 | 154 | /// Returns an error. 155 | fn serialize_u8(self, _v: u8) -> Result { 156 | Err(Error::top_level()) 157 | } 158 | 159 | /// Returns an error. 160 | fn serialize_u16(self, _v: u16) -> Result { 161 | Err(Error::top_level()) 162 | } 163 | 164 | /// Returns an error. 165 | fn serialize_u32(self, _v: u32) -> Result { 166 | Err(Error::top_level()) 167 | } 168 | 169 | /// Returns an error. 170 | fn serialize_u64(self, _v: u64) -> Result { 171 | Err(Error::top_level()) 172 | } 173 | 174 | /// Returns an error. 175 | fn serialize_f32(self, _v: f32) -> Result { 176 | Err(Error::top_level()) 177 | } 178 | 179 | /// Returns an error. 180 | fn serialize_f64(self, _v: f64) -> Result { 181 | Err(Error::top_level()) 182 | } 183 | 184 | /// Returns an error. 185 | fn serialize_char(self, _v: char) -> Result { 186 | Err(Error::top_level()) 187 | } 188 | 189 | /// Returns an error. 190 | fn serialize_str(self, _value: &str) -> Result { 191 | Err(Error::top_level()) 192 | } 193 | 194 | /// Returns an error. 195 | fn serialize_bytes(self, _value: &[u8]) -> Result { 196 | Err(Error::top_level()) 197 | } 198 | 199 | /// Returns `Ok`. 200 | fn serialize_unit(self) -> Result { 201 | Ok(self.urlencoder) 202 | } 203 | 204 | /// Returns `Ok`. 205 | fn serialize_unit_struct(self, _name: &'static str) -> Result { 206 | Ok(self.urlencoder) 207 | } 208 | 209 | /// Returns an error. 210 | fn serialize_unit_variant( 211 | self, 212 | _name: &'static str, 213 | _variant_index: u32, 214 | _variant: &'static str, 215 | ) -> Result { 216 | Err(Error::top_level()) 217 | } 218 | 219 | /// Serializes the inner value, ignoring the newtype name. 220 | fn serialize_newtype_struct( 221 | self, 222 | _name: &'static str, 223 | value: &T, 224 | ) -> Result { 225 | value.serialize(self) 226 | } 227 | 228 | /// Returns an error. 229 | fn serialize_newtype_variant( 230 | self, 231 | _name: &'static str, 232 | _variant_index: u32, 233 | _variant: &'static str, 234 | _value: &T, 235 | ) -> Result { 236 | Err(Error::top_level()) 237 | } 238 | 239 | /// Returns `Ok`. 240 | fn serialize_none(self) -> Result { 241 | Ok(self.urlencoder) 242 | } 243 | 244 | /// Serializes the given value. 245 | fn serialize_some(self, value: &T) -> Result { 246 | value.serialize(self) 247 | } 248 | 249 | /// Serialize a sequence, given length (if any) is ignored. 250 | fn serialize_seq(self, _len: Option) -> Result { 251 | Ok(SeqSerializer { urlencoder: self.urlencoder }) 252 | } 253 | 254 | /// Returns an error. 255 | fn serialize_tuple(self, _len: usize) -> Result { 256 | Ok(TupleSerializer { urlencoder: self.urlencoder }) 257 | } 258 | 259 | /// Returns an error. 260 | fn serialize_tuple_struct( 261 | self, 262 | _name: &'static str, 263 | _len: usize, 264 | ) -> Result { 265 | Err(Error::top_level()) 266 | } 267 | 268 | /// Returns an error. 269 | fn serialize_tuple_variant( 270 | self, 271 | _name: &'static str, 272 | _variant_index: u32, 273 | _variant: &'static str, 274 | _len: usize, 275 | ) -> Result { 276 | Err(Error::top_level()) 277 | } 278 | 279 | /// Serializes a map, given length is ignored. 280 | fn serialize_map(self, _len: Option) -> Result { 281 | Ok(MapSerializer { urlencoder: self.urlencoder, key: None }) 282 | } 283 | 284 | /// Serializes a struct, given length is ignored. 285 | fn serialize_struct( 286 | self, 287 | _name: &'static str, 288 | _len: usize, 289 | ) -> Result { 290 | Ok(StructSerializer { urlencoder: self.urlencoder }) 291 | } 292 | 293 | /// Returns an error. 294 | fn serialize_struct_variant( 295 | self, 296 | _name: &'static str, 297 | _variant_index: u32, 298 | _variant: &'static str, 299 | _len: usize, 300 | ) -> Result { 301 | Err(Error::top_level()) 302 | } 303 | } 304 | 305 | impl<'input, 'output, Target> ser::SerializeSeq for SeqSerializer<'input, 'output, Target> 306 | where 307 | Target: 'output + UrlEncodedTarget, 308 | { 309 | type Ok = &'output mut UrlEncodedSerializer<'input, Target>; 310 | type Error = Error; 311 | 312 | fn serialize_element(&mut self, value: &T) -> Result<(), Error> { 313 | value.serialize(pair::PairSerializer::new(self.urlencoder)) 314 | } 315 | 316 | fn end(self) -> Result { 317 | Ok(self.urlencoder) 318 | } 319 | } 320 | 321 | impl<'input, 'output, Target> ser::SerializeTuple for TupleSerializer<'input, 'output, Target> 322 | where 323 | Target: 'output + UrlEncodedTarget, 324 | { 325 | type Ok = &'output mut UrlEncodedSerializer<'input, Target>; 326 | type Error = Error; 327 | 328 | fn serialize_element(&mut self, value: &T) -> Result<(), Error> { 329 | value.serialize(pair::PairSerializer::new(self.urlencoder)) 330 | } 331 | 332 | fn end(self) -> Result { 333 | Ok(self.urlencoder) 334 | } 335 | } 336 | 337 | impl<'input, 'output, Target> ser::SerializeTupleStruct 338 | for TupleStructSerializer<'input, 'output, Target> 339 | where 340 | Target: 'output + UrlEncodedTarget, 341 | { 342 | type Ok = &'output mut UrlEncodedSerializer<'input, Target>; 343 | type Error = Error; 344 | 345 | fn serialize_field(&mut self, value: &T) -> Result<(), Error> { 346 | self.inner.serialize_field(value) 347 | } 348 | 349 | fn end(self) -> Result { 350 | self.inner.end() 351 | } 352 | } 353 | 354 | impl<'input, 'output, Target> ser::SerializeTupleVariant 355 | for TupleVariantSerializer<'input, 'output, Target> 356 | where 357 | Target: 'output + UrlEncodedTarget, 358 | { 359 | type Ok = &'output mut UrlEncodedSerializer<'input, Target>; 360 | type Error = Error; 361 | 362 | fn serialize_field(&mut self, value: &T) -> Result<(), Error> { 363 | self.inner.serialize_field(value) 364 | } 365 | 366 | fn end(self) -> Result { 367 | self.inner.end() 368 | } 369 | } 370 | 371 | impl<'input, 'output, Target> ser::SerializeMap for MapSerializer<'input, 'output, Target> 372 | where 373 | Target: 'output + UrlEncodedTarget, 374 | { 375 | type Ok = &'output mut UrlEncodedSerializer<'input, Target>; 376 | type Error = Error; 377 | 378 | fn serialize_entry( 379 | &mut self, 380 | key: &K, 381 | value: &V, 382 | ) -> Result<(), Error> { 383 | let key_sink = key::KeySink::new(|key| { 384 | let value_sink = value::ValueSink::new(self.urlencoder, &key); 385 | value.serialize(part::PartSerializer::new(value_sink))?; 386 | self.key = None; 387 | Ok(()) 388 | }); 389 | let entry_serializer = part::PartSerializer::new(key_sink); 390 | key.serialize(entry_serializer) 391 | } 392 | 393 | fn serialize_key(&mut self, key: &T) -> Result<(), Error> { 394 | let key_sink = key::KeySink::new(|key| Ok(key.into())); 395 | let key_serializer = part::PartSerializer::new(key_sink); 396 | self.key = Some(key.serialize(key_serializer)?); 397 | Ok(()) 398 | } 399 | 400 | fn serialize_value(&mut self, value: &T) -> Result<(), Error> { 401 | { 402 | let key = self.key.as_ref().ok_or_else(Error::no_key)?; 403 | let value_sink = value::ValueSink::new(self.urlencoder, key); 404 | value.serialize(part::PartSerializer::new(value_sink))?; 405 | } 406 | self.key = None; 407 | Ok(()) 408 | } 409 | 410 | fn end(self) -> Result { 411 | Ok(self.urlencoder) 412 | } 413 | } 414 | 415 | impl<'input, 'output, Target> ser::SerializeStruct for StructSerializer<'input, 'output, Target> 416 | where 417 | Target: 'output + UrlEncodedTarget, 418 | { 419 | type Ok = &'output mut UrlEncodedSerializer<'input, Target>; 420 | type Error = Error; 421 | 422 | fn serialize_field( 423 | &mut self, 424 | key: &'static str, 425 | value: &T, 426 | ) -> Result<(), Error> { 427 | let value_sink = value::ValueSink::new(self.urlencoder, key); 428 | value.serialize(part::PartSerializer::new(value_sink)) 429 | } 430 | 431 | fn end(self) -> Result { 432 | Ok(self.urlencoder) 433 | } 434 | } 435 | 436 | impl<'input, 'output, Target> ser::SerializeStructVariant 437 | for StructVariantSerializer<'input, 'output, Target> 438 | where 439 | Target: 'output + UrlEncodedTarget, 440 | { 441 | type Ok = &'output mut UrlEncodedSerializer<'input, Target>; 442 | type Error = Error; 443 | 444 | fn serialize_field( 445 | &mut self, 446 | key: &'static str, 447 | value: &T, 448 | ) -> Result<(), Error> { 449 | self.inner.serialize_field(key, value) 450 | } 451 | 452 | fn end(self) -> Result { 453 | self.inner.end() 454 | } 455 | } 456 | 457 | #[cfg(test)] 458 | mod tests; 459 | -------------------------------------------------------------------------------- /src/ser/error.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | borrow::Cow, 3 | error, fmt, 4 | str::{self, Utf8Error}, 5 | }; 6 | 7 | use serde::ser; 8 | 9 | /// Errors returned during serializing to `application/x-www-form-urlencoded`. 10 | #[derive(Clone, Debug, PartialEq, Eq)] 11 | pub struct Error(ErrorKind); 12 | 13 | #[derive(Clone, Debug, PartialEq, Eq)] 14 | enum ErrorKind { 15 | Custom(Cow<'static, str>), 16 | Utf8(Utf8Error), 17 | } 18 | 19 | impl Error { 20 | pub(super) fn done() -> Self { 21 | Error(ErrorKind::Custom("this pair has already been serialized".into())) 22 | } 23 | 24 | pub(super) fn not_done() -> Self { 25 | Error(ErrorKind::Custom("this pair has not yet been serialized".into())) 26 | } 27 | 28 | pub(super) fn unsupported_key() -> Self { 29 | Error(ErrorKind::Custom("unsupported key".into())) 30 | } 31 | 32 | pub(super) fn unsupported_value() -> Self { 33 | Error(ErrorKind::Custom("unsupported value".into())) 34 | } 35 | 36 | pub(super) fn unsupported_pair() -> Self { 37 | Error(ErrorKind::Custom("unsupported pair".into())) 38 | } 39 | 40 | pub(super) fn top_level() -> Self { 41 | Error(ErrorKind::Custom("top-level serializer supports only maps and structs".into())) 42 | } 43 | 44 | pub(super) fn no_key() -> Self { 45 | Error(ErrorKind::Custom("tried to serialize a value before serializing key".into())) 46 | } 47 | 48 | pub(super) fn utf8(error: Utf8Error) -> Self { 49 | Error(ErrorKind::Utf8(error)) 50 | } 51 | } 52 | 53 | impl fmt::Display for Error { 54 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 55 | match &self.0 { 56 | ErrorKind::Custom(msg) => msg.fmt(f), 57 | ErrorKind::Utf8(err) => write!(f, "invalid UTF-8: {}", err), 58 | } 59 | } 60 | } 61 | 62 | impl error::Error for Error { 63 | /// The lower-level cause of this error, in the case of a `Utf8` error. 64 | fn cause(&self) -> Option<&dyn error::Error> { 65 | match &self.0 { 66 | ErrorKind::Custom(_) => None, 67 | ErrorKind::Utf8(err) => Some(err), 68 | } 69 | } 70 | 71 | /// The lower-level source of this error, in the case of a `Utf8` error. 72 | fn source(&self) -> Option<&(dyn error::Error + 'static)> { 73 | match &self.0 { 74 | ErrorKind::Custom(_) => None, 75 | ErrorKind::Utf8(err) => Some(err), 76 | } 77 | } 78 | } 79 | 80 | impl ser::Error for Error { 81 | fn custom(msg: T) -> Self { 82 | Self(ErrorKind::Custom(format!("{}", msg).into())) 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/ser/key.rs: -------------------------------------------------------------------------------- 1 | use std::{borrow::Cow, ops::Deref}; 2 | 3 | use serde::ser::{self, Serialize}; 4 | 5 | use super::{part::Sink, Error}; 6 | 7 | pub enum Key<'key> { 8 | Static(&'static str), 9 | Dynamic(Cow<'key, str>), 10 | } 11 | 12 | impl Deref for Key<'_> { 13 | type Target = str; 14 | 15 | fn deref(&self) -> &str { 16 | match *self { 17 | Key::Static(key) => key, 18 | Key::Dynamic(ref key) => key, 19 | } 20 | } 21 | } 22 | 23 | impl<'key> From> for Cow<'static, str> { 24 | fn from(key: Key<'key>) -> Self { 25 | match key { 26 | Key::Static(key) => key.into(), 27 | Key::Dynamic(key) => key.into_owned().into(), 28 | } 29 | } 30 | } 31 | 32 | pub struct KeySink { 33 | end: End, 34 | } 35 | 36 | impl KeySink 37 | where 38 | End: for<'key> FnOnce(Key<'key>) -> Result, 39 | { 40 | pub fn new(end: End) -> Self { 41 | KeySink { end } 42 | } 43 | } 44 | 45 | impl Sink for KeySink 46 | where 47 | End: for<'key> FnOnce(Key<'key>) -> Result, 48 | { 49 | type Ok = Ok; 50 | type SerializeSeq = ser::Impossible; 51 | 52 | fn serialize_static_str(self, value: &'static str) -> Result { 53 | (self.end)(Key::Static(value)) 54 | } 55 | 56 | fn serialize_str(self, value: &str) -> Result { 57 | (self.end)(Key::Dynamic(value.into())) 58 | } 59 | 60 | fn serialize_string(self, value: String) -> Result { 61 | (self.end)(Key::Dynamic(value.into())) 62 | } 63 | 64 | fn serialize_none(self) -> Result { 65 | Err(self.unsupported()) 66 | } 67 | 68 | fn serialize_some(self, _value: &T) -> Result { 69 | Err(self.unsupported()) 70 | } 71 | 72 | fn serialize_seq(self) -> Result { 73 | Err(self.unsupported()) 74 | } 75 | 76 | fn unsupported(self) -> Error { 77 | Error::unsupported_key() 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/ser/pair.rs: -------------------------------------------------------------------------------- 1 | use std::{borrow::Cow, mem}; 2 | 3 | use form_urlencoded::{Serializer as UrlEncodedSerializer, Target as UrlEncodedTarget}; 4 | use serde::ser; 5 | 6 | use crate::ser::{key::KeySink, part::PartSerializer, value::ValueSink, Error}; 7 | 8 | pub struct PairSerializer<'input, 'target, Target: UrlEncodedTarget> { 9 | urlencoder: &'target mut UrlEncodedSerializer<'input, Target>, 10 | state: PairState, 11 | } 12 | 13 | impl<'input, 'target, Target> PairSerializer<'input, 'target, Target> 14 | where 15 | Target: 'target + UrlEncodedTarget, 16 | { 17 | pub fn new(urlencoder: &'target mut UrlEncodedSerializer<'input, Target>) -> Self { 18 | PairSerializer { urlencoder, state: PairState::WaitingForKey } 19 | } 20 | } 21 | 22 | impl<'target, Target> ser::Serializer for PairSerializer<'_, 'target, Target> 23 | where 24 | Target: 'target + UrlEncodedTarget, 25 | { 26 | type Ok = (); 27 | type Error = Error; 28 | type SerializeSeq = ser::Impossible<(), Error>; 29 | type SerializeTuple = Self; 30 | type SerializeTupleStruct = ser::Impossible<(), Error>; 31 | type SerializeTupleVariant = ser::Impossible<(), Error>; 32 | type SerializeMap = ser::Impossible<(), Error>; 33 | type SerializeStruct = ser::Impossible<(), Error>; 34 | type SerializeStructVariant = ser::Impossible<(), Error>; 35 | 36 | fn serialize_bool(self, _v: bool) -> Result<(), Error> { 37 | Err(Error::unsupported_pair()) 38 | } 39 | 40 | fn serialize_i8(self, _v: i8) -> Result<(), Error> { 41 | Err(Error::unsupported_pair()) 42 | } 43 | 44 | fn serialize_i16(self, _v: i16) -> Result<(), Error> { 45 | Err(Error::unsupported_pair()) 46 | } 47 | 48 | fn serialize_i32(self, _v: i32) -> Result<(), Error> { 49 | Err(Error::unsupported_pair()) 50 | } 51 | 52 | fn serialize_i64(self, _v: i64) -> Result<(), Error> { 53 | Err(Error::unsupported_pair()) 54 | } 55 | 56 | fn serialize_u8(self, _v: u8) -> Result<(), Error> { 57 | Err(Error::unsupported_pair()) 58 | } 59 | 60 | fn serialize_u16(self, _v: u16) -> Result<(), Error> { 61 | Err(Error::unsupported_pair()) 62 | } 63 | 64 | fn serialize_u32(self, _v: u32) -> Result<(), Error> { 65 | Err(Error::unsupported_pair()) 66 | } 67 | 68 | fn serialize_u64(self, _v: u64) -> Result<(), Error> { 69 | Err(Error::unsupported_pair()) 70 | } 71 | 72 | fn serialize_f32(self, _v: f32) -> Result<(), Error> { 73 | Err(Error::unsupported_pair()) 74 | } 75 | 76 | fn serialize_f64(self, _v: f64) -> Result<(), Error> { 77 | Err(Error::unsupported_pair()) 78 | } 79 | 80 | fn serialize_char(self, _v: char) -> Result<(), Error> { 81 | Err(Error::unsupported_pair()) 82 | } 83 | 84 | fn serialize_str(self, _value: &str) -> Result<(), Error> { 85 | Err(Error::unsupported_pair()) 86 | } 87 | 88 | fn serialize_bytes(self, _value: &[u8]) -> Result<(), Error> { 89 | Err(Error::unsupported_pair()) 90 | } 91 | 92 | fn serialize_unit(self) -> Result<(), Error> { 93 | Err(Error::unsupported_pair()) 94 | } 95 | 96 | fn serialize_unit_struct(self, _name: &'static str) -> Result<(), Error> { 97 | Err(Error::unsupported_pair()) 98 | } 99 | 100 | fn serialize_unit_variant( 101 | self, 102 | _name: &'static str, 103 | _variant_index: u32, 104 | _variant: &'static str, 105 | ) -> Result<(), Error> { 106 | Err(Error::unsupported_pair()) 107 | } 108 | 109 | fn serialize_newtype_struct( 110 | self, 111 | _name: &'static str, 112 | value: &T, 113 | ) -> Result<(), Error> { 114 | value.serialize(self) 115 | } 116 | 117 | fn serialize_newtype_variant( 118 | self, 119 | _name: &'static str, 120 | _variant_index: u32, 121 | _variant: &'static str, 122 | _value: &T, 123 | ) -> Result<(), Error> { 124 | Err(Error::unsupported_pair()) 125 | } 126 | 127 | fn serialize_none(self) -> Result<(), Error> { 128 | Ok(()) 129 | } 130 | 131 | fn serialize_some(self, value: &T) -> Result<(), Error> { 132 | value.serialize(self) 133 | } 134 | 135 | fn serialize_seq(self, _len: Option) -> Result { 136 | Err(Error::unsupported_pair()) 137 | } 138 | 139 | fn serialize_tuple(self, len: usize) -> Result { 140 | if len == 2 { 141 | Ok(self) 142 | } else { 143 | Err(Error::unsupported_pair()) 144 | } 145 | } 146 | 147 | fn serialize_tuple_struct( 148 | self, 149 | _name: &'static str, 150 | _len: usize, 151 | ) -> Result { 152 | Err(Error::unsupported_pair()) 153 | } 154 | 155 | fn serialize_tuple_variant( 156 | self, 157 | _name: &'static str, 158 | _variant_index: u32, 159 | _variant: &'static str, 160 | _len: usize, 161 | ) -> Result { 162 | Err(Error::unsupported_pair()) 163 | } 164 | 165 | fn serialize_map(self, _len: Option) -> Result { 166 | Err(Error::unsupported_pair()) 167 | } 168 | 169 | fn serialize_struct( 170 | self, 171 | _name: &'static str, 172 | _len: usize, 173 | ) -> Result { 174 | Err(Error::unsupported_pair()) 175 | } 176 | 177 | fn serialize_struct_variant( 178 | self, 179 | _name: &'static str, 180 | _variant_index: u32, 181 | _variant: &'static str, 182 | _len: usize, 183 | ) -> Result { 184 | Err(Error::unsupported_pair()) 185 | } 186 | } 187 | 188 | impl<'target, Target> ser::SerializeTuple for PairSerializer<'_, 'target, Target> 189 | where 190 | Target: 'target + UrlEncodedTarget, 191 | { 192 | type Ok = (); 193 | type Error = Error; 194 | 195 | fn serialize_element(&mut self, value: &T) -> Result<(), Error> { 196 | match mem::replace(&mut self.state, PairState::Done) { 197 | PairState::WaitingForKey => { 198 | let key_sink = KeySink::new(|key| Ok(key.into())); 199 | let key_serializer = PartSerializer::new(key_sink); 200 | self.state = PairState::WaitingForValue { key: value.serialize(key_serializer)? }; 201 | Ok(()) 202 | } 203 | PairState::WaitingForValue { key } => { 204 | let result = { 205 | let value_sink = ValueSink::new(self.urlencoder, &key); 206 | let value_serializer = PartSerializer::new(value_sink); 207 | value.serialize(value_serializer) 208 | }; 209 | if result.is_ok() { 210 | self.state = PairState::Done; 211 | } else { 212 | self.state = PairState::WaitingForValue { key }; 213 | } 214 | result 215 | } 216 | PairState::Done => Err(Error::done()), 217 | } 218 | } 219 | 220 | fn end(self) -> Result<(), Error> { 221 | if let PairState::Done = self.state { 222 | Ok(()) 223 | } else { 224 | Err(Error::not_done()) 225 | } 226 | } 227 | } 228 | 229 | enum PairState { 230 | WaitingForKey, 231 | WaitingForValue { key: Cow<'static, str> }, 232 | Done, 233 | } 234 | -------------------------------------------------------------------------------- /src/ser/part.rs: -------------------------------------------------------------------------------- 1 | use std::str; 2 | 3 | use serde::ser::{self, Serializer as _}; 4 | 5 | use super::Error; 6 | 7 | pub struct PartSerializer { 8 | sink: S, 9 | } 10 | 11 | impl PartSerializer { 12 | pub fn new(sink: S) -> Self { 13 | PartSerializer { sink } 14 | } 15 | } 16 | 17 | pub trait Sink: Sized { 18 | type Ok; 19 | type SerializeSeq: ser::SerializeSeq; 20 | 21 | fn serialize_static_str(self, value: &'static str) -> Result; 22 | 23 | fn serialize_str(self, value: &str) -> Result; 24 | fn serialize_string(self, value: String) -> Result; 25 | fn serialize_none(self) -> Result; 26 | 27 | fn serialize_some(self, value: &T) -> Result; 28 | 29 | fn serialize_seq(self) -> Result; 30 | 31 | fn unsupported(self) -> Error; 32 | } 33 | 34 | impl ser::Serializer for PartSerializer { 35 | type Ok = S::Ok; 36 | type Error = Error; 37 | type SerializeSeq = S::SerializeSeq; 38 | type SerializeTuple = ser::Impossible; 39 | type SerializeTupleStruct = ser::Impossible; 40 | type SerializeTupleVariant = ser::Impossible; 41 | type SerializeMap = ser::Impossible; 42 | type SerializeStruct = ser::Impossible; 43 | type SerializeStructVariant = ser::Impossible; 44 | 45 | fn serialize_bool(self, v: bool) -> Result { 46 | self.sink.serialize_static_str(if v { "true" } else { "false" }) 47 | } 48 | 49 | fn serialize_i8(self, v: i8) -> Result { 50 | self.serialize_integer(v) 51 | } 52 | 53 | fn serialize_i16(self, v: i16) -> Result { 54 | self.serialize_integer(v) 55 | } 56 | 57 | fn serialize_i32(self, v: i32) -> Result { 58 | self.serialize_integer(v) 59 | } 60 | 61 | fn serialize_i64(self, v: i64) -> Result { 62 | self.serialize_integer(v) 63 | } 64 | 65 | fn serialize_u8(self, v: u8) -> Result { 66 | self.serialize_integer(v) 67 | } 68 | 69 | fn serialize_u16(self, v: u16) -> Result { 70 | self.serialize_integer(v) 71 | } 72 | 73 | fn serialize_u32(self, v: u32) -> Result { 74 | self.serialize_integer(v) 75 | } 76 | 77 | fn serialize_u64(self, v: u64) -> Result { 78 | self.serialize_integer(v) 79 | } 80 | 81 | fn serialize_u128(self, v: u128) -> Result { 82 | self.serialize_integer(v) 83 | } 84 | 85 | fn serialize_i128(self, v: i128) -> Result { 86 | self.serialize_integer(v) 87 | } 88 | 89 | fn serialize_f32(self, v: f32) -> Result { 90 | #[cfg(feature = "ryu")] 91 | return self.serialize_floating(v); 92 | 93 | #[cfg(not(feature = "ryu"))] 94 | return self.serialize_str(&v.to_string()); 95 | } 96 | 97 | fn serialize_f64(self, v: f64) -> Result { 98 | #[cfg(feature = "ryu")] 99 | return self.serialize_floating(v); 100 | 101 | #[cfg(not(feature = "ryu"))] 102 | return self.serialize_str(&v.to_string()); 103 | } 104 | 105 | fn serialize_char(self, v: char) -> Result { 106 | self.sink.serialize_string(v.to_string()) 107 | } 108 | 109 | fn serialize_str(self, value: &str) -> Result { 110 | self.sink.serialize_str(value) 111 | } 112 | 113 | fn serialize_bytes(self, value: &[u8]) -> Result { 114 | match str::from_utf8(value) { 115 | Ok(value) => self.sink.serialize_str(value), 116 | Err(err) => Err(Error::utf8(err)), 117 | } 118 | } 119 | 120 | fn serialize_unit(self) -> Result { 121 | Err(self.sink.unsupported()) 122 | } 123 | 124 | fn serialize_unit_struct(self, name: &'static str) -> Result { 125 | self.sink.serialize_static_str(name) 126 | } 127 | 128 | fn serialize_unit_variant( 129 | self, 130 | _name: &'static str, 131 | _variant_index: u32, 132 | variant: &'static str, 133 | ) -> Result { 134 | self.sink.serialize_static_str(variant) 135 | } 136 | 137 | fn serialize_newtype_struct( 138 | self, 139 | _name: &'static str, 140 | value: &T, 141 | ) -> Result { 142 | value.serialize(self) 143 | } 144 | 145 | fn serialize_newtype_variant( 146 | self, 147 | _name: &'static str, 148 | _variant_index: u32, 149 | _variant: &'static str, 150 | _value: &T, 151 | ) -> Result { 152 | Err(self.sink.unsupported()) 153 | } 154 | 155 | fn serialize_none(self) -> Result { 156 | self.sink.serialize_none() 157 | } 158 | 159 | fn serialize_some(self, value: &T) -> Result { 160 | self.sink.serialize_some(value) 161 | } 162 | 163 | fn serialize_seq(self, _len: Option) -> Result { 164 | self.sink.serialize_seq() 165 | } 166 | 167 | fn serialize_tuple(self, _len: usize) -> Result { 168 | Err(self.sink.unsupported()) 169 | } 170 | 171 | fn serialize_tuple_struct( 172 | self, 173 | _name: &'static str, 174 | _len: usize, 175 | ) -> Result { 176 | Err(self.sink.unsupported()) 177 | } 178 | 179 | fn serialize_tuple_variant( 180 | self, 181 | _name: &'static str, 182 | _variant_index: u32, 183 | _variant: &'static str, 184 | _len: usize, 185 | ) -> Result { 186 | Err(self.sink.unsupported()) 187 | } 188 | 189 | fn serialize_map(self, _len: Option) -> Result { 190 | Err(self.sink.unsupported()) 191 | } 192 | 193 | fn serialize_struct( 194 | self, 195 | _name: &'static str, 196 | _len: usize, 197 | ) -> Result { 198 | Err(self.sink.unsupported()) 199 | } 200 | 201 | fn serialize_struct_variant( 202 | self, 203 | _name: &'static str, 204 | _variant_index: u32, 205 | _variant: &'static str, 206 | _len: usize, 207 | ) -> Result { 208 | Err(self.sink.unsupported()) 209 | } 210 | } 211 | 212 | impl PartSerializer { 213 | fn serialize_integer(self, value: I) -> Result 214 | where 215 | I: itoa::Integer, 216 | { 217 | let mut buf = itoa::Buffer::new(); 218 | self.serialize_str(buf.format(value)) 219 | } 220 | 221 | #[cfg(feature = "ryu")] 222 | fn serialize_floating(self, value: F) -> Result 223 | where 224 | F: ryu::Float, 225 | { 226 | let mut buf = ryu::Buffer::new(); 227 | self.serialize_str(buf.format(value)) 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /src/ser/tests.rs: -------------------------------------------------------------------------------- 1 | use serde::Serialize; 2 | 3 | #[derive(Serialize)] 4 | struct NewType(T); 5 | 6 | #[test] 7 | fn serialize_newtype_i32() { 8 | let params = &[("field", Some(NewType(11)))]; 9 | assert_eq!(super::to_string(params), Ok("field=11".to_owned())); 10 | } 11 | 12 | #[test] 13 | fn serialize_newtype_u128() { 14 | let params = &[("field", Some(NewType(u128::MAX)))]; 15 | assert_eq!(super::to_string(params), Ok(format!("field={}", u128::MAX))); 16 | } 17 | 18 | #[test] 19 | fn serialize_newtype_i128() { 20 | let params = &[("field", Some(NewType(i128::MIN)))]; 21 | assert_eq!(super::to_string(params), Ok(format!("field={}", i128::MIN))); 22 | } 23 | 24 | #[test] 25 | fn serialize_option_map_int() { 26 | let params = &[("first", Some(23)), ("middle", None), ("last", Some(42))]; 27 | 28 | assert_eq!(super::to_string(params), Ok("first=23&last=42".to_owned())); 29 | } 30 | 31 | #[test] 32 | fn serialize_option_map_string() { 33 | let params = &[("first", Some("hello")), ("middle", None), ("last", Some("world"))]; 34 | 35 | assert_eq!(super::to_string(params), Ok("first=hello&last=world".to_owned())); 36 | } 37 | 38 | #[test] 39 | fn serialize_option_map_bool() { 40 | let params = &[("one", Some(true)), ("two", Some(false))]; 41 | 42 | assert_eq!(super::to_string(params), Ok("one=true&two=false".to_owned())); 43 | } 44 | 45 | #[test] 46 | fn serialize_map_bool() { 47 | let params = &[("one", true), ("two", false)]; 48 | 49 | assert_eq!(super::to_string(params), Ok("one=true&two=false".to_owned())); 50 | } 51 | 52 | #[test] 53 | fn serialize_map_duplicate_keys() { 54 | let params = &[("foo", "a"), ("foo", "b")]; 55 | assert_eq!(super::to_string(params), Ok("foo=a&foo=b".to_owned())); 56 | } 57 | 58 | #[derive(Serialize)] 59 | enum X { 60 | A, 61 | B, 62 | C, 63 | } 64 | 65 | #[test] 66 | fn serialize_unit_enum() { 67 | let params = &[("one", X::A), ("two", X::B), ("three", X::C)]; 68 | assert_eq!(super::to_string(params), Ok("one=A&two=B&three=C".to_owned())); 69 | } 70 | 71 | #[derive(Serialize)] 72 | struct Unit; 73 | 74 | #[test] 75 | fn serialize_unit_struct() { 76 | assert_eq!(super::to_string(Unit), Ok("".to_owned())); 77 | } 78 | 79 | #[test] 80 | fn serialize_unit_type() { 81 | assert_eq!(super::to_string(()), Ok("".to_owned())); 82 | } 83 | 84 | #[derive(Serialize)] 85 | struct Wrapper { 86 | item: T, 87 | } 88 | 89 | #[derive(Serialize)] 90 | struct NewStruct { 91 | list: Vec, 92 | } 93 | 94 | #[derive(Serialize)] 95 | struct Struct { 96 | list: Vec>, 97 | } 98 | 99 | #[derive(Serialize)] 100 | struct ListStruct { 101 | list: Vec>, 102 | } 103 | 104 | #[test] 105 | fn serialize_newstruct() { 106 | let s = NewStruct { list: vec!["hello".into(), "world".into()] }; 107 | assert_eq!("list=hello&list=world".to_owned(), super::to_string(s).unwrap()); 108 | } 109 | 110 | #[test] 111 | fn serialize_vec_bool() { 112 | let params = Wrapper { item: vec![true, false, false] }; 113 | assert_eq!(super::to_string(params).unwrap(), "item=true&item=false&item=false".to_owned()); 114 | } 115 | 116 | #[test] 117 | fn serialize_vec_num() { 118 | let params = Wrapper { item: vec![0, 1, 2] }; 119 | assert_eq!(super::to_string(params).unwrap(), "item=0&item=1&item=2".to_owned()); 120 | } 121 | 122 | #[test] 123 | fn serialize_vec_str() { 124 | let params = Wrapper { item: vec!["hello", "world", "hello"] }; 125 | assert_eq!(super::to_string(params).unwrap(), "item=hello&item=world&item=hello".to_owned()); 126 | } 127 | 128 | #[test] 129 | fn serialize_struct_opt() { 130 | let s = Struct { list: vec![Some("hello".into()), Some("world".into())] }; 131 | assert_eq!("list=hello&list=world".to_owned(), super::to_string(s).unwrap()); 132 | } 133 | 134 | #[test] 135 | fn serialize_struct_newtype() { 136 | let s = ListStruct { list: vec![NewType(0), NewType(1)] }; 137 | assert_eq!("list=0&list=1".to_owned(), super::to_string(s).unwrap()); 138 | } 139 | 140 | #[test] 141 | fn serialize_struct_unit_enum() { 142 | let params = Wrapper { item: vec![X::A, X::B, X::C] }; 143 | assert_eq!(super::to_string(params), Ok("item=A&item=B&item=C".to_owned())); 144 | } 145 | 146 | #[test] 147 | fn serialize_list_of_str() { 148 | let params = &[("list", vec!["hello", "world"])]; 149 | 150 | assert_eq!(super::to_string(params), Ok("list=hello&list=world".to_owned())); 151 | } 152 | 153 | #[test] 154 | fn serialize_multiple_lists() { 155 | #[derive(Serialize)] 156 | struct Lists { 157 | xs: Vec, 158 | ys: Vec, 159 | } 160 | 161 | let params = Lists { xs: vec![true, false], ys: vec![3, 2, 1] }; 162 | 163 | assert_eq!(super::to_string(params), Ok("xs=true&xs=false&ys=3&ys=2&ys=1".to_owned())); 164 | } 165 | 166 | #[test] 167 | fn serialize_nested_list() { 168 | let params = &[("list", vec![vec![0_u8]])]; 169 | assert!(super::to_string(params).unwrap_err().to_string().contains("unsupported")); 170 | } 171 | 172 | #[test] 173 | fn serialize_list_of_option() { 174 | let params = &[("list", vec![Some(10), Some(100)])]; 175 | assert_eq!(super::to_string(params), Ok("list=10&list=100".to_owned())); 176 | } 177 | 178 | #[test] 179 | fn serialize_list_of_newtype() { 180 | let params = &[("list", vec![NewType("test".to_owned())])]; 181 | assert_eq!(super::to_string(params), Ok("list=test".to_owned())); 182 | } 183 | 184 | #[test] 185 | fn serialize_list_of_enum() { 186 | let params = &[("item", vec![X::A, X::B, X::C])]; 187 | assert_eq!(super::to_string(params), Ok("item=A&item=B&item=C".to_owned())); 188 | } 189 | 190 | #[test] 191 | fn serialize_map() { 192 | let mut s = std::collections::BTreeMap::new(); 193 | s.insert("a", "hello"); 194 | s.insert("b", "world"); 195 | 196 | let encoded = super::to_string(s).unwrap(); 197 | assert_eq!("a=hello&b=world", encoded); 198 | } 199 | -------------------------------------------------------------------------------- /src/ser/value.rs: -------------------------------------------------------------------------------- 1 | use std::str; 2 | 3 | use form_urlencoded::{Serializer as UrlEncodedSerializer, Target as UrlEncodedTarget}; 4 | use serde::ser::{Serialize, SerializeSeq}; 5 | 6 | use super::{ 7 | part::{PartSerializer, Sink}, 8 | Error, 9 | }; 10 | 11 | pub struct ValueSink<'input, 'key, 'target, Target> 12 | where 13 | Target: UrlEncodedTarget, 14 | { 15 | urlencoder: &'target mut UrlEncodedSerializer<'input, Target>, 16 | key: &'key str, 17 | nested: bool, 18 | } 19 | 20 | impl<'input, 'key, 'target, Target> ValueSink<'input, 'key, 'target, Target> 21 | where 22 | Target: 'target + UrlEncodedTarget, 23 | { 24 | pub fn new( 25 | urlencoder: &'target mut UrlEncodedSerializer<'input, Target>, 26 | key: &'key str, 27 | ) -> Self { 28 | ValueSink { urlencoder, key, nested: false } 29 | } 30 | } 31 | 32 | impl<'target, Target> Sink for ValueSink<'_, '_, 'target, Target> 33 | where 34 | Target: 'target + UrlEncodedTarget, 35 | { 36 | type Ok = (); 37 | type SerializeSeq = Self; 38 | 39 | fn serialize_str(self, value: &str) -> Result<(), Error> { 40 | self.urlencoder.append_pair(self.key, value); 41 | Ok(()) 42 | } 43 | 44 | fn serialize_static_str(self, value: &'static str) -> Result<(), Error> { 45 | self.serialize_str(value) 46 | } 47 | 48 | fn serialize_string(self, value: String) -> Result<(), Error> { 49 | self.serialize_str(&value) 50 | } 51 | 52 | fn serialize_none(self) -> Result { 53 | Ok(()) 54 | } 55 | 56 | fn serialize_some(self, value: &T) -> Result { 57 | value.serialize(PartSerializer::new(self)) 58 | } 59 | 60 | fn serialize_seq(self) -> Result { 61 | if self.nested { 62 | Err(self.unsupported()) 63 | } else { 64 | Ok(self) 65 | } 66 | } 67 | 68 | fn unsupported(self) -> Error { 69 | Error::unsupported_value() 70 | } 71 | } 72 | 73 | impl<'target, Target> SerializeSeq for ValueSink<'_, '_, 'target, Target> 74 | where 75 | Target: 'target + UrlEncodedTarget, 76 | { 77 | type Ok = (); 78 | type Error = Error; 79 | 80 | fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> 81 | where 82 | T: Serialize + ?Sized, 83 | { 84 | value.serialize(PartSerializer::new(ValueSink { 85 | urlencoder: self.urlencoder, 86 | key: self.key, 87 | nested: true, 88 | })) 89 | } 90 | 91 | fn end(self) -> Result { 92 | Ok(()) 93 | } 94 | } 95 | --------------------------------------------------------------------------------