Allow map key to be borrowed from &Value
diff --git a/src/value/de.rs b/src/value/de.rs
index b0e0cb8..f70589b 100644
--- a/src/value/de.rs
+++ b/src/value/de.rs
@@ -1253,7 +1253,7 @@
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 @@
}
}
}
+
+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",
+ ))
+ }
+}
diff --git a/tests/test.rs b/tests/test.rs
index 88f89c7..97da813 100644
--- a/tests/test.rs
+++ b/tests/test.rs
@@ -2132,3 +2132,28 @@
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();
+}