witchcraft_metrics/
metric_id.rs1use std::borrow::Cow;
15use std::collections::{btree_map, BTreeMap};
16
17#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
21pub struct MetricId {
22    name: Cow<'static, str>,
23    tags: Tags,
24}
25
26impl MetricId {
27    pub fn new<T>(name: T) -> MetricId
29    where
30        T: Into<Cow<'static, str>>,
31    {
32        MetricId {
33            name: name.into(),
34            tags: Tags(BTreeMap::new()),
35        }
36    }
37
38    pub fn with_tag<K, V>(mut self, key: K, value: V) -> MetricId
40    where
41        K: Into<Cow<'static, str>>,
42        V: Into<Cow<'static, str>>,
43    {
44        self.tags.0.insert(key.into(), value.into());
45        self
46    }
47
48    #[inline]
50    pub fn name(&self) -> &str {
51        &self.name
52    }
53
54    #[inline]
56    pub fn tags(&self) -> &Tags {
57        &self.tags
58    }
59}
60
61impl From<String> for MetricId {
62    #[inline]
63    fn from(s: String) -> Self {
64        MetricId::new(s)
65    }
66}
67
68impl From<&'static str> for MetricId {
69    #[inline]
70    fn from(s: &'static str) -> Self {
71        MetricId::new(s)
72    }
73}
74
75impl From<Cow<'static, str>> for MetricId {
76    #[inline]
77    fn from(s: Cow<'static, str>) -> MetricId {
78        MetricId::new(s)
79    }
80}
81
82#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
84pub struct Tags(BTreeMap<Cow<'static, str>, Cow<'static, str>>);
85
86impl Tags {
87    #[inline]
89    pub fn iter(&self) -> TagsIter<'_> {
90        TagsIter(self.0.iter())
91    }
92}
93
94impl<'a> IntoIterator for &'a Tags {
95    type Item = (&'a str, &'a str);
96    type IntoIter = TagsIter<'a>;
97
98    #[inline]
99    fn into_iter(self) -> TagsIter<'a> {
100        self.iter()
101    }
102}
103
104pub struct TagsIter<'a>(btree_map::Iter<'a, Cow<'static, str>, Cow<'static, str>>);
106
107impl<'a> Iterator for TagsIter<'a> {
108    type Item = (&'a str, &'a str);
109
110    #[inline]
111    fn next(&mut self) -> Option<Self::Item> {
112        self.0.next().map(|(k, v)| (&**k, &**v))
113    }
114
115    #[inline]
116    fn size_hint(&self) -> (usize, Option<usize>) {
117        self.0.size_hint()
118    }
119}
120
121impl<'a> ExactSizeIterator for TagsIter<'a> {}
122
123#[cfg(test)]
124mod test {
125    use crate::MetricId;
126
127    #[test]
128    fn basic() {
129        let id = MetricId::new("foo.bar")
130            .with_tag("a", "b")
131            .with_tag("fizz", "buzz")
132            .with_tag("fizz", "bazz");
133
134        assert_eq!(id.name(), "foo.bar");
135        assert_eq!(
136            id.tags().iter().collect::<Vec<_>>(),
137            &[("a", "b"), ("fizz", "bazz")]
138        );
139    }
140}