//! Deserialization support for the `application/x-www-form-urlencoded` format. use serde::de::Error as de_Error; use serde::de::{ self, DeserializeSeed, EnumAccess, IntoDeserializer, VariantAccess, Visitor, }; use serde::de::value::MapDeserializer; use std::borrow::Cow; use std::io::Read; use url::form_urlencoded::parse; use url::form_urlencoded::Parse as UrlEncodedParse; #[doc(inline)] pub use serde::de::value::Error; /// Deserializes a `application/x-wwww-url-encoded` value from a `&[u8]`. /// /// ```ignore /// 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_urlencoded::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-wwww-url-encoded` value from a `&str`. /// /// ```ignore /// 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_urlencoded::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()) } #[allow(dead_code)] /// 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: MapDeserializer<'de, PartIterator<'de>, Error>, } impl<'de> Deserializer<'de> { /// Returns a new `Deserializer`. pub fn new(parser: UrlEncodedParse<'de>) -> Self { Deserializer { inner: MapDeserializer::new(PartIterator(parser)), } } } 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_map(visitor) } fn deserialize_map(self, visitor: V) -> Result where V: de::Visitor<'de>, { visitor.visit_map(self.inner) } fn deserialize_seq(self, visitor: V) -> Result where V: de::Visitor<'de>, { visitor.visit_seq(self.inner) } fn deserialize_unit(self, visitor: V) -> Result where V: de::Visitor<'de>, { self.inner.end()?; visitor.visit_unit() } forward_to_deserialize_any! { bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string option bytes byte_buf unit_struct newtype_struct tuple_struct 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))) } } struct Part<'de>(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>, { self.0.into_deserializer().deserialize_any(visitor) } fn deserialize_option(self, visitor: V) -> Result where V: de::Visitor<'de>, { 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(ValueEnumAccess { value: self.0 }) } forward_to_deserialize_any! { char str string unit bytes byte_buf unit_struct newtype_struct tuple_struct struct identifier tuple ignored_any seq 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, } } /// Provides access to a keyword which can be deserialized into an enum variant. The enum variant /// must be a unit variant, otherwise deserialization will fail. struct ValueEnumAccess<'de> { value: Cow<'de, str>, } impl<'de> EnumAccess<'de> for ValueEnumAccess<'de> { type Error = Error; type Variant = UnitOnlyVariantAccess; fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error> where V: DeserializeSeed<'de>, { let variant = seed.deserialize(self.value.into_deserializer())?; Ok((variant, UnitOnlyVariantAccess)) } } /// A visitor for deserializing the contents of the enum variant. As we only support /// `unit_variant`, all other variant types will return an error. struct UnitOnlyVariantAccess; impl<'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: DeserializeSeed<'de>, { Err(Error::custom("expected unit variant")) } fn tuple_variant(self, _len: usize, _visitor: V) -> Result where V: Visitor<'de>, { Err(Error::custom("expected unit variant")) } fn struct_variant( self, _fields: &'static [&'static str], _visitor: V, ) -> Result where V: Visitor<'de>, { Err(Error::custom("expected unit variant")) } }