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] | ||||
| name = "serde_urlencoded" | ||||
| version = "0.5.2" | ||||
| version = "0.5.3" | ||||
| authors = ["Anthony Ramine <n.oxyde@gmail.com>"] | ||||
| 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" | ||||
|  | ||||
							
								
								
									
										67
									
								
								src/de.rs
									
									
									
									
									
								
							
							
						
						
									
										67
									
								
								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<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! { | ||||
|         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<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; | ||||
| #[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)); | ||||
| } | ||||
|  | ||||
| @ -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())); | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user