diff --git a/Cargo.toml b/Cargo.toml index 9b8c13ee..da1bdac6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_urlencoded" -version = "0.5.2" +version = "0.5.3" authors = ["Anthony Ramine "] license = "MIT/Apache-2.0" repository = "https://github.com/nox/serde_urlencoded" @@ -20,3 +20,6 @@ dtoa = "0.4.0" itoa = "0.4.0" serde = "1.0.0" url = "1.0.0" + +[dev-dependencies] +serde_derive = "1.0" diff --git a/src/de.rs b/src/de.rs index 137093d2..eeb5ff36 100644 --- a/src/de.rs +++ b/src/de.rs @@ -1,7 +1,7 @@ //! Deserialization support for the `application/x-www-form-urlencoded` format. use serde::de::{self, IntoDeserializer}; - +use serde::de::Error as de_Error; use serde::de::value::MapDeserializer; use std::borrow::Cow; use std::io::Read; @@ -197,6 +197,17 @@ impl<'de> de::Deserializer<'de> for Part<'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(self.0)) + } + forward_to_deserialize_any! { char str @@ -210,7 +221,6 @@ impl<'de> de::Deserializer<'de> for Part<'de> { struct identifier tuple - enum ignored_any seq map @@ -230,3 +240,56 @@ impl<'de> de::Deserializer<'de> for Part<'de> { f64 => deserialize_f64, } } + +struct ValueEnumAccess<'de>(Cow<'de, str>); + +impl<'de> 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: de::DeserializeSeed<'de>, + { + let variant = seed.deserialize(self.0.into_deserializer())?; + Ok((variant, UnitOnlyVariantAccess)) + } +} + +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")) + } +} diff --git a/tests/test_deserialize.rs b/tests/test_deserialize.rs index d2fb5fef..ee19374c 100644 --- a/tests/test_deserialize.rs +++ b/tests/test_deserialize.rs @@ -1,4 +1,6 @@ extern crate serde_urlencoded; +#[macro_use] +extern crate serde_derive; #[test] fn deserialize_bytes() { @@ -40,3 +42,21 @@ fn deserialize_unit() { assert_eq!(serde_urlencoded::from_str("&&"), Ok(())); assert!(serde_urlencoded::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!(serde_urlencoded::from_str("one=A&two=B&three=C"), Ok(result)); +} diff --git a/tests/test_serialize.rs b/tests/test_serialize.rs index e4e70eeb..3905ce6b 100644 --- a/tests/test_serialize.rs +++ b/tests/test_serialize.rs @@ -1,4 +1,6 @@ extern crate serde_urlencoded; +#[macro_use] +extern crate serde_derive; #[test] fn serialize_option_map_int() { @@ -32,3 +34,17 @@ fn serialize_map_bool() { assert_eq!(serde_urlencoded::to_string(params), Ok("one=true&two=false".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!(serde_urlencoded::to_string(params), + Ok("one=A&two=B&three=C".to_owned())); +}