diff --git a/src/known_key.rs b/src/known_key.rs index 2e2ac245..442edd08 100644 --- a/src/known_key.rs +++ b/src/known_key.rs @@ -65,6 +65,80 @@ where } } +/// Trait for targets that support looking up a [`KnownKey`]. +pub trait KnownKeyTarget { + /// The resulting value type produced by the lookup. + type Output; + /// Looks up this key in the target, returning `None` if not present. + #[must_use] + fn lookup<'target>(&'target self, key: &KnownKey<'_>) -> Option<&'target Self::Output>; +} + +/// Trait for targets that support mutable lookup of a [`KnownKey`]. +pub trait KnownKeyTargetMut { + /// The resulting value type produced by the lookup. + type Output; + /// Looks up this key mutably in the target, returning `None` if not present. + fn lookup_mut<'target>( + &'target mut self, + key: &KnownKey<'_>, + ) -> Option<&'target mut Self::Output>; +} + +impl KnownKeyTarget for halfbrown::HashMap +where + K: std::borrow::Borrow + std::hash::Hash + Eq, +{ + type Output = V; + #[cfg_attr(not(feature = "no-inline"), inline)] + fn lookup<'target>(&'target self, key: &KnownKey<'_>) -> Option<&'target V> { + key.map_lookup(self) + } +} + +impl KnownKeyTargetMut for halfbrown::HashMap +where + K: std::borrow::Borrow + std::hash::Hash + Eq, +{ + type Output = V; + #[cfg_attr(not(feature = "no-inline"), inline)] + fn lookup_mut<'target>(&'target mut self, key: &KnownKey<'_>) -> Option<&'target mut V> { + key.map_lookup_mut(self) + } +} + +impl KnownKeyTarget for crate::BorrowedValue<'_> { + type Output = Self; + #[cfg_attr(not(feature = "no-inline"), inline)] + fn lookup<'target>(&'target self, key: &KnownKey<'_>) -> Option<&'target Self> { + self.as_object().and_then(|m| key.map_lookup(m)) + } +} + +impl KnownKeyTargetMut for crate::BorrowedValue<'_> { + type Output = Self; + #[cfg_attr(not(feature = "no-inline"), inline)] + fn lookup_mut<'target>(&'target mut self, key: &KnownKey<'_>) -> Option<&'target mut Self> { + self.as_object_mut().and_then(|m| key.map_lookup_mut(m)) + } +} + +impl KnownKeyTarget for crate::OwnedValue { + type Output = Self; + #[cfg_attr(not(feature = "no-inline"), inline)] + fn lookup<'target>(&'target self, key: &KnownKey<'_>) -> Option<&'target Self> { + self.as_object().and_then(|m| key.map_lookup(m)) + } +} + +impl KnownKeyTargetMut for crate::OwnedValue { + type Output = Self; + #[cfg_attr(not(feature = "no-inline"), inline)] + fn lookup_mut<'target>(&'target mut self, key: &KnownKey<'_>) -> Option<&'target mut Self> { + self.as_object_mut().and_then(|m| key.map_lookup_mut(m)) + } +} + impl<'key> KnownKey<'key> { /// The known key #[cfg_attr(not(feature = "no-inline"), inline)] @@ -82,7 +156,7 @@ impl<'key> KnownKey<'key> { /// ```rust /// use simd_json::prelude::*; /// use simd_json::*; - /// let object = json!({ + /// let object: BorrowedValue = json!({ /// "answer": 42, /// "key": 7 /// }).into(); @@ -91,19 +165,14 @@ impl<'key> KnownKey<'key> { /// ``` #[cfg_attr(not(feature = "no-inline"), inline)] #[must_use] - pub fn lookup<'target, 'value>( - &self, - target: &'target Value<'value>, - ) -> Option<&'target Value<'value>> + pub fn lookup<'target, T>(&self, target: &'target T) -> Option<&'target T::Output> where - 'key: 'value, - 'value: 'target, + T: ?Sized + KnownKeyTarget, { - target.as_object().and_then(|m| self.map_lookup(m)) + target.lookup(self) } - /// Looks up this key in a `Object` the inner representation of an object `Value`, returns None if the - /// key wasn't present. + /// Looks up this key in an `Object`, returns None if the key wasn't present. /// /// ```rust /// use simd_json::prelude::*; @@ -119,16 +188,15 @@ impl<'key> KnownKey<'key> { /// ``` #[cfg_attr(not(feature = "no-inline"), inline)] #[must_use] - pub fn map_lookup<'target, 'value>( + pub fn map_lookup<'target, K, V>( &self, - map: &'target super::borrowed::Object<'value>, - ) -> Option<&'target Value<'value>> + map: &'target halfbrown::HashMap, + ) -> Option<&'target V> where - 'key: 'value, - 'value: 'target, + K: std::borrow::Borrow + std::hash::Hash + Eq, { map.raw_entry() - .from_key_hashed_nocheck(self.hash, &self.key) + .from_key_hashed_nocheck(self.hash, self.key.as_ref()) .map(|kv| kv.1) } @@ -153,18 +221,14 @@ impl<'key> KnownKey<'key> { /// assert_eq!(object["answer"], 42); /// ``` #[cfg_attr(not(feature = "no-inline"), inline)] - pub fn lookup_mut<'target, 'value>( - &self, - target: &'target mut Value<'value>, - ) -> Option<&'target mut Value<'value>> + pub fn lookup_mut<'target, T>(&self, target: &'target mut T) -> Option<&'target mut T::Output> where - 'key: 'value, - 'value: 'target, + T: ?Sized + KnownKeyTargetMut, { - target.as_object_mut().and_then(|m| self.map_lookup_mut(m)) + target.lookup_mut(self) } - /// Looks up this key in a `Object<'value>`, the inner representation of an object value. + /// Looks up this key in an `Object`, the inner representation of an object value. /// returns None if the key wasn't present. /// /// ```rust @@ -187,17 +251,16 @@ impl<'key> KnownKey<'key> { /// /// ``` #[cfg_attr(not(feature = "no-inline"), inline)] - pub fn map_lookup_mut<'target, 'value>( + pub fn map_lookup_mut<'target, K, V>( &self, - map: &'target mut super::borrowed::Object<'value>, - ) -> Option<&'target mut Value<'value>> + map: &'target mut halfbrown::HashMap, + ) -> Option<&'target mut V> where - 'key: 'value, - 'value: 'target, + K: std::borrow::Borrow + std::hash::Hash + Eq, { match map .raw_entry_mut() - .from_key_hashed_nocheck(self.hash, &self.key) + .from_key_hashed_nocheck(self.hash, self.key.as_ref()) { RawEntryMut::Occupied(e) => Some(e.into_mut()), RawEntryMut::Vacant(_e) => None, @@ -400,6 +463,36 @@ mod tests { #![allow(clippy::unnecessary_operation, clippy::non_ascii_literal)] use super::*; + #[test] + fn known_key_owned() { + use crate::OwnedValue; + let mut v = OwnedValue::object(); + v.try_insert("key", 1); + let key1 = KnownKey::from("key"); + let key2 = KnownKey::from("cake"); + + assert!(key1.lookup(&OwnedValue::null()).is_none()); + assert!(key2.lookup(&OwnedValue::null()).is_none()); + assert_eq!(key1.lookup(&v).unwrap().as_u8(), Some(1)); + assert!(key2.lookup(&v).is_none()); + + if let Some(val) = key1.lookup_mut(&mut v) { + *val = OwnedValue::from(42); + } + assert_eq!(key1.lookup(&v).unwrap().as_u8(), Some(42)); + + if let Some(m) = v.as_object() { + assert_eq!(key1.map_lookup(m).unwrap().as_u8(), Some(42)); + assert_eq!(key1.lookup(m).unwrap().as_u8(), Some(42)); + } + if let Some(m) = v.as_object_mut() { + if let Some(val) = key1.map_lookup_mut(m) { + *val = OwnedValue::from(84); + } + } + assert_eq!(key1.lookup(&v).unwrap().as_u8(), Some(84)); + } + #[test] fn known_key() { use crate::cow::Cow;