Allow map key to be borrowed from &Value

This commit is contained in:
David Tolnay 2018-11-09 09:11:23 -08:00
parent 62f40665f0
commit bcad4a9460
No known key found for this signature in database
GPG Key ID: F9BA143B95FF6D82
2 changed files with 125 additions and 1 deletions

View File

@ -1253,7 +1253,7 @@ impl<'de> serde::Deserializer<'de> for MapKeyDeserializer<'de> {
where
V: Visitor<'de>,
{
self.key.into_deserializer().deserialize_any(visitor)
BorrowedCowStrDeserializer::new(self.key).deserialize_any(visitor)
}
deserialize_integer_key!(deserialize_i8 => visit_i8);
@ -1387,3 +1387,102 @@ impl Value {
}
}
}
struct BorrowedCowStrDeserializer<'de> {
value: Cow<'de, str>,
}
impl<'de> BorrowedCowStrDeserializer<'de> {
fn new(value: Cow<'de, str>) -> Self {
BorrowedCowStrDeserializer { value: value }
}
}
impl<'de> de::Deserializer<'de> for BorrowedCowStrDeserializer<'de> {
type Error = Error;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
match self.value {
Cow::Borrowed(string) => visitor.visit_borrowed_str(string),
Cow::Owned(string) => visitor.visit_string(string),
}
}
fn deserialize_enum<V>(
self,
_name: &str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
visitor.visit_enum(self)
}
forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct identifier ignored_any
}
}
impl<'de> de::EnumAccess<'de> for BorrowedCowStrDeserializer<'de> {
type Error = Error;
type Variant = UnitOnly;
fn variant_seed<T>(self, seed: T) -> Result<(T::Value, Self::Variant), Self::Error>
where
T: de::DeserializeSeed<'de>,
{
let value = seed.deserialize(self)?;
Ok((value, UnitOnly))
}
}
struct UnitOnly;
impl<'de> de::VariantAccess<'de> for UnitOnly {
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(de::Error::invalid_type(
Unexpected::UnitVariant,
&"newtype variant",
))
}
fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
Err(de::Error::invalid_type(
Unexpected::UnitVariant,
&"tuple variant",
))
}
fn struct_variant<V>(
self,
_fields: &'static [&'static str],
_visitor: V,
) -> Result<V::Value, Self::Error>
where
V: de::Visitor<'de>,
{
Err(de::Error::invalid_type(
Unexpected::UnitVariant,
&"struct variant",
))
}
}

View File

@ -2132,3 +2132,28 @@ fn test_boxed_raw_value() {
let array_to_string = serde_json::to_string(&array_from_str).unwrap();
assert_eq!(r#"["a",42,{"foo": "bar"},null]"#, array_to_string);
}
#[test]
fn test_borrow_in_map_key() {
#[derive(Deserialize, Debug)]
struct Outer {
map: BTreeMap<MyMapKey, ()>,
}
#[derive(Ord, PartialOrd, Eq, PartialEq, Debug)]
struct MyMapKey(usize);
impl<'de> Deserialize<'de> for MyMapKey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
let s = <&str>::deserialize(deserializer)?;
let n = s.parse().map_err(de::Error::custom)?;
Ok(MyMapKey(n))
}
}
let value = json!({ "map": { "1": null } });
Outer::deserialize(&value).unwrap();
}