serde_html_form-0.2.6/.cargo_vcs_info.json0000644000000001360000000000100142120ustar { "git": { "sha1": "24a380f581c3ef036d96970af446fa6fc6066c85" }, "path_in_vcs": "" }serde_html_form-0.2.6/.gitignore000064400000000000000000000000221046102023000147640ustar 00000000000000target Cargo.lock serde_html_form-0.2.6/.rustfmt.toml000064400000000000000000000002451046102023000154620ustar 00000000000000format_code_in_doc_comments = true imports_granularity = "Crate" use_small_heuristics = "Max" newline_style = "Unix" reorder_imports = true use_try_shorthand = true serde_html_form-0.2.6/CHANGELOG.md000064400000000000000000000032601046102023000146140ustar 00000000000000# 0.2.6 Fix deserialization of optional sequences of a single non-string element. # 0.2.5 Add `push_to_string` for serializing a struct to the end of an existing `String` buffer (instead of allocating a fresh one for the serialized output). # 0.2.4 Fix deserialization of optional sequences of a single element. # 0.2.3 Improve README and crate documentation (now the exact same, instead of just a single-line description). # 0.2.2 This release only upgrades one of the crates' dev-dependencies. # 0.2.1 This release only upgrades one of the crates' private dependencies. # 0.2.0 Support deserialization of sequences with duplicate keys. This used to fail, but passes now: ```rust let result = vec![("foo".to_owned(), 1), ("bar".to_owned(), 2), ("foo".to_owned(), 3)]; assert_eq!(super::from_str("foo=1&bar=2&foo=3"), Ok(result)); ``` This should mainly affect deserialization to a type that's explicitly a sequence, like arrays or `Vec`, but some other things were changed too so if you are getting unexpected deserialization errors, please open an issue. This release has a minimum Rust version of 1.56. # 0.1.1 Support deserialization of `Option`al values to better support forms with optional inputs of non-string types: ```rust #[derive(Deserialize, PartialEq)] struct MyForm { field: Option, } // What browsers send when a value is given assert_eq!(serde_html_form::from_str("field=5").unwrap(), MyForm { field: Some(5) }); // What browsers send when no value is given assert_eq!(serde_html_form::from_str("field=").unwrap(), MyForm { field: None }); // This also works assert_eq!(serde_html_form::from_str("").unwrap(), MyForm { field: None }); ``` # 0.1.0 Initial release. serde_html_form-0.2.6/Cargo.toml0000644000000026530000000000100122160ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.56" name = "serde_html_form" version = "0.2.6" exclude = ["/.github"] description = "(De-)serialization support for the `application/x-www-form-urlencoded` format" readme = "README.md" keywords = [ "serde", "serialization", "urlencoded", ] categories = [ "encoding", "web-programming", ] license = "MIT" repository = "https://github.com/jplatte/serde_html_form" [lib] bench = false [[bench]] name = "upstream_comparison" harness = false [dependencies.form_urlencoded] version = "1.0.1" [dependencies.indexmap] version = "2.0.0" [dependencies.itoa] version = "1.0.1" [dependencies.ryu] version = "1.0.9" optional = true [dependencies.serde] version = "1.0.136" [dev-dependencies.assert_matches2] version = "0.1.0" [dev-dependencies.divan] version = "0.1.11" [dev-dependencies.serde] version = "1.0.136" features = ["derive"] [dev-dependencies.serde_urlencoded] version = "0.7.1" [features] default = ["ryu"] serde_html_form-0.2.6/Cargo.toml.orig0000644000000021510000000000100131460ustar [package] name = "serde_html_form" version = "0.2.6" license = "MIT" repository = "https://github.com/jplatte/serde_html_form" description = "(De-)serialization support for the `application/x-www-form-urlencoded` format" categories = ["encoding", "web-programming"] keywords = ["serde", "serialization", "urlencoded"] exclude = ["/.github"] edition = "2021" rust-version = "1.56" [lib] bench = false [features] default = ["ryu"] [dependencies] # Percent encoding and mapping of query string to pair of key-values form_urlencoded = "1.0.1" # Used for internal buffering during deserialization indexmap = "2.0.0" # Fast integer serialization itoa = "1.0.1" # Fast and better-looking float serialization ryu = { version = "1.0.9", optional = true } # Contains the Serializer and Deserializer traits serde = "1.0.136" [dev-dependencies] # For the assert_matches! macro assert_matches2 = "0.1.0" # Some tests use structs that derive Serialize / Deserialize serde = { version = "1.0.136", features = ["derive"] } # For benchmarks divan = "0.1.11" serde_urlencoded = "0.7.1" [[bench]] name = "upstream_comparison" harness = false serde_html_form-0.2.6/Cargo.toml.orig000064400000000000000000000021511046102023000156700ustar 00000000000000[package] name = "serde_html_form" version = "0.2.6" license = "MIT" repository = "https://github.com/jplatte/serde_html_form" description = "(De-)serialization support for the `application/x-www-form-urlencoded` format" categories = ["encoding", "web-programming"] keywords = ["serde", "serialization", "urlencoded"] exclude = ["/.github"] edition = "2021" rust-version = "1.56" [lib] bench = false [features] default = ["ryu"] [dependencies] # Percent encoding and mapping of query string to pair of key-values form_urlencoded = "1.0.1" # Used for internal buffering during deserialization indexmap = "2.0.0" # Fast integer serialization itoa = "1.0.1" # Fast and better-looking float serialization ryu = { version = "1.0.9", optional = true } # Contains the Serializer and Deserializer traits serde = "1.0.136" [dev-dependencies] # For the assert_matches! macro assert_matches2 = "0.1.0" # Some tests use structs that derive Serialize / Deserialize serde = { version = "1.0.136", features = ["derive"] } # For benchmarks divan = "0.1.11" serde_urlencoded = "0.7.1" [[bench]] name = "upstream_comparison" harness = false serde_html_form-0.2.6/LICENSE000064400000000000000000000017771046102023000140230ustar 00000000000000Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. serde_html_form-0.2.6/README.md000064400000000000000000000067541046102023000142750ustar 00000000000000# `serde_html_form` (De-)serialization support for the `application/x-www-form-urlencoded` format. This crate is a Rust library for serialising to and deserialising from the [`application/x-www-form-urlencoded`][urlencoded] format. It is built upon [Serde], a high performance generic serialization framework and [rust-url], a URL parser for Rust. It is a fork of [`serde_urlencoded`], with additional support for maps or structs with fields of sequence type (e.g. `Vec`). It also supports `Option` in values, treating `foo=` as `foo: None`. [rust-url]: https://github.com/servo/rust-url [Serde]: https://github.com/serde-rs/serde [urlencoded]: https://url.spec.whatwg.org/#application/x-www-form-urlencoded [`serde_urlencoded`]: https://github.com/nox/serde_urlencoded ## Examples Sequences like `value=x&value=y`: ```rust use serde::Deserialize; #[derive(Debug, PartialEq, Deserialize)] struct Form { // By default, at least one occurrence of this field must be present (this // is mandated by how serde works). // // Since this is usually not desired, use `serde(default)` to instantiate // this struct's field with a `Default` value if input doesn't contain that // field. #[serde(default)] value: Vec, } assert_eq!( serde_html_form::from_str("value=&value=abc"), Ok(Form { value: vec!["".to_owned(), "abc".to_owned()] }) ); assert_eq!( serde_html_form::from_str(""), Ok(Form { value: vec![] }) ); ``` Sequences like `value[]=x&value[]=y`: ```rust use serde::Deserialize; #[derive(Debug, PartialEq, Deserialize)] struct Form { // If you want to support `value[]=x&value[]=y`, you can use // `serde(rename)`. You could even use `serde(alias)` instead to allow both, // but note that mixing both in one input string would also be allowed then. #[serde(default, rename = "value[]")] value: Vec, } assert_eq!( serde_html_form::from_str("value[]=x&value[]=y"), Ok(Form { value: vec!["x".to_owned(), "y".to_owned()] }) ); assert_eq!( serde_html_form::from_str("value[]=hello"), Ok(Form { value: vec!["hello".to_owned()] }) ); ``` Optional values: ```rust use serde::Deserialize; #[derive(Debug, PartialEq, Deserialize)] struct Form { // Finally, this crate also supports deserializing empty values as `None` // if your values are `Option`s. // Note that serde's `Deserialize` derive implicitly allows omission of // `Option`-typed fields (except when combined with some other attributes). single: Option, // Not using `serde(default)` here to require at least one occurrence. at_least_one: Vec>, } assert_eq!( serde_html_form::from_str("at_least_one=5"), Ok(Form { // Implicit `serde(default)` in action. single: None, // `serde_html_form`'s support for optional values being used. at_least_one: vec![Some(5)], }) ); assert_eq!( serde_html_form::from_str("at_least_one=&single=1&at_least_one=5"), Ok(Form { single: Some(1), at_least_one: vec![ // Empty strings get deserialized as `None`. None, // It's no problem that the `at_least_one` field repetitions are // not consecutive (single comes in between). Some(5), ] }) ); assert!( serde_html_form::from_str::
("").is_err(), "at_least_one is not part of the input" ); ``` ## License This crate is licensed under the MIT license ([LICENSE](LICENSE) or ). serde_html_form-0.2.6/src/de/part.rs000064400000000000000000000106121046102023000154750ustar 00000000000000use std::borrow::Cow; use serde::{ de::{self, Error as _, IntoDeserializer}, forward_to_deserialize_any, }; use super::Error; #[derive(PartialEq, PartialOrd, Eq, Ord, Hash)] pub(super) struct Part<'de>(pub Cow<'de, str>); impl<'de> IntoDeserializer<'de> for Part<'de> { type Deserializer = Self; fn into_deserializer(self) -> Self::Deserializer { self } } macro_rules! forward_parsed_value { ($($ty:ident => $method:ident,)*) => { $( fn $method(self, visitor: V) -> Result where V: de::Visitor<'de> { match self.0.parse::<$ty>() { Ok(val) => val.into_deserializer().$method(visitor), Err(e) => Err(de::Error::custom(e)) } } )* } } impl<'de> de::Deserializer<'de> for Part<'de> { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: de::Visitor<'de>, { match self.0 { Cow::Borrowed(value) => visitor.visit_borrowed_str(value), Cow::Owned(value) => visitor.visit_string(value), } } fn deserialize_option(self, visitor: V) -> Result where V: de::Visitor<'de>, { if self.0.is_empty() { visitor.visit_none() } else { visitor.visit_some(self) } } fn deserialize_enum( self, _name: &'static str, _variants: &'static [&'static str], visitor: V, ) -> Result where V: de::Visitor<'de>, { visitor.visit_enum(self) } fn deserialize_newtype_struct( self, _name: &'static str, visitor: V, ) -> Result where V: de::Visitor<'de>, { visitor.visit_newtype_struct(self) } fn deserialize_seq(self, visitor: V) -> Result where V: de::Visitor<'de>, { visitor.visit_seq(PartSeqAccess(Some(self))) } forward_to_deserialize_any! { char str string unit bytes byte_buf unit_struct tuple_struct struct identifier tuple ignored_any map } forward_parsed_value! { bool => deserialize_bool, u8 => deserialize_u8, u16 => deserialize_u16, u32 => deserialize_u32, u64 => deserialize_u64, i8 => deserialize_i8, i16 => deserialize_i16, i32 => deserialize_i32, i64 => deserialize_i64, f32 => deserialize_f32, f64 => deserialize_f64, } } impl<'de> de::EnumAccess<'de> for Part<'de> { type Error = Error; type Variant = UnitOnlyVariantAccess; fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error> where V: de::DeserializeSeed<'de>, { let variant = seed.deserialize(self.0.into_deserializer())?; Ok((variant, UnitOnlyVariantAccess)) } } struct PartSeqAccess<'de>(Option>); impl<'de> de::SeqAccess<'de> for PartSeqAccess<'de> { type Error = Error; fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> where T: de::DeserializeSeed<'de>, { match self.0.take() { Some(value) => seed.deserialize(value).map(Some), None => Ok(None), } } fn size_hint(&self) -> Option { Some(self.0.is_some() as usize) } } pub(crate) struct UnitOnlyVariantAccess; impl<'de> de::VariantAccess<'de> for UnitOnlyVariantAccess { type Error = Error; fn unit_variant(self) -> Result<(), Self::Error> { Ok(()) } fn newtype_variant_seed(self, _seed: T) -> Result where T: de::DeserializeSeed<'de>, { Err(Error::custom("expected unit variant")) } fn tuple_variant(self, _len: usize, _visitor: V) -> Result where V: de::Visitor<'de>, { Err(Error::custom("expected unit variant")) } fn struct_variant( self, _fields: &'static [&'static str], _visitor: V, ) -> Result where V: de::Visitor<'de>, { Err(Error::custom("expected unit variant")) } } serde_html_form-0.2.6/src/de/tests.rs000064400000000000000000000122331046102023000156720ustar 00000000000000use std::collections::BTreeMap; use serde::Deserialize; #[derive(Deserialize, Debug, PartialEq)] struct NewType(T); #[test] fn deserialize_newtype_i32() { let result = vec![("field".to_owned(), NewType(11))]; assert_eq!(super::from_str("field=11"), Ok(result)); } #[test] fn deserialize_bytes() { let result = vec![("first".to_owned(), 23), ("last".to_owned(), 42)]; assert_eq!(super::from_bytes(b"first=23&last=42"), Ok(result)); } #[test] fn deserialize_str() { let result = vec![("first".to_owned(), 23), ("last".to_owned(), 42)]; assert_eq!(super::from_str("first=23&last=42"), Ok(result)); } #[test] fn deserialize_borrowed_str() { let result = vec![("first", 23), ("last", 42)]; assert_eq!(super::from_str("first=23&last=42"), Ok(result)); } #[test] fn deserialize_reader() { let result = vec![("first".to_owned(), 23), ("last".to_owned(), 42)]; assert_eq!(super::from_reader(b"first=23&last=42" as &[_]), Ok(result)); } #[test] fn deserialize_option() { let result = vec![("first".to_owned(), Some(23)), ("last".to_owned(), Some(42))]; assert_eq!(super::from_str("first=23&last=42"), Ok(result)); } #[test] fn deserialize_empty_string() { let result = vec![("first".to_owned(), "")]; assert_eq!(super::from_str("first="), Ok(result)); } #[test] fn deserialize_map() { let result = BTreeMap::from_iter([("first".to_owned(), 23), ("second".to_owned(), 42)]); assert_eq!(super::from_str("first=23&second=42"), Ok(result)); } #[test] fn deserialize_map_vec() { let result = BTreeMap::from_iter([("first".to_owned(), vec![23, 1]), ("second".to_owned(), vec![42])]); assert_eq!(super::from_str("first=23&second=42&first=1"), Ok(result)); } #[test] fn deserialize_tuple_list() { let result = vec![("foo".to_owned(), 1), ("bar".to_owned(), 2), ("foo".to_owned(), 3)]; assert_eq!(super::from_str("foo=1&bar=2&foo=3"), Ok(result)); } #[test] fn deserialize_vec_strings() { #[derive(Deserialize, PartialEq, Debug)] struct Form { value: Vec, } assert_eq!( super::from_str("value=&value=abc"), Ok(Form { value: vec!["".to_owned(), "abc".to_owned()] }) ); } #[test] fn deserialize_option_vec() { #[derive(Deserialize, PartialEq, Debug)] struct Form { value: Option>, } assert_eq!(super::from_str(""), Ok(Form { value: None })); assert_eq!(super::from_str("value=abc"), Ok(Form { value: Some(vec!["abc".to_owned()]) })); assert_eq!( super::from_str("value=abc&value=def"), Ok(Form { value: Some(vec!["abc".to_owned(), "def".to_owned()]) }) ); } #[test] fn deserialize_option_vec_int() { #[derive(Deserialize, PartialEq, Debug)] struct Form { value: Option>, } assert_eq!(super::from_str(""), Ok(Form { value: None })); assert_eq!(super::from_str("value=0"), Ok(Form { value: Some(vec![0]) })); assert_eq!(super::from_str("value=3&value=-1"), Ok(Form { value: Some(vec![3, -1]) })); } #[test] fn deserialize_option_no_value() { #[derive(Deserialize, PartialEq, Debug)] struct Form { value: Option, } assert_eq!(super::from_str("value="), Ok(Form { value: None })); } #[test] fn deserialize_vec_options_no_value() { #[derive(Deserialize, PartialEq, Debug)] struct Form { value: Vec>, } assert_eq!(super::from_str("value=&value=&value="), Ok(Form { value: vec![None, None, None] })); } #[test] fn deserialize_vec_options_some_values() { #[derive(Deserialize, PartialEq, Debug)] struct Form { value: Vec>, } assert_eq!( super::from_str("value=&value=4&value="), Ok(Form { value: vec![None, Some(4.0), None] }) ); } #[test] fn deserialize_option_vec_no_value() { #[derive(Deserialize, PartialEq, Debug)] struct Form { value: Option>, } assert_eq!( super::from_str::("value=&value=&value=").unwrap_err().to_string(), "cannot parse float from empty string" ); } #[test] fn deserialize_option_vec_with_values() { #[derive(Deserialize, PartialEq, Debug)] struct Form { value: Option>, } assert_eq!( super::from_str("value=3&value=4&value=5"), Ok(Form { value: Some(vec![3.0, 4.0, 5.0]) }) ); } #[test] fn deserialize_no_value_err() { #[derive(Deserialize, PartialEq, Debug)] struct Form { value: f64, } assert_eq!( super::from_str::("value=").unwrap_err().to_string(), "cannot parse float from empty string" ); } #[test] fn deserialize_unit() { assert_eq!(super::from_str(""), Ok(())); assert_eq!(super::from_str("&"), Ok(())); assert_eq!(super::from_str("&&"), Ok(())); assert!(super::from_str::<()>("first=23").is_err()); } #[derive(Deserialize, Debug, PartialEq, Eq)] enum X { A, B, C, } #[test] fn deserialize_unit_enum() { let result = vec![("one".to_owned(), X::A), ("two".to_owned(), X::B), ("three".to_owned(), X::C)]; assert_eq!(super::from_str("one=A&two=B&three=C"), Ok(result)); } #[test] fn deserialize_unit_type() { assert_eq!(super::from_str(""), Ok(())); } serde_html_form-0.2.6/src/de/val_or_vec.rs000064400000000000000000000150561046102023000166550ustar 00000000000000use std::{hint::unreachable_unchecked, iter, mem, vec}; use serde::de::{ self, value::{Error, SeqDeserializer}, Deserializer, IntoDeserializer, }; #[derive(Debug)] pub(crate) enum ValOrVec { Val(T), Vec(Vec), } impl ValOrVec { pub fn push(&mut self, new_val: T) { match self { Self::Val(_) => { // Change self to a Vec variant and take ownership of the previous value let old_self = mem::replace(self, ValOrVec::Vec(Vec::with_capacity(2))); let old_val = match old_self { Self::Val(v) => v, // Safety: We would not be in the outer branch otherwise _ => unsafe { unreachable_unchecked() }, }; let vec = match self { ValOrVec::Vec(v) => v, // Safety: We set self to Vec with the mem::replace above _ => unsafe { unreachable_unchecked() }, }; vec.push(old_val); vec.push(new_val); } Self::Vec(vec) => vec.push(new_val), } } fn deserialize_val(self, f: F) -> Result where F: FnOnce(T) -> Result, E: de::Error, { match self { ValOrVec::Val(val) => f(val), ValOrVec::Vec(_) => Err(de::Error::custom("unsupported value")), } } } impl IntoIterator for ValOrVec { type Item = T; type IntoIter = IntoIter; fn into_iter(self) -> Self::IntoIter { IntoIter::new(self) } } pub enum IntoIter { Val(iter::Once), Vec(vec::IntoIter), } impl IntoIter { fn new(vv: ValOrVec) -> Self { match vv { ValOrVec::Val(val) => IntoIter::Val(iter::once(val)), ValOrVec::Vec(vec) => IntoIter::Vec(vec.into_iter()), } } } impl Iterator for IntoIter { type Item = T; fn next(&mut self) -> Option { match self { IntoIter::Val(iter) => iter.next(), IntoIter::Vec(iter) => iter.next(), } } } impl<'de, T> IntoDeserializer<'de> for ValOrVec where T: IntoDeserializer<'de> + Deserializer<'de, Error = Error>, { type Deserializer = Self; fn into_deserializer(self) -> Self::Deserializer { self } } macro_rules! forward_to_part { ($($method:ident,)*) => { $( fn $method(self, visitor: V) -> Result where V: de::Visitor<'de> { self.deserialize_val(move |val| val.$method(visitor)) } )* } } impl<'de, T> Deserializer<'de> for ValOrVec where T: IntoDeserializer<'de> + Deserializer<'de, Error = Error>, { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: de::Visitor<'de>, { match self { Self::Val(val) => val.deserialize_any(visitor), Self::Vec(_) => self.deserialize_seq(visitor), } } fn deserialize_seq(self, visitor: V) -> Result where V: de::Visitor<'de>, { visitor.visit_seq(SeqDeserializer::new(self.into_iter())) } fn deserialize_enum( self, name: &'static str, variants: &'static [&'static str], visitor: V, ) -> Result where V: de::Visitor<'de>, { self.deserialize_val(move |val| val.deserialize_enum(name, variants, visitor)) } fn deserialize_tuple(self, len: usize, visitor: V) -> Result where V: de::Visitor<'de>, { self.deserialize_val(move |val| val.deserialize_tuple(len, visitor)) } fn deserialize_struct( self, name: &'static str, fields: &'static [&'static str], visitor: V, ) -> Result where V: de::Visitor<'de>, { self.deserialize_val(move |val| val.deserialize_struct(name, fields, visitor)) } fn deserialize_unit_struct( self, name: &'static str, visitor: V, ) -> Result where V: de::Visitor<'de>, { self.deserialize_val(move |val| val.deserialize_unit_struct(name, visitor)) } fn deserialize_tuple_struct( self, name: &'static str, len: usize, visitor: V, ) -> Result where V: de::Visitor<'de>, { self.deserialize_val(move |val| val.deserialize_tuple_struct(name, len, visitor)) } fn deserialize_newtype_struct( self, name: &'static str, visitor: V, ) -> Result where V: de::Visitor<'de>, { self.deserialize_val(move |val| val.deserialize_newtype_struct(name, visitor)) } fn deserialize_ignored_any(self, visitor: V) -> Result where V: de::Visitor<'de>, { visitor.visit_unit() } fn deserialize_option(self, visitor: V) -> Result where V: de::Visitor<'de>, { match self { ValOrVec::Val(val) => val.deserialize_option(visitor), ValOrVec::Vec(_) => visitor.visit_some(self), } } forward_to_part! { deserialize_bool, deserialize_char, deserialize_str, deserialize_string, deserialize_bytes, deserialize_byte_buf, deserialize_unit, deserialize_u8, deserialize_u16, deserialize_u32, deserialize_u64, deserialize_i8, deserialize_i16, deserialize_i32, deserialize_i64, deserialize_f32, deserialize_f64, deserialize_identifier, deserialize_map, } } #[cfg(test)] mod tests { use std::borrow::Cow; use assert_matches2::assert_matches; use super::ValOrVec; #[test] fn cow_borrowed() { let mut x = ValOrVec::Val(Cow::Borrowed("a")); x.push(Cow::Borrowed("b")); x.push(Cow::Borrowed("c")); assert_matches!(x, ValOrVec::Vec(v)); assert_eq!(v, vec!["a", "b", "c"]); } #[test] fn cow_owned() { let mut x = ValOrVec::Val(Cow::from("a".to_owned())); x.push(Cow::from("b".to_owned())); x.push(Cow::from("c".to_owned())); assert_matches!(x, ValOrVec::Vec(v)); assert_eq!(v, vec!["a".to_owned(), "b".to_owned(), "c".to_owned()]); } } serde_html_form-0.2.6/src/de.rs000064400000000000000000000120631046102023000145310ustar 00000000000000//! Deserialization support for the `application/x-www-form-urlencoded` format. use std::io::Read; use form_urlencoded::{parse, Parse as UrlEncodedParse}; use indexmap::map::{self, IndexMap}; use serde::{ de::{self, value::MapDeserializer}, forward_to_deserialize_any, }; #[doc(inline)] pub use serde::de::value::Error; mod part; mod val_or_vec; use self::{part::Part, val_or_vec::ValOrVec}; /// Deserializes a `application/x-www-form-urlencoded` value from a `&[u8]`. /// /// ``` /// let meal = vec![ /// ("bread".to_owned(), "baguette".to_owned()), /// ("cheese".to_owned(), "comté".to_owned()), /// ("meat".to_owned(), "ham".to_owned()), /// ("fat".to_owned(), "butter".to_owned()), /// ]; /// /// assert_eq!( /// serde_html_form::from_bytes::>( /// b"bread=baguette&cheese=comt%C3%A9&meat=ham&fat=butter" /// ), /// Ok(meal) /// ); /// ``` pub fn from_bytes<'de, T>(input: &'de [u8]) -> Result where T: de::Deserialize<'de>, { T::deserialize(Deserializer::new(parse(input))) } /// Deserializes a `application/x-www-form-urlencoded` value from a `&str`. /// /// ``` /// let meal = vec![ /// ("bread".to_owned(), "baguette".to_owned()), /// ("cheese".to_owned(), "comté".to_owned()), /// ("meat".to_owned(), "ham".to_owned()), /// ("fat".to_owned(), "butter".to_owned()), /// ]; /// /// assert_eq!( /// serde_html_form::from_str::>( /// "bread=baguette&cheese=comt%C3%A9&meat=ham&fat=butter" /// ), /// Ok(meal) /// ); /// ``` pub fn from_str<'de, T>(input: &'de str) -> Result where T: de::Deserialize<'de>, { from_bytes(input.as_bytes()) } /// Convenience function that reads all bytes from `reader` and deserializes /// them with `from_bytes`. pub fn from_reader(mut reader: R) -> Result where T: de::DeserializeOwned, R: Read, { let mut buf = vec![]; reader .read_to_end(&mut buf) .map_err(|e| de::Error::custom(format_args!("could not read input: {}", e)))?; from_bytes(&buf) } /// A deserializer for the `application/x-www-form-urlencoded` format. /// /// * Supported top-level outputs are structs, maps and sequences of pairs, /// with or without a given length. /// /// * Main `deserialize` methods defers to `deserialize_map`. /// /// * Everything else but `deserialize_seq` and `deserialize_seq_fixed_size` /// defers to `deserialize`. pub struct Deserializer<'de> { inner: UrlEncodedParse<'de>, } impl<'de> Deserializer<'de> { /// Returns a new `Deserializer`. pub fn new(parse: UrlEncodedParse<'de>) -> Self { Deserializer { inner: parse } } } impl<'de> de::Deserializer<'de> for Deserializer<'de> { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: de::Visitor<'de>, { self.deserialize_seq(visitor) } fn deserialize_map(self, visitor: V) -> Result where V: de::Visitor<'de>, { visitor.visit_map(MapDeserializer::new(group_entries(self.inner).into_iter())) } fn deserialize_seq(self, visitor: V) -> Result where V: de::Visitor<'de>, { visitor.visit_seq(MapDeserializer::new(PartIterator(self.inner))) } fn deserialize_unit(self, visitor: V) -> Result where V: de::Visitor<'de>, { let deserializer = MapDeserializer::new(PartIterator(self.inner)); deserializer.end()?; visitor.visit_unit() } fn deserialize_newtype_struct(self, _name: &str, visitor: V) -> Result where V: de::Visitor<'de>, { visitor.visit_newtype_struct(self) } fn deserialize_struct( self, _name: &'static str, _fields: &'static [&'static str], visitor: V, ) -> Result where V: de::Visitor<'de>, { self.deserialize_map(visitor) } forward_to_deserialize_any! { bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string option bytes byte_buf unit_struct tuple_struct identifier tuple enum ignored_any } } struct PartIterator<'de>(UrlEncodedParse<'de>); impl<'de> Iterator for PartIterator<'de> { type Item = (Part<'de>, Part<'de>); fn next(&mut self) -> Option { self.0.next().map(|(k, v)| (Part(k), Part(v))) } } fn group_entries(parse: UrlEncodedParse<'_>) -> IndexMap, ValOrVec>> { use map::Entry::*; let mut res = IndexMap::new(); for (key, value) in parse { match res.entry(Part(key)) { Vacant(v) => { v.insert(ValOrVec::Val(Part(value))); } Occupied(mut o) => { o.get_mut().push(Part(value)); } } } res } #[cfg(test)] mod tests; serde_html_form-0.2.6/src/lib.rs000064400000000000000000000012331046102023000147040ustar 00000000000000#![doc = include_str!("../README.md")] #![warn( rust_2018_idioms, unused_qualifications, clippy::branches_sharing_code, clippy::cloned_instead_of_copied, clippy::empty_line_after_outer_attr, clippy::inefficient_to_string, clippy::mut_mut, clippy::nonstandard_macro_braces, clippy::semicolon_if_nothing_returned, clippy::str_to_string, clippy::unreadable_literal, clippy::unseparated_literal_suffix, clippy::wildcard_imports )] pub mod de; pub mod ser; #[doc(inline)] pub use crate::de::{from_bytes, from_reader, from_str, Deserializer}; #[doc(inline)] pub use crate::ser::{push_to_string, to_string, Serializer}; serde_html_form-0.2.6/src/ser/error.rs000064400000000000000000000043711046102023000160660ustar 00000000000000use std::{ borrow::Cow, error, fmt, str::{self, Utf8Error}, }; use serde::ser; /// Errors returned during serializing to `application/x-www-form-urlencoded`. #[derive(Clone, Debug, PartialEq, Eq)] pub struct Error(ErrorKind); #[derive(Clone, Debug, PartialEq, Eq)] enum ErrorKind { Custom(Cow<'static, str>), Utf8(Utf8Error), } impl Error { pub(super) fn done() -> Self { Error(ErrorKind::Custom("this pair has already been serialized".into())) } pub(super) fn not_done() -> Self { Error(ErrorKind::Custom("this pair has not yet been serialized".into())) } pub(super) fn unsupported_key() -> Self { Error(ErrorKind::Custom("unsupported key".into())) } pub(super) fn unsupported_value() -> Self { Error(ErrorKind::Custom("unsupported value".into())) } pub(super) fn unsupported_pair() -> Self { Error(ErrorKind::Custom("unsupported pair".into())) } pub(super) fn top_level() -> Self { Error(ErrorKind::Custom("top-level serializer supports only maps and structs".into())) } pub(super) fn no_key() -> Self { Error(ErrorKind::Custom("tried to serialize a value before serializing key".into())) } pub(super) fn utf8(error: Utf8Error) -> Self { Error(ErrorKind::Utf8(error)) } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.0 { ErrorKind::Custom(msg) => msg.fmt(f), ErrorKind::Utf8(err) => write!(f, "invalid UTF-8: {}", err), } } } impl error::Error for Error { /// The lower-level cause of this error, in the case of a `Utf8` error. fn cause(&self) -> Option<&dyn error::Error> { match &self.0 { ErrorKind::Custom(_) => None, ErrorKind::Utf8(err) => Some(err), } } /// The lower-level source of this error, in the case of a `Utf8` error. fn source(&self) -> Option<&(dyn error::Error + 'static)> { match &self.0 { ErrorKind::Custom(_) => None, ErrorKind::Utf8(err) => Some(err), } } } impl ser::Error for Error { fn custom(msg: T) -> Self { Self(ErrorKind::Custom(format!("{}", msg).into())) } } serde_html_form-0.2.6/src/ser/key.rs000064400000000000000000000033471046102023000155270ustar 00000000000000use std::{borrow::Cow, ops::Deref}; use serde::ser::{self, Serialize}; use super::{part::Sink, Error}; pub enum Key<'key> { Static(&'static str), Dynamic(Cow<'key, str>), } impl<'key> Deref for Key<'key> { type Target = str; fn deref(&self) -> &str { match *self { Key::Static(key) => key, Key::Dynamic(ref key) => key, } } } impl<'key> From> for Cow<'static, str> { fn from(key: Key<'key>) -> Self { match key { Key::Static(key) => key.into(), Key::Dynamic(key) => key.into_owned().into(), } } } pub struct KeySink { end: End, } impl KeySink where End: for<'key> FnOnce(Key<'key>) -> Result, { pub fn new(end: End) -> Self { KeySink { end } } } impl Sink for KeySink where End: for<'key> FnOnce(Key<'key>) -> Result, { type Ok = Ok; type SerializeSeq = ser::Impossible; fn serialize_static_str(self, value: &'static str) -> Result { (self.end)(Key::Static(value)) } fn serialize_str(self, value: &str) -> Result { (self.end)(Key::Dynamic(value.into())) } fn serialize_string(self, value: String) -> Result { (self.end)(Key::Dynamic(value.into())) } fn serialize_none(self) -> Result { Err(self.unsupported()) } fn serialize_some(self, _value: &T) -> Result { Err(self.unsupported()) } fn serialize_seq(self) -> Result { Err(self.unsupported()) } fn unsupported(self) -> Error { Error::unsupported_key() } } serde_html_form-0.2.6/src/ser/pair.rs000064400000000000000000000150201046102023000156610ustar 00000000000000use std::{borrow::Cow, mem}; use form_urlencoded::{Serializer as UrlEncodedSerializer, Target as UrlEncodedTarget}; use serde::ser; use crate::ser::{key::KeySink, part::PartSerializer, value::ValueSink, Error}; pub struct PairSerializer<'input, 'target, Target: UrlEncodedTarget> { urlencoder: &'target mut UrlEncodedSerializer<'input, Target>, state: PairState, } impl<'input, 'target, Target> PairSerializer<'input, 'target, Target> where Target: 'target + UrlEncodedTarget, { pub fn new(urlencoder: &'target mut UrlEncodedSerializer<'input, Target>) -> Self { PairSerializer { urlencoder, state: PairState::WaitingForKey } } } impl<'input, 'target, Target> ser::Serializer for PairSerializer<'input, 'target, Target> where Target: 'target + UrlEncodedTarget, { type Ok = (); type Error = Error; type SerializeSeq = ser::Impossible<(), Error>; type SerializeTuple = Self; type SerializeTupleStruct = ser::Impossible<(), Error>; type SerializeTupleVariant = ser::Impossible<(), Error>; type SerializeMap = ser::Impossible<(), Error>; type SerializeStruct = ser::Impossible<(), Error>; type SerializeStructVariant = ser::Impossible<(), Error>; fn serialize_bool(self, _v: bool) -> Result<(), Error> { Err(Error::unsupported_pair()) } fn serialize_i8(self, _v: i8) -> Result<(), Error> { Err(Error::unsupported_pair()) } fn serialize_i16(self, _v: i16) -> Result<(), Error> { Err(Error::unsupported_pair()) } fn serialize_i32(self, _v: i32) -> Result<(), Error> { Err(Error::unsupported_pair()) } fn serialize_i64(self, _v: i64) -> Result<(), Error> { Err(Error::unsupported_pair()) } fn serialize_u8(self, _v: u8) -> Result<(), Error> { Err(Error::unsupported_pair()) } fn serialize_u16(self, _v: u16) -> Result<(), Error> { Err(Error::unsupported_pair()) } fn serialize_u32(self, _v: u32) -> Result<(), Error> { Err(Error::unsupported_pair()) } fn serialize_u64(self, _v: u64) -> Result<(), Error> { Err(Error::unsupported_pair()) } fn serialize_f32(self, _v: f32) -> Result<(), Error> { Err(Error::unsupported_pair()) } fn serialize_f64(self, _v: f64) -> Result<(), Error> { Err(Error::unsupported_pair()) } fn serialize_char(self, _v: char) -> Result<(), Error> { Err(Error::unsupported_pair()) } fn serialize_str(self, _value: &str) -> Result<(), Error> { Err(Error::unsupported_pair()) } fn serialize_bytes(self, _value: &[u8]) -> Result<(), Error> { Err(Error::unsupported_pair()) } fn serialize_unit(self) -> Result<(), Error> { Err(Error::unsupported_pair()) } fn serialize_unit_struct(self, _name: &'static str) -> Result<(), Error> { Err(Error::unsupported_pair()) } fn serialize_unit_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, ) -> Result<(), Error> { Err(Error::unsupported_pair()) } fn serialize_newtype_struct( self, _name: &'static str, value: &T, ) -> Result<(), Error> { value.serialize(self) } fn serialize_newtype_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _value: &T, ) -> Result<(), Error> { Err(Error::unsupported_pair()) } fn serialize_none(self) -> Result<(), Error> { Ok(()) } fn serialize_some(self, value: &T) -> Result<(), Error> { value.serialize(self) } fn serialize_seq(self, _len: Option) -> Result { Err(Error::unsupported_pair()) } fn serialize_tuple(self, len: usize) -> Result { if len == 2 { Ok(self) } else { Err(Error::unsupported_pair()) } } fn serialize_tuple_struct( self, _name: &'static str, _len: usize, ) -> Result { Err(Error::unsupported_pair()) } fn serialize_tuple_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize, ) -> Result { Err(Error::unsupported_pair()) } fn serialize_map(self, _len: Option) -> Result { Err(Error::unsupported_pair()) } fn serialize_struct( self, _name: &'static str, _len: usize, ) -> Result { Err(Error::unsupported_pair()) } fn serialize_struct_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize, ) -> Result { Err(Error::unsupported_pair()) } } impl<'input, 'target, Target> ser::SerializeTuple for PairSerializer<'input, 'target, Target> where Target: 'target + UrlEncodedTarget, { type Ok = (); type Error = Error; fn serialize_element(&mut self, value: &T) -> Result<(), Error> { match mem::replace(&mut self.state, PairState::Done) { PairState::WaitingForKey => { let key_sink = KeySink::new(|key| Ok(key.into())); let key_serializer = PartSerializer::new(key_sink); self.state = PairState::WaitingForValue { key: value.serialize(key_serializer)? }; Ok(()) } PairState::WaitingForValue { key } => { let result = { let value_sink = ValueSink::new(self.urlencoder, &key); let value_serializer = PartSerializer::new(value_sink); value.serialize(value_serializer) }; if result.is_ok() { self.state = PairState::Done; } else { self.state = PairState::WaitingForValue { key }; } result } PairState::Done => Err(Error::done()), } } fn end(self) -> Result<(), Error> { if let PairState::Done = self.state { Ok(()) } else { Err(Error::not_done()) } } } enum PairState { WaitingForKey, WaitingForValue { key: Cow<'static, str> }, Done, } serde_html_form-0.2.6/src/ser/part.rs000064400000000000000000000142271046102023000157040ustar 00000000000000use std::str; use serde::ser::{self, Serializer as _}; use super::Error; pub struct PartSerializer { sink: S, } impl PartSerializer { pub fn new(sink: S) -> Self { PartSerializer { sink } } } pub trait Sink: Sized { type Ok; type SerializeSeq: ser::SerializeSeq; fn serialize_static_str(self, value: &'static str) -> Result; fn serialize_str(self, value: &str) -> Result; fn serialize_string(self, value: String) -> Result; fn serialize_none(self) -> Result; fn serialize_some(self, value: &T) -> Result; fn serialize_seq(self) -> Result; fn unsupported(self) -> Error; } impl ser::Serializer for PartSerializer { type Ok = S::Ok; type Error = Error; type SerializeSeq = S::SerializeSeq; type SerializeTuple = ser::Impossible; type SerializeTupleStruct = ser::Impossible; type SerializeTupleVariant = ser::Impossible; type SerializeMap = ser::Impossible; type SerializeStruct = ser::Impossible; type SerializeStructVariant = ser::Impossible; fn serialize_bool(self, v: bool) -> Result { self.sink.serialize_static_str(if v { "true" } else { "false" }) } fn serialize_i8(self, v: i8) -> Result { self.serialize_integer(v) } fn serialize_i16(self, v: i16) -> Result { self.serialize_integer(v) } fn serialize_i32(self, v: i32) -> Result { self.serialize_integer(v) } fn serialize_i64(self, v: i64) -> Result { self.serialize_integer(v) } fn serialize_u8(self, v: u8) -> Result { self.serialize_integer(v) } fn serialize_u16(self, v: u16) -> Result { self.serialize_integer(v) } fn serialize_u32(self, v: u32) -> Result { self.serialize_integer(v) } fn serialize_u64(self, v: u64) -> Result { self.serialize_integer(v) } fn serialize_u128(self, v: u128) -> Result { self.serialize_integer(v) } fn serialize_i128(self, v: i128) -> Result { self.serialize_integer(v) } fn serialize_f32(self, v: f32) -> Result { #[cfg(feature = "ryu")] return self.serialize_floating(v); #[cfg(not(feature = "ryu"))] return self.serialize_str(&v.to_string()); } fn serialize_f64(self, v: f64) -> Result { #[cfg(feature = "ryu")] return self.serialize_floating(v); #[cfg(not(feature = "ryu"))] return self.serialize_str(&v.to_string()); } fn serialize_char(self, v: char) -> Result { self.sink.serialize_string(v.to_string()) } fn serialize_str(self, value: &str) -> Result { self.sink.serialize_str(value) } fn serialize_bytes(self, value: &[u8]) -> Result { match str::from_utf8(value) { Ok(value) => self.sink.serialize_str(value), Err(err) => Err(Error::utf8(err)), } } fn serialize_unit(self) -> Result { Err(self.sink.unsupported()) } fn serialize_unit_struct(self, name: &'static str) -> Result { self.sink.serialize_static_str(name) } fn serialize_unit_variant( self, _name: &'static str, _variant_index: u32, variant: &'static str, ) -> Result { self.sink.serialize_static_str(variant) } fn serialize_newtype_struct( self, _name: &'static str, value: &T, ) -> Result { value.serialize(self) } fn serialize_newtype_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _value: &T, ) -> Result { Err(self.sink.unsupported()) } fn serialize_none(self) -> Result { self.sink.serialize_none() } fn serialize_some(self, value: &T) -> Result { self.sink.serialize_some(value) } fn serialize_seq(self, _len: Option) -> Result { self.sink.serialize_seq() } fn serialize_tuple(self, _len: usize) -> Result { Err(self.sink.unsupported()) } fn serialize_tuple_struct( self, _name: &'static str, _len: usize, ) -> Result { Err(self.sink.unsupported()) } fn serialize_tuple_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize, ) -> Result { Err(self.sink.unsupported()) } fn serialize_map(self, _len: Option) -> Result { Err(self.sink.unsupported()) } fn serialize_struct( self, _name: &'static str, _len: usize, ) -> Result { Err(self.sink.unsupported()) } fn serialize_struct_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize, ) -> Result { Err(self.sink.unsupported()) } } impl PartSerializer { fn serialize_integer(self, value: I) -> Result where I: itoa::Integer, { let mut buf = itoa::Buffer::new(); self.serialize_str(buf.format(value)) } #[cfg(feature = "ryu")] fn serialize_floating(self, value: F) -> Result where F: ryu::Float, { let mut buf = ryu::Buffer::new(); self.serialize_str(buf.format(value)) } } serde_html_form-0.2.6/src/ser/tests.rs000064400000000000000000000116041046102023000160740ustar 00000000000000use serde::Serialize; #[derive(Serialize)] struct NewType(T); #[test] fn serialize_newtype_i32() { let params = &[("field", Some(NewType(11)))]; assert_eq!(super::to_string(params), Ok("field=11".to_owned())); } #[test] fn serialize_newtype_u128() { let params = &[("field", Some(NewType(u128::MAX)))]; assert_eq!(super::to_string(params), Ok(format!("field={}", u128::MAX))); } #[test] fn serialize_newtype_i128() { let params = &[("field", Some(NewType(i128::MIN)))]; assert_eq!(super::to_string(params), Ok(format!("field={}", i128::MIN))); } #[test] fn serialize_option_map_int() { let params = &[("first", Some(23)), ("middle", None), ("last", Some(42))]; assert_eq!(super::to_string(params), Ok("first=23&last=42".to_owned())); } #[test] fn serialize_option_map_string() { let params = &[("first", Some("hello")), ("middle", None), ("last", Some("world"))]; assert_eq!(super::to_string(params), Ok("first=hello&last=world".to_owned())); } #[test] fn serialize_option_map_bool() { let params = &[("one", Some(true)), ("two", Some(false))]; assert_eq!(super::to_string(params), Ok("one=true&two=false".to_owned())); } #[test] fn serialize_map_bool() { let params = &[("one", true), ("two", false)]; assert_eq!(super::to_string(params), Ok("one=true&two=false".to_owned())); } #[test] fn serialize_map_duplicate_keys() { let params = &[("foo", "a"), ("foo", "b")]; assert_eq!(super::to_string(params), Ok("foo=a&foo=b".to_owned())); } #[derive(Serialize)] enum X { A, B, C, } #[test] fn serialize_unit_enum() { let params = &[("one", X::A), ("two", X::B), ("three", X::C)]; assert_eq!(super::to_string(params), Ok("one=A&two=B&three=C".to_owned())); } #[derive(Serialize)] struct Unit; #[test] fn serialize_unit_struct() { assert_eq!(super::to_string(Unit), Ok("".to_owned())); } #[test] fn serialize_unit_type() { assert_eq!(super::to_string(()), Ok("".to_owned())); } #[derive(Serialize)] struct Wrapper { item: T, } #[derive(Serialize)] struct NewStruct { list: Vec, } #[derive(Serialize)] struct Struct { list: Vec>, } #[derive(Serialize)] struct ListStruct { list: Vec>, } #[test] fn serialize_newstruct() { let s = NewStruct { list: vec!["hello".into(), "world".into()] }; assert_eq!("list=hello&list=world".to_owned(), super::to_string(s).unwrap()); } #[test] fn serialize_vec_bool() { let params = Wrapper { item: vec![true, false, false] }; assert_eq!(super::to_string(params).unwrap(), "item=true&item=false&item=false".to_owned()); } #[test] fn serialize_vec_num() { let params = Wrapper { item: vec![0, 1, 2] }; assert_eq!(super::to_string(params).unwrap(), "item=0&item=1&item=2".to_owned()); } #[test] fn serialize_vec_str() { let params = Wrapper { item: vec!["hello", "world", "hello"] }; assert_eq!(super::to_string(params).unwrap(), "item=hello&item=world&item=hello".to_owned()); } #[test] fn serialize_struct_opt() { let s = Struct { list: vec![Some("hello".into()), Some("world".into())] }; assert_eq!("list=hello&list=world".to_owned(), super::to_string(s).unwrap()); } #[test] fn serialize_struct_newtype() { let s = ListStruct { list: vec![NewType(0), NewType(1)] }; assert_eq!("list=0&list=1".to_owned(), super::to_string(s).unwrap()); } #[test] fn serialize_struct_unit_enum() { let params = Wrapper { item: vec![X::A, X::B, X::C] }; assert_eq!(super::to_string(params), Ok("item=A&item=B&item=C".to_owned())); } #[test] fn serialize_list_of_str() { let params = &[("list", vec!["hello", "world"])]; assert_eq!(super::to_string(params), Ok("list=hello&list=world".to_owned())); } #[test] fn serialize_multiple_lists() { #[derive(Serialize)] struct Lists { xs: Vec, ys: Vec, } let params = Lists { xs: vec![true, false], ys: vec![3, 2, 1] }; assert_eq!(super::to_string(params), Ok("xs=true&xs=false&ys=3&ys=2&ys=1".to_owned())); } #[test] fn serialize_nested_list() { let params = &[("list", vec![vec![0_u8]])]; assert!(super::to_string(params).unwrap_err().to_string().contains("unsupported")); } #[test] fn serialize_list_of_option() { let params = &[("list", vec![Some(10), Some(100)])]; assert_eq!(super::to_string(params), Ok("list=10&list=100".to_owned())); } #[test] fn serialize_list_of_newtype() { let params = &[("list", vec![NewType("test".to_owned())])]; assert_eq!(super::to_string(params), Ok("list=test".to_owned())); } #[test] fn serialize_list_of_enum() { let params = &[("item", vec![X::A, X::B, X::C])]; assert_eq!(super::to_string(params), Ok("item=A&item=B&item=C".to_owned())); } #[test] fn serialize_map() { let mut s = std::collections::BTreeMap::new(); s.insert("a", "hello"); s.insert("b", "world"); let encoded = super::to_string(s).unwrap(); assert_eq!("a=hello&b=world", encoded); } serde_html_form-0.2.6/src/ser/value.rs000064400000000000000000000043731046102023000160530ustar 00000000000000use std::str; use form_urlencoded::{Serializer as UrlEncodedSerializer, Target as UrlEncodedTarget}; use serde::ser::{Serialize, SerializeSeq}; use super::{ part::{PartSerializer, Sink}, Error, }; pub struct ValueSink<'input, 'key, 'target, Target> where Target: UrlEncodedTarget, { urlencoder: &'target mut UrlEncodedSerializer<'input, Target>, key: &'key str, nested: bool, } impl<'input, 'key, 'target, Target> ValueSink<'input, 'key, 'target, Target> where Target: 'target + UrlEncodedTarget, { pub fn new( urlencoder: &'target mut UrlEncodedSerializer<'input, Target>, key: &'key str, ) -> Self { ValueSink { urlencoder, key, nested: false } } } impl<'input, 'key, 'target, Target> Sink for ValueSink<'input, 'key, 'target, Target> where Target: 'target + UrlEncodedTarget, { type Ok = (); type SerializeSeq = Self; fn serialize_str(self, value: &str) -> Result<(), Error> { self.urlencoder.append_pair(self.key, value); Ok(()) } fn serialize_static_str(self, value: &'static str) -> Result<(), Error> { self.serialize_str(value) } fn serialize_string(self, value: String) -> Result<(), Error> { self.serialize_str(&value) } fn serialize_none(self) -> Result { Ok(()) } fn serialize_some(self, value: &T) -> Result { value.serialize(PartSerializer::new(self)) } fn serialize_seq(self) -> Result { if self.nested { Err(self.unsupported()) } else { Ok(self) } } fn unsupported(self) -> Error { Error::unsupported_value() } } impl<'input, 'key, 'target, Target> SerializeSeq for ValueSink<'input, 'key, 'target, Target> where Target: 'target + UrlEncodedTarget, { type Ok = (); type Error = Error; fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> where T: Serialize, { value.serialize(PartSerializer::new(ValueSink { urlencoder: self.urlencoder, key: self.key, nested: true, })) } fn end(self) -> Result { Ok(()) } } serde_html_form-0.2.6/src/ser.rs000064400000000000000000000331241046102023000147330ustar 00000000000000//! Serialization support for the `application/x-www-form-urlencoded` format. mod error; mod key; mod pair; mod part; mod value; use std::{borrow::Cow, str}; use form_urlencoded::{Serializer as UrlEncodedSerializer, Target as UrlEncodedTarget}; use serde::ser; pub use self::error::Error; /// Serializes a value into a `application/x-www-form-urlencoded` `String` buffer. /// /// ``` /// let meal = &[("bread", "baguette"), ("cheese", "comté"), ("meat", "ham"), ("fat", "butter")]; /// /// assert_eq!( /// serde_html_form::to_string(meal), /// Ok("bread=baguette&cheese=comt%C3%A9&meat=ham&fat=butter".to_owned()) /// ); /// ``` pub fn to_string(input: T) -> Result { let mut target = String::new(); push_to_string(&mut target, input)?; Ok(target) } /// Serializes a value into the provided `application/x-www-form-urlencoded` `String` buffer. /// /// ``` /// let meal = &[("bread", "baguette"), ("cheese", "comté"), ("meat", "ham"), ("fat", "butter")]; /// /// let mut target = "/cook?".to_owned(); /// /// serde_html_form::ser::push_to_string(&mut target, meal).unwrap(); /// /// assert_eq!(target, "/cook?bread=baguette&cheese=comt%C3%A9&meat=ham&fat=butter"); /// ``` pub fn push_to_string(target: &mut String, input: T) -> Result<(), Error> { let start_position = target.len(); let mut urlencoder = UrlEncodedSerializer::for_suffix(target, start_position); input.serialize(Serializer::new(&mut urlencoder))?; urlencoder.finish(); Ok(()) } /// A serializer for the `application/x-www-form-urlencoded` format. /// /// * Supported top-level inputs are structs, maps and sequences of pairs, /// with or without a given length. /// /// * Supported keys and values are integers, bytes (if convertible to strings), /// unit structs and unit variants. /// /// * Newtype structs defer to their inner values. pub struct Serializer<'input, 'output, Target: UrlEncodedTarget> { urlencoder: &'output mut UrlEncodedSerializer<'input, Target>, } impl<'input, 'output, Target: 'output + UrlEncodedTarget> Serializer<'input, 'output, Target> { /// Returns a new `Serializer`. pub fn new(urlencoder: &'output mut UrlEncodedSerializer<'input, Target>) -> Self { Serializer { urlencoder } } } /// Sequence serializer. pub struct SeqSerializer<'input, 'output, Target: UrlEncodedTarget> { urlencoder: &'output mut UrlEncodedSerializer<'input, Target>, } /// Tuple serializer. /// /// Mostly used for arrays. pub struct TupleSerializer<'input, 'output, Target: UrlEncodedTarget> { urlencoder: &'output mut UrlEncodedSerializer<'input, Target>, } /// Tuple struct serializer. /// /// Never instantiated, tuple structs are not supported. pub struct TupleStructSerializer<'input, 'output, T: UrlEncodedTarget> { inner: ser::Impossible<&'output mut UrlEncodedSerializer<'input, T>, Error>, } /// Tuple variant serializer. /// /// Never instantiated, tuple variants are not supported. pub struct TupleVariantSerializer<'input, 'output, T: UrlEncodedTarget> { inner: ser::Impossible<&'output mut UrlEncodedSerializer<'input, T>, Error>, } /// Map serializer. pub struct MapSerializer<'input, 'output, Target: UrlEncodedTarget> { urlencoder: &'output mut UrlEncodedSerializer<'input, Target>, key: Option>, } /// Struct serializer. pub struct StructSerializer<'input, 'output, Target: UrlEncodedTarget> { urlencoder: &'output mut UrlEncodedSerializer<'input, Target>, } /// Struct variant serializer. /// /// Never instantiated, struct variants are not supported. pub struct StructVariantSerializer<'input, 'output, T: UrlEncodedTarget> { inner: ser::Impossible<&'output mut UrlEncodedSerializer<'input, T>, Error>, } impl<'input, 'output, Target> ser::Serializer for Serializer<'input, 'output, Target> where Target: 'output + UrlEncodedTarget, { type Ok = &'output mut UrlEncodedSerializer<'input, Target>; type Error = Error; type SerializeSeq = SeqSerializer<'input, 'output, Target>; type SerializeTuple = TupleSerializer<'input, 'output, Target>; type SerializeTupleStruct = TupleStructSerializer<'input, 'output, Target>; type SerializeTupleVariant = TupleVariantSerializer<'input, 'output, Target>; type SerializeMap = MapSerializer<'input, 'output, Target>; type SerializeStruct = StructSerializer<'input, 'output, Target>; type SerializeStructVariant = StructVariantSerializer<'input, 'output, Target>; /// Returns an error. fn serialize_bool(self, _v: bool) -> Result { Err(Error::top_level()) } /// Returns an error. fn serialize_i8(self, _v: i8) -> Result { Err(Error::top_level()) } /// Returns an error. fn serialize_i16(self, _v: i16) -> Result { Err(Error::top_level()) } /// Returns an error. fn serialize_i32(self, _v: i32) -> Result { Err(Error::top_level()) } /// Returns an error. fn serialize_i64(self, _v: i64) -> Result { Err(Error::top_level()) } /// Returns an error. fn serialize_u8(self, _v: u8) -> Result { Err(Error::top_level()) } /// Returns an error. fn serialize_u16(self, _v: u16) -> Result { Err(Error::top_level()) } /// Returns an error. fn serialize_u32(self, _v: u32) -> Result { Err(Error::top_level()) } /// Returns an error. fn serialize_u64(self, _v: u64) -> Result { Err(Error::top_level()) } /// Returns an error. fn serialize_f32(self, _v: f32) -> Result { Err(Error::top_level()) } /// Returns an error. fn serialize_f64(self, _v: f64) -> Result { Err(Error::top_level()) } /// Returns an error. fn serialize_char(self, _v: char) -> Result { Err(Error::top_level()) } /// Returns an error. fn serialize_str(self, _value: &str) -> Result { Err(Error::top_level()) } /// Returns an error. fn serialize_bytes(self, _value: &[u8]) -> Result { Err(Error::top_level()) } /// Returns `Ok`. fn serialize_unit(self) -> Result { Ok(self.urlencoder) } /// Returns `Ok`. fn serialize_unit_struct(self, _name: &'static str) -> Result { Ok(self.urlencoder) } /// Returns an error. fn serialize_unit_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, ) -> Result { Err(Error::top_level()) } /// Serializes the inner value, ignoring the newtype name. fn serialize_newtype_struct( self, _name: &'static str, value: &T, ) -> Result { value.serialize(self) } /// Returns an error. fn serialize_newtype_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _value: &T, ) -> Result { Err(Error::top_level()) } /// Returns `Ok`. fn serialize_none(self) -> Result { Ok(self.urlencoder) } /// Serializes the given value. fn serialize_some(self, value: &T) -> Result { value.serialize(self) } /// Serialize a sequence, given length (if any) is ignored. fn serialize_seq(self, _len: Option) -> Result { Ok(SeqSerializer { urlencoder: self.urlencoder }) } /// Returns an error. fn serialize_tuple(self, _len: usize) -> Result { Ok(TupleSerializer { urlencoder: self.urlencoder }) } /// Returns an error. fn serialize_tuple_struct( self, _name: &'static str, _len: usize, ) -> Result { Err(Error::top_level()) } /// Returns an error. fn serialize_tuple_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize, ) -> Result { Err(Error::top_level()) } /// Serializes a map, given length is ignored. fn serialize_map(self, _len: Option) -> Result { Ok(MapSerializer { urlencoder: self.urlencoder, key: None }) } /// Serializes a struct, given length is ignored. fn serialize_struct( self, _name: &'static str, _len: usize, ) -> Result { Ok(StructSerializer { urlencoder: self.urlencoder }) } /// Returns an error. fn serialize_struct_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize, ) -> Result { Err(Error::top_level()) } } impl<'input, 'output, Target> ser::SerializeSeq for SeqSerializer<'input, 'output, Target> where Target: 'output + UrlEncodedTarget, { type Ok = &'output mut UrlEncodedSerializer<'input, Target>; type Error = Error; fn serialize_element(&mut self, value: &T) -> Result<(), Error> { value.serialize(pair::PairSerializer::new(self.urlencoder)) } fn end(self) -> Result { Ok(self.urlencoder) } } impl<'input, 'output, Target> ser::SerializeTuple for TupleSerializer<'input, 'output, Target> where Target: 'output + UrlEncodedTarget, { type Ok = &'output mut UrlEncodedSerializer<'input, Target>; type Error = Error; fn serialize_element(&mut self, value: &T) -> Result<(), Error> { value.serialize(pair::PairSerializer::new(self.urlencoder)) } fn end(self) -> Result { Ok(self.urlencoder) } } impl<'input, 'output, Target> ser::SerializeTupleStruct for TupleStructSerializer<'input, 'output, Target> where Target: 'output + UrlEncodedTarget, { type Ok = &'output mut UrlEncodedSerializer<'input, Target>; type Error = Error; fn serialize_field(&mut self, value: &T) -> Result<(), Error> { self.inner.serialize_field(value) } fn end(self) -> Result { self.inner.end() } } impl<'input, 'output, Target> ser::SerializeTupleVariant for TupleVariantSerializer<'input, 'output, Target> where Target: 'output + UrlEncodedTarget, { type Ok = &'output mut UrlEncodedSerializer<'input, Target>; type Error = Error; fn serialize_field(&mut self, value: &T) -> Result<(), Error> { self.inner.serialize_field(value) } fn end(self) -> Result { self.inner.end() } } impl<'input, 'output, Target> ser::SerializeMap for MapSerializer<'input, 'output, Target> where Target: 'output + UrlEncodedTarget, { type Ok = &'output mut UrlEncodedSerializer<'input, Target>; type Error = Error; fn serialize_entry( &mut self, key: &K, value: &V, ) -> Result<(), Error> { let key_sink = key::KeySink::new(|key| { let value_sink = value::ValueSink::new(self.urlencoder, &key); value.serialize(part::PartSerializer::new(value_sink))?; self.key = None; Ok(()) }); let entry_serializer = part::PartSerializer::new(key_sink); key.serialize(entry_serializer) } fn serialize_key(&mut self, key: &T) -> Result<(), Error> { let key_sink = key::KeySink::new(|key| Ok(key.into())); let key_serializer = part::PartSerializer::new(key_sink); self.key = Some(key.serialize(key_serializer)?); Ok(()) } fn serialize_value(&mut self, value: &T) -> Result<(), Error> { { let key = self.key.as_ref().ok_or_else(Error::no_key)?; let value_sink = value::ValueSink::new(self.urlencoder, key); value.serialize(part::PartSerializer::new(value_sink))?; } self.key = None; Ok(()) } fn end(self) -> Result { Ok(self.urlencoder) } } impl<'input, 'output, Target> ser::SerializeStruct for StructSerializer<'input, 'output, Target> where Target: 'output + UrlEncodedTarget, { type Ok = &'output mut UrlEncodedSerializer<'input, Target>; type Error = Error; fn serialize_field( &mut self, key: &'static str, value: &T, ) -> Result<(), Error> { let value_sink = value::ValueSink::new(self.urlencoder, key); value.serialize(part::PartSerializer::new(value_sink)) } fn end(self) -> Result { Ok(self.urlencoder) } } impl<'input, 'output, Target> ser::SerializeStructVariant for StructVariantSerializer<'input, 'output, Target> where Target: 'output + UrlEncodedTarget, { type Ok = &'output mut UrlEncodedSerializer<'input, Target>; type Error = Error; fn serialize_field( &mut self, key: &'static str, value: &T, ) -> Result<(), Error> { self.inner.serialize_field(key, value) } fn end(self) -> Result { self.inner.end() } } #[cfg(test)] mod tests;