1use std::collections::HashSet;
18use std::fmt;
19
20mod matcher;
21pub use matcher::{MatchOp, Matcher, Matchers};
22
23pub const METRIC_NAME: &str = "__name__";
25pub const ALERT_NAME: &str = "alertname";
27pub const BUCKET_LABEL: &str = "le";
29pub const INSTANCE_NAME: &str = "instance";
31
32pub type Label = String;
33
34#[derive(Debug, Clone, PartialEq, Eq)]
35pub struct Labels {
36 pub labels: Vec<Label>,
37}
38
39impl Labels {
40 pub fn append(mut self, l: Label) -> Self {
41 self.labels.push(l);
42 self
43 }
44
45 pub fn new(ls: Vec<&str>) -> Self {
46 let labels = ls.iter().map(|s| s.to_string()).collect();
47 Self { labels }
48 }
49
50 pub fn is_empty(&self) -> bool {
51 self.labels.is_empty()
52 }
53
54 pub fn is_joint(&self, ls: &Labels) -> bool {
55 let s1: HashSet<&String> = self.labels.iter().collect();
56 let s2: HashSet<&String> = ls.labels.iter().collect();
57
58 !s1.is_disjoint(&s2)
59 }
60
61 pub fn intersect(&self, ls: &Labels) -> Labels {
62 let s1: HashSet<&String> = self.labels.iter().collect();
63 let s2: HashSet<&String> = ls.labels.iter().collect();
64 let labels = s1.intersection(&s2).map(|s| s.to_string()).collect();
65
66 Self { labels }
67 }
68}
69
70impl fmt::Display for Labels {
71 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72 write!(f, "{}", self.labels.join(", "))
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79
80 #[test]
81 fn test_to_string() {
82 let cases = vec![
83 (vec![], ""),
84 (vec!["foo"], "foo"),
85 (vec!["foo", "bar"], "foo, bar"),
86 (vec!["foo", "foo", "bar"], "foo, foo, bar"),
87 ];
88
89 for (ls, expect) in cases {
90 let lb = Labels::new(ls);
91 assert_eq!(expect, lb.to_string())
92 }
93 }
94
95 #[test]
96 fn test_is_joint() {
97 let cases = vec![
98 (vec!["foo"], vec!["bar"], false),
99 (vec!["foo"], vec!["foo", "bar"], true),
100 (vec!["foo"], vec!["foo"], true),
101 ];
102
103 for (lb1, lb2, is) in cases {
104 let lb1 = Labels::new(lb1);
105 let lb2 = Labels::new(lb2);
106 assert_eq!(is, lb1.is_joint(&lb2), "{:?} and {:?}", lb1, lb2)
107 }
108 }
109
110 #[test]
111 fn test_intersect() {
112 let cases = vec![
113 (vec!["foo"], vec!["bar"], vec![]),
114 (vec!["foo"], vec!["foo", "bar"], vec!["foo"]),
115 (vec!["foo"], vec!["foo"], vec!["foo"]),
116 (vec!["foo", "bar"], vec!["bar", "foo"], vec!["foo", "bar"]),
117 ];
118
119 for (lb1, lb2, common) in cases {
120 let lb1 = Labels::new(lb1);
121 let lb2 = Labels::new(lb2);
122 let intersection: HashSet<_> = lb1.intersect(&lb2).labels.into_iter().collect();
123 let expect: HashSet<_> = common.iter().map(|s| s.to_string()).collect();
124 assert_eq!(expect, intersection)
125 }
126 }
127}