use std::borrow::Borrow;
use std::hash::{Hash, Hasher};
use std::fmt::{Debug, Formatter, Result as FmtResult};
use std::iter::FromIterator;
use std::ops::Deref;
use super::helpers::join;
pub const KEY_SEPERATOR: &'static str = "::";
pub struct Key {
value: str,
}
impl PartialEq for Key {
fn eq(&self, other: &Key) -> bool {
PartialEq::eq(&self.value, &other.value)
}
}
impl Eq for Key {}
impl Hash for Key {
fn hash<H: Hasher>(&self, state: &mut H) {
Hash::hash(&self.value, state)
}
}
impl Debug for Key {
fn fmt(&self, fmt: &mut Formatter<'_>) -> FmtResult {
let value = &self.value;
write!(fmt, "{:?}", value)
}
}
impl Key {
pub fn new(key: &str) -> &Key {
unsafe { &*(key as *const str as *const Key) }
}
pub fn components<'a>(&'a self) -> Components<'a> {
let parts = (&self.value).split(KEY_SEPERATOR);
Components { parts }
}
pub fn to_key_buf(&self) -> KeyBuf {
self.to_owned()
}
pub fn start_with<K: AsRef<Key>>(&self, prefix: K) -> bool {
self._starts_with(prefix.as_ref())
}
fn _starts_with(&self, prefix: &Key) -> bool {
self.post_prefix_iterator(prefix).is_some()
}
fn post_prefix_iterator(&self, prefix: &Key) -> Option<impl Iterator<Item = &str>> {
let mut self_components = self.components();
let mut prefix_components = prefix.components();
loop {
let prev_component = self_components.clone();
match (self_components.next(), prefix_components.next()) {
(Some(x), Some(y)) if x == y => continue,
(Some(_), Some(_)) => return None,
(None, Some(_)) => return None,
(Some(_), None) => return Some(prev_component),
(None, None) => return Some(prev_component),
}
}
}
pub fn strip_prefix<K: AsRef<Key>>(&self, prefix: K) -> KeyBuf {
self._strip_prefix(prefix.as_ref())
}
pub fn _strip_prefix(&self, prefix: &Key) -> KeyBuf {
if let Some(iter) = self.post_prefix_iterator(prefix) {
KeyBuf::from_iter(iter)
} else {
self.to_key_buf()
}
}
pub fn extend_with_suffix<K: AsRef<Key>>(&self, suffix: K) -> KeyBuf {
self._extend_with_suffix(suffix.as_ref())
}
fn _extend_with_suffix(&self, suffix: &Key) -> KeyBuf {
let mut result = self.to_key_buf();
result.push(suffix);
result
}
pub fn as_str(&self) -> &str {
&self.value
}
pub fn to_string_with_seperator(&self, seperator: &str) -> String {
join(self.components(), seperator)
}
}
impl AsRef<Key> for Key {
fn as_ref(&self) -> &Key {
self
}
}
impl AsRef<Key> for str {
fn as_ref(&self) -> &Key {
&Key::new(self)
}
}
impl Deref for Key {
type Target = str;
fn deref(&self) -> &str {
&self.value
}
}
impl ToOwned for Key {
type Owned = KeyBuf;
fn to_owned(&self) -> Self::Owned {
KeyBuf {
value: (&self.value).to_owned(),
}
}
}
#[derive(Clone)]
pub struct Components<'a> {
parts: std::str::Split<'a, &'static str>,
}
impl<'a> Iterator for Components<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<Self::Item> {
self.parts.next()
}
}
#[derive(Debug, Clone)]
pub struct KeyBuf {
value: String,
}
impl KeyBuf {
pub fn new() -> Self {
KeyBuf {
value: String::new(),
}
}
pub fn push<K: AsRef<Key>>(&mut self, value: K) {
self._push(value.as_ref())
}
fn _push(&mut self, value: &str) {
if self.value.len() != 0 {
self.value.push_str(KEY_SEPERATOR);
}
self.value.push_str(value);
}
}
impl<'a> FromIterator<&'a str> for KeyBuf {
fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = &'a str>,
{
KeyBuf {
value: join(iter.into_iter(), KEY_SEPERATOR),
}
}
}
impl PartialEq for KeyBuf {
fn eq(&self, other: &KeyBuf) -> bool {
PartialEq::eq(&self.value, &other.value)
}
}
impl Eq for KeyBuf {}
impl Hash for KeyBuf {
fn hash<H: Hasher>(&self, state: &mut H) {
Hash::hash(&self.value, state)
}
}
impl Deref for KeyBuf {
type Target = Key;
fn deref(&self) -> &Key {
Key::new(&self.value)
}
}
impl AsRef<Key> for KeyBuf {
fn as_ref(&self) -> &Key {
Key::new(&self.value)
}
}
impl Borrow<Key> for KeyBuf {
fn borrow(&self) -> &Key {
Key::new(&self.value)
}
}
#[cfg(test)]
mod tests {
use super::{Key, KeyBuf};
#[test]
fn test_creating_key() {
let key = Key::new("hello");
assert_eq!(key.as_str(), "hello");
}
#[test]
fn keybuf_to_key() {
let mut buf = KeyBuf::new();
buf.push("hello");
let key = buf.as_ref();
assert_eq!(key.as_str(), "hello");
}
}