use crate::error::Result;
use crate::types::{Key, KeyPrefix, Namespace};
#[must_use]
pub fn is_key_within_namespace(key: &Key, namespace: &Namespace) -> bool {
let key_str = key.as_str();
let ns = namespace.as_str();
if key_str == ns {
return true;
}
key_str
.strip_prefix(ns)
.is_some_and(|suffix| suffix.starts_with('/'))
}
pub fn join_namespace_and_leaf(
namespace: &Namespace,
leaf: &str,
) -> Result<Key> {
namespace.join(leaf)
}
#[must_use]
pub fn parent_namespace(
namespace: &Namespace,
) -> Option<Namespace> {
namespace.parent()
}
#[must_use]
pub fn namespace_ancestors(
namespace: &Namespace,
) -> Vec<Namespace> {
let mut current = namespace.clone();
let mut result = Vec::new();
while let Some(parent) = current.parent() {
result.push(parent.clone());
current = parent;
}
result
}
#[must_use]
pub fn namespace_depth(
namespace: &Namespace,
) -> usize {
segment_count(namespace.as_str())
}
#[must_use]
pub fn key_depth(key: &Key) -> usize {
segment_count(key.as_str())
}
#[must_use]
pub fn namespace_leaf(
namespace: &Namespace,
) -> &str {
namespace.leaf()
}
#[must_use]
pub fn key_leaf(key: &Key) -> &str {
key.leaf()
}
#[must_use]
pub fn namespace_prefix(
namespace: &Namespace,
) -> KeyPrefix {
KeyPrefix::new(namespace.as_str())
.expect("validated namespace must create valid prefix")
}
#[must_use]
pub fn key_matches_prefix(
key: &Key,
prefix: &KeyPrefix,
) -> bool {
prefix.matches(key)
}
#[must_use]
pub fn split_key(
key: &Key,
) -> Option<(Namespace, String)> {
let raw = key.as_str();
raw.rsplit_once('/').map(|(prefix, leaf)| {
(
Namespace::new(prefix)
.expect("validated key prefix must be valid namespace"),
leaf.to_owned(),
)
})
}
#[must_use]
pub fn common_namespace(
left: &Key,
right: &Key,
) -> Option<Namespace> {
let left_parts: Vec<&str> =
left.as_str().split('/').collect();
let right_parts: Vec<&str> =
right.as_str().split('/').collect();
let mut shared = Vec::new();
for (a, b) in left_parts.iter().zip(right_parts.iter()) {
if a == b {
shared.push(*a);
} else {
break;
}
}
if shared.is_empty() {
return None;
}
Namespace::new(shared.join("/")).ok()
}
#[must_use]
pub fn trim_outer_separators(
input: &str,
) -> &str {
input.trim_matches('/')
}
#[must_use]
fn segment_count(input: &str) -> usize {
input.split('/').count()
}