manaconf 0.2.0

a layered configuration library
Documentation
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;

/// The string seperator used between components of a key
pub const KEY_SEPERATOR: &'static str = "::";

// we presume a Key is layout compatible with a 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 {
    /// Create a new key from a &str
    pub fn new(key: &str) -> &Key {
        // This is fine as the lifetime for `&Key` should
        // match the lifetime of the `&str` of `key`
        //
        // And thus we are okay to hold this as a pointer
        //
        // This is pretty much what `std::path::Path` and
        // `std::path::PathBuf` do anyway.
        unsafe { &*(key as *const str as *const Key) }
    }

    /// Gets an iterator over the key's components
    pub fn components<'a>(&'a self) -> Components<'a> {
        let parts = (&self.value).split(KEY_SEPERATOR);

        Components { parts }
    }

    /// Creates a `KeyBuf` from the current `Key`
    pub fn to_key_buf(&self) -> KeyBuf {
        self.to_owned()
    }

    /// Determines if the current key starts with a given `prefix`
    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),
            }
        }
    }

    /// Strips the given `prefix` from the key and returns the modfied key as a
    /// `KeyBuf`
    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
    }

    /// Gets a representation of the key as as a `&str`
    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(),
        }
    }
}

/// Iterator over the components of a `Key`
#[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()
    }
}

/// `KeyBuf` is the owned version of a `Key`.
///
/// It is to `Key` as `PathBuf` is to `Path`
#[derive(Debug, Clone)]
pub struct KeyBuf {
    value: String,
}

impl KeyBuf {
    /// Creates an empty `KeyBuf`
    pub fn new() -> Self {
        KeyBuf {
            value: String::new(),
        }
    }

    /// Pushes a component or series of components into the key
    ///
    /// # Example
    ///
    /// ```
    /// let mut buf = KeyBuf::new();
    /// buf.push("config");
    /// buf.push("section");
    /// buf.push("subsection::item");
    /// buf.push(Key::new("database::host"));
    ///
    /// assert_eq!(buf.as_str(), "config::section::subsection::item::database::host");
    /// ```
    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");
    }
}