//! Structured keys. use crate::MaybeStaticStr; use std::borrow::Borrow; use std::fmt; /// A type that can be converted into a [`Key`](struct.Key.html). pub trait ToKey { /// Perform the conversion. fn to_key(&self) -> Key<'_>; } impl ToKey for &T where T: ToKey + ?Sized, { fn to_key(&self) -> Key<'_> { (**self).to_key() } } impl<'k> ToKey for Key<'k> { fn to_key(&self) -> Key<'_> { Key { key: self.key } } } impl ToKey for str { fn to_key(&self) -> Key<'_> { Key::from_str(self) } } /// A key in a key-value. // These impls must only be based on the as_str() representation of the key // If a new field (such as an optional index) is added to the key they must not affect comparison #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Key<'k> { key: MaybeStaticStr<'k>, } impl<'k> Key<'k> { /// Get a key from a borrowed string. #[allow(clippy::should_implement_trait)] // Part of the public API now. pub fn from_str(key: &'k str) -> Self { Key { key: MaybeStaticStr::Borrowed(key), } } /// Get a key from a static str. pub fn from_str_static(key: &'static str) -> Self { Key { key: MaybeStaticStr::Static(key), } } /// Get a borrowed string from this key. /// /// The lifetime of the returned string is bound to the borrow of `self` rather /// than to `'k`. pub fn as_str(&self) -> &str { self.key.get() } /// Try to get a borrowed string for the lifetime `'k` from this key. /// /// If the key is a borrow of a longer lived string, this method will return `Some`. /// If the key is internally buffered, this method will return `None`. pub fn to_borrowed_str(&self) -> Option<&'k str> { // NOTE: If the internals of `Key` support buffering this // won't be unconditionally `Some` anymore. We want to keep // this option open Some(self.key.get()) } /// Try to get a static string from this key. pub fn to_static_str(&self) -> Option<&'static str> { match self.key { MaybeStaticStr::Static(s) => Some(s), MaybeStaticStr::Borrowed(_) => None, } } } impl<'k> fmt::Display for Key<'k> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.key.get().fmt(f) } } impl<'k> AsRef for Key<'k> { fn as_ref(&self) -> &str { self.as_str() } } impl<'k> Borrow for Key<'k> { fn borrow(&self) -> &str { self.as_str() } } impl<'k> From<&'k str> for Key<'k> { fn from(s: &'k str) -> Self { Key::from_str(s) } } #[cfg(feature = "std")] mod std_support { use super::*; use std::borrow::Cow; impl ToKey for String { fn to_key(&self) -> Key<'_> { Key::from_str(self) } } impl<'a> ToKey for Cow<'a, str> { fn to_key(&self) -> Key<'_> { Key::from_str(self) } } } #[cfg(feature = "kv_sval")] mod sval_support { use super::*; use sval::Value; use sval_ref::ValueRef; impl<'a> Value for Key<'a> { fn stream<'sval, S: sval::Stream<'sval> + ?Sized>( &'sval self, stream: &mut S, ) -> sval::Result { self.key.get().stream(stream) } } impl<'a> ValueRef<'a> for Key<'a> { fn stream_ref + ?Sized>(&self, stream: &mut S) -> sval::Result { self.key.get().stream(stream) } } } #[cfg(feature = "kv_serde")] mod serde_support { use super::*; use serde_core::{Serialize, Serializer}; impl<'a> Serialize for Key<'a> { fn serialize(&self, serializer: S) -> Result where S: Serializer, { self.key.get().serialize(serializer) } } } #[cfg(test)] mod tests { use super::*; #[test] fn key_from_string() { assert_eq!("a key", Key::from_str("a key").as_str()); } #[test] fn key_to_borrowed() { assert_eq!("a key", Key::from_str("a key").to_borrowed_str().unwrap()); } #[test] fn key_static_eq() { assert_eq!(Key::from_str_static("a key"), Key::from_str_static("a key")); } #[test] fn key_borrowed_eq() { const KEY: &str = "a key"; let k1 = String::from(KEY); let k2 = String::from(KEY); assert_eq!(Key::from_str(&k1), Key::from_str(&k2)); } #[test] fn key_borrowed_and_static_eq() { const KEY: &str = "a key"; let static_key = Key::from_str_static(KEY); let borrowed_key = Key::from_str(KEY); assert_eq!(static_key, borrowed_key); } }