From 1b5bef811bc8c650d28f2a1f63b89299acd14ec4 Mon Sep 17 00:00:00 2001 From: Douman Date: Thu, 12 Jul 2018 18:34:27 +0300 Subject: [PATCH] Apply enum PR https://github.com/nox/serde_urlencoded/pull/30 --- serde_urlencoded/src/de.rs | 69 +++++++++++++++++++++- serde_urlencoded/tests/test_deserialize.rs | 20 +++++++ serde_urlencoded/tests/test_serialize.rs | 16 +++++ 3 files changed, 103 insertions(+), 2 deletions(-) diff --git a/serde_urlencoded/src/de.rs b/serde_urlencoded/src/de.rs index 137093d2a..4c3fe1b93 100644 --- a/serde_urlencoded/src/de.rs +++ b/serde_urlencoded/src/de.rs @@ -1,6 +1,7 @@ //! Deserialization support for the `application/x-www-form-urlencoded` format. -use serde::de::{self, IntoDeserializer}; +use serde::de::{self, DeserializeSeed, EnumAccess, IntoDeserializer, VariantAccess, Visitor}; +use serde::de::Error as de_Error; use serde::de::value::MapDeserializer; use std::borrow::Cow; @@ -197,6 +198,12 @@ 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 { value: self.0 }) + } + forward_to_deserialize_any! { char str @@ -210,7 +217,6 @@ impl<'de> de::Deserializer<'de> for Part<'de> { struct identifier tuple - enum ignored_any seq map @@ -230,3 +236,62 @@ impl<'de> de::Deserializer<'de> for Part<'de> { 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")) + } +} diff --git a/serde_urlencoded/tests/test_deserialize.rs b/serde_urlencoded/tests/test_deserialize.rs index d2fb5fef9..ee19374ca 100644 --- a/serde_urlencoded/tests/test_deserialize.rs +++ b/serde_urlencoded/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/serde_urlencoded/tests/test_serialize.rs b/serde_urlencoded/tests/test_serialize.rs index e4e70eeb4..3905ce6b8 100644 --- a/serde_urlencoded/tests/test_serialize.rs +++ b/serde_urlencoded/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())); +}