/// Namespaced cache key.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct CacheKey {
    namespace: String,
    parts: Vec<String>,
}

impl CacheKey {
    /// Creates a key with namespace.
    pub fn new(
        namespace: impl Into<String>,
        parts: impl IntoIterator<Item = impl Into<String>>,
    ) -> Self {
        Self {
            namespace: namespace.into(),
            parts: parts.into_iter().map(Into::into).collect(),
        }
    }

    /// Renders a stable colon-separated key.
    pub fn render(&self) -> String {
        std::iter::once(self.namespace.as_str())
            .chain(self.parts.iter().map(String::as_str))
            .collect::<Vec<_>>()
            .join(":")
    }
}
