use std::collections::VecDeque; use std::ops::{Deref, DerefMut}; /// A double-ended vec of strings constituting a metric name or a future part thereof. #[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Default)] pub struct NameParts { /// Nodes are stored in order or their final appearance in the names /// If there is no namespace, the deque is empty. nodes: VecDeque, } impl NameParts { /// Returns true if this instance is equal to or a subset (more specific) of the target instance. /// e.g. `a.b.c` is within `a.b` /// e.g. `a.d.c` is not within `a.b` pub fn is_within(&self, other: &NameParts) -> bool { // quick check: if this name has less parts it cannot be equal or more specific if self.len() < other.nodes.len() { return false; } for (i, part) in other.nodes.iter().enumerate() { if part != &self.nodes[i] { return false; } } true } /// Make a name in this namespace pub fn make_name>(&self, leaf: S) -> MetricName { let mut nodes = self.clone(); nodes.push_back(leaf.into()); MetricName { nodes } } /// Extract a copy of the last name part /// Panics if empty pub fn short(&self) -> MetricName { self.back().expect("Short metric name").clone().into() } } /// Turn any string into a StringDeque impl> From for NameParts { fn from(name_part: S) -> Self { let name: String = name_part.into(); // can we do better than asserting? empty names should not exist, ever... debug_assert!(!name.is_empty()); let mut nodes = NameParts::default(); nodes.push_front(name); nodes } } /// Enable use of VecDeque methods such as len(), push_*, insert()... impl Deref for NameParts { type Target = VecDeque; fn deref(&self) -> &Self::Target { &self.nodes } } /// Enable use of VecDeque methods such as len(), push_*, insert()... impl DerefMut for NameParts { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.nodes } } /// The name of a metric, including the concatenated possible namespaces in which it was defined. #[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)] pub struct MetricName { nodes: NameParts, } impl MetricName { /// Prepend to the existing namespace. pub fn prepend>(mut self, namespace: S) -> Self { let parts: NameParts = namespace.into(); parts .iter() .rev() .for_each(|node| self.nodes.push_front(node.clone())); self } /// Append to the existing namespace. pub fn append>(mut self, namespace: S) -> Self { let offset = self.nodes.len() - 1; let parts: NameParts = namespace.into(); for (i, part) in parts.iter().enumerate() { self.nodes.insert(i + offset, part.clone()) } self } /// Combine name parts into a string. pub fn join(&self, separator: &str) -> String { self.nodes .iter() .map(|s| &**s) .collect::>() .join(separator) } } impl> From for MetricName { fn from(name: S) -> Self { MetricName { nodes: NameParts::from(name), } } } impl Deref for MetricName { type Target = NameParts; fn deref(&self) -> &Self::Target { &self.nodes } } impl DerefMut for MetricName { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.nodes } } #[cfg(test)] mod test { use super::*; #[test] fn string_deque_within_same() { let mut sd1: NameParts = "c".into(); sd1.push_front("b".into()); assert_eq!(true, sd1.is_within(&sd1)); } #[test] fn string_deque_within_other() { let mut sd1: NameParts = "b".into(); sd1.push_front("a".into()); let mut sd2: NameParts = "c".into(); sd2.push_front("b".into()); sd2.push_front("a".into()); assert_eq!(true, sd2.is_within(&sd1)); assert_eq!(false, sd1.is_within(&sd2)); } }