use caseless::default_case_fold_str;
use std::fmt;
use std::hash::{Hash, Hasher};
const KEY_DELIMITER: &str = ":";
#[derive(Clone)]
pub struct ConfigKey(String);
impl ConfigKey {
fn new() -> Self {
Self(String::new())
}
pub fn empty() -> Self {
Self::new()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn separator() -> &'static str {
KEY_DELIMITER
}
pub fn section_key(&self) -> Self {
if self == "" {
ConfigKey::new()
} else {
match self.0.rfind(KEY_DELIMITER) {
None => self.clone(),
Some(i) => Self(self.0[(i + 1)..].to_owned()),
}
}
}
pub fn parent(&self) -> Self {
if self == "" {
ConfigKey::new()
} else {
match self.0.rfind(KEY_DELIMITER) {
None => ConfigKey::new(),
Some(i) => Self(self.0[..i].to_owned()),
}
}
}
pub fn combine<S2: Into<ConfigKey>>(&self, key: S2) -> Self {
let key = key.into();
if self == "" {
key
} else {
let mut s = String::with_capacity(self.len() + key.len() + KEY_DELIMITER.len());
s.push_str(self.as_ref());
s.push_str(KEY_DELIMITER);
s.push_str(key.as_ref());
Self(s)
}
}
pub fn join<S: Into<ConfigKey>, I: IntoIterator<Item = S>>(parts: I) -> Self {
let mut s = String::with_capacity(50);
let mut first = true;
for part in parts.into_iter().filter_map(|part| {
let part = part.into();
if part.as_ref() == "" {
None
} else {
Some(part)
}
}) {
if first {
first = false;
} else {
s.push_str(KEY_DELIMITER);
}
s.push_str(part.as_ref());
}
Self(s)
}
pub fn unsafe_from<S: Into<String>>(value: S) -> Self {
Self(value.into())
}
}
impl fmt::Display for ConfigKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
impl fmt::Debug for ConfigKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.0, f)
}
}
impl AsRef<str> for ConfigKey {
fn as_ref(&self) -> &str {
&self.0
}
}
impl Hash for ConfigKey {
#[inline]
fn hash<H: Hasher>(&self, hasher: &mut H) {
self.0.hash(hasher)
}
}
impl PartialEq for ConfigKey {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.0.eq(&other.0)
}
}
impl PartialEq<String> for ConfigKey {
fn eq(&self, other: &String) -> bool {
self.eq(&ConfigKey::from(other))
}
}
impl PartialEq<str> for ConfigKey {
fn eq(&self, other: &str) -> bool {
self.eq(&ConfigKey::from(other))
}
}
impl PartialEq<&String> for ConfigKey {
fn eq(&self, other: &&String) -> bool {
self.eq(&ConfigKey::from(*other))
}
}
impl PartialEq<&str> for ConfigKey {
fn eq(&self, other: &&str) -> bool {
self.eq(&ConfigKey::from(*other))
}
}
impl Eq for ConfigKey {}
impl From<&str> for ConfigKey {
fn from(value: &str) -> Self {
ConfigKey(default_case_fold_str(value))
}
}
impl From<&String> for ConfigKey {
#[inline]
fn from(value: &String) -> Self {
let s: &str = &value;
ConfigKey::from(s)
}
}
impl From<String> for ConfigKey {
#[inline]
fn from(value: String) -> Self {
let s: &str = &value;
ConfigKey::from(s)
}
}
impl From<&ConfigKey> for ConfigKey {
#[inline]
fn from(value: &ConfigKey) -> Self {
value.clone()
}
}
impl Into<String> for ConfigKey {
fn into(self) -> String {
self.0
}
}