Merge #30
30: Support deserializing a (keyword) string into a unit-only enum r=nox a=smangelsdorf
This adds support for deserializing a structure such as:
```rust
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
enum SortOrder {
    Asc,
    Desc,
}
#[derive(Serialize, Deserialize, Debug)]
struct SearchOptions {
    sort: SortOrder,
}
```
This is already supported for serialization (and I've added a test case for the existing support as part of this PR), but attempting to deserialize the string `"sort=asc"` would result in the error:
```
invalid type: string "asc", expected enum SortOrder
```
I've made a sample in the playground of the way this is handled in `serde_urlencoded` vs `serde_json`: https://play.rust-lang.org/?gist=75fc1e5bbbc1eec29a472373d47488a0&version=stable
This brings the behaviour in line with the way `serde_json` currently handles this case, which I hope is appropriate. Happy to tweak the behaviour if there's a better way to handle it.
Co-authored-by: Shaun Mangelsdorf <s.mangelsdorf@gmail.com>
			
			
This commit is contained in:
		
						commit
						199ed02274
					
				| @ -1,6 +1,6 @@ | |||||||
| [package] | [package] | ||||||
| name = "serde_urlencoded" | name = "serde_urlencoded" | ||||||
| version = "0.5.2" | version = "0.5.3" | ||||||
| authors = ["Anthony Ramine <n.oxyde@gmail.com>"] | authors = ["Anthony Ramine <n.oxyde@gmail.com>"] | ||||||
| license = "MIT/Apache-2.0" | license = "MIT/Apache-2.0" | ||||||
| repository = "https://github.com/nox/serde_urlencoded" | repository = "https://github.com/nox/serde_urlencoded" | ||||||
| @ -20,3 +20,6 @@ dtoa = "0.4.0" | |||||||
| itoa = "0.4.0" | itoa = "0.4.0" | ||||||
| serde = "1.0.0" | serde = "1.0.0" | ||||||
| url = "1.0.0" | url = "1.0.0" | ||||||
|  | 
 | ||||||
|  | [dev-dependencies] | ||||||
|  | serde_derive = "1.0" | ||||||
|  | |||||||
							
								
								
									
										67
									
								
								src/de.rs
									
									
									
									
									
								
							
							
						
						
									
										67
									
								
								src/de.rs
									
									
									
									
									
								
							| @ -1,7 +1,7 @@ | |||||||
| //! Deserialization support for the `application/x-www-form-urlencoded` format.
 | //! Deserialization support for the `application/x-www-form-urlencoded` format.
 | ||||||
| 
 | 
 | ||||||
| use serde::de::{self, IntoDeserializer}; | use serde::de::{self, IntoDeserializer}; | ||||||
| 
 | use serde::de::Error as de_Error; | ||||||
| use serde::de::value::MapDeserializer; | use serde::de::value::MapDeserializer; | ||||||
| use std::borrow::Cow; | use std::borrow::Cow; | ||||||
| use std::io::Read; | use std::io::Read; | ||||||
| @ -197,6 +197,17 @@ impl<'de> de::Deserializer<'de> for Part<'de> { | |||||||
|         visitor.visit_some(self) |         visitor.visit_some(self) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     fn deserialize_enum<V>( | ||||||
|  |         self, | ||||||
|  |         _name: &'static str, | ||||||
|  |         _variants: &'static [&'static str], | ||||||
|  |         visitor: V, | ||||||
|  |     ) -> Result<V::Value, Self::Error> | ||||||
|  |         where V: de::Visitor<'de>, | ||||||
|  |     { | ||||||
|  |         visitor.visit_enum(ValueEnumAccess(self.0)) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     forward_to_deserialize_any! { |     forward_to_deserialize_any! { | ||||||
|         char |         char | ||||||
|         str |         str | ||||||
| @ -210,7 +221,6 @@ impl<'de> de::Deserializer<'de> for Part<'de> { | |||||||
|         struct |         struct | ||||||
|         identifier |         identifier | ||||||
|         tuple |         tuple | ||||||
|         enum |  | ||||||
|         ignored_any |         ignored_any | ||||||
|         seq |         seq | ||||||
|         map |         map | ||||||
| @ -230,3 +240,56 @@ impl<'de> de::Deserializer<'de> for Part<'de> { | |||||||
|         f64 => deserialize_f64, |         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<V>( | ||||||
|  |         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<T>(self, _seed: T) -> Result<T::Value, Self::Error> | ||||||
|  |         where T: de::DeserializeSeed<'de>, | ||||||
|  |     { | ||||||
|  |         Err(Error::custom("expected unit variant")) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn tuple_variant<V>( | ||||||
|  |         self, | ||||||
|  |         _len: usize, | ||||||
|  |         _visitor: V, | ||||||
|  |     ) -> Result<V::Value, Self::Error> | ||||||
|  |         where V: de::Visitor<'de>, | ||||||
|  |     { | ||||||
|  |         Err(Error::custom("expected unit variant")) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn struct_variant<V>( | ||||||
|  |         self, | ||||||
|  |         _fields: &'static [&'static str], | ||||||
|  |         _visitor: V, | ||||||
|  |     ) -> Result<V::Value, Self::Error> | ||||||
|  |         where V: de::Visitor<'de>, | ||||||
|  |     { | ||||||
|  |         Err(Error::custom("expected unit variant")) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | |||||||
| @ -1,4 +1,6 @@ | |||||||
| extern crate serde_urlencoded; | extern crate serde_urlencoded; | ||||||
|  | #[macro_use] | ||||||
|  | extern crate serde_derive; | ||||||
| 
 | 
 | ||||||
| #[test] | #[test] | ||||||
| fn deserialize_bytes() { | fn deserialize_bytes() { | ||||||
| @ -40,3 +42,21 @@ fn deserialize_unit() { | |||||||
|     assert_eq!(serde_urlencoded::from_str("&&"), Ok(())); |     assert_eq!(serde_urlencoded::from_str("&&"), Ok(())); | ||||||
|     assert!(serde_urlencoded::from_str::<()>("first=23").is_err()); |     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)); | ||||||
|  | } | ||||||
|  | |||||||
| @ -1,4 +1,6 @@ | |||||||
| extern crate serde_urlencoded; | extern crate serde_urlencoded; | ||||||
|  | #[macro_use] | ||||||
|  | extern crate serde_derive; | ||||||
| 
 | 
 | ||||||
| #[test] | #[test] | ||||||
| fn serialize_option_map_int() { | fn serialize_option_map_int() { | ||||||
| @ -32,3 +34,17 @@ fn serialize_map_bool() { | |||||||
|     assert_eq!(serde_urlencoded::to_string(params), |     assert_eq!(serde_urlencoded::to_string(params), | ||||||
|                Ok("one=true&two=false".to_owned())); |                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())); | ||||||
|  | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user