promql_parser/label/
mod.rs1use 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(feature = "ser")]
77impl serde::Serialize for Labels {
78 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
79 where
80 S: serde::Serializer,
81 {
82 use serde::ser::SerializeSeq;
83 let mut seq = serializer.serialize_seq(Some(self.labels.len()))?;
84
85 for l in &self.labels {
86 seq.serialize_element(&l)?;
87 }
88
89 seq.end()
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96
97 #[test]
98 fn test_to_string() {
99 let cases = vec![
100 (vec![], ""),
101 (vec!["foo"], "foo"),
102 (vec!["foo", "bar"], "foo, bar"),
103 (vec!["foo", "foo", "bar"], "foo, foo, bar"),
104 ];
105
106 for (ls, expect) in cases {
107 let lb = Labels::new(ls);
108 assert_eq!(expect, lb.to_string())
109 }
110 }
111
112 #[test]
113 fn test_is_joint() {
114 let cases = vec![
115 (vec!["foo"], vec!["bar"], false),
116 (vec!["foo"], vec!["foo", "bar"], true),
117 (vec!["foo"], vec!["foo"], true),
118 ];
119
120 for (lb1, lb2, is) in cases {
121 let lb1 = Labels::new(lb1);
122 let lb2 = Labels::new(lb2);
123 assert_eq!(is, lb1.is_joint(&lb2), "{lb1:?} and {lb2:?}")
124 }
125 }
126
127 #[test]
128 fn test_intersect() {
129 let cases = vec![
130 (vec!["foo"], vec!["bar"], vec![]),
131 (vec!["foo"], vec!["foo", "bar"], vec!["foo"]),
132 (vec!["foo"], vec!["foo"], vec!["foo"]),
133 (vec!["foo", "bar"], vec!["bar", "foo"], vec!["foo", "bar"]),
134 ];
135
136 for (lb1, lb2, common) in cases {
137 let lb1 = Labels::new(lb1);
138 let lb2 = Labels::new(lb2);
139 let intersection: HashSet<_> = lb1.intersect(&lb2).labels.into_iter().collect();
140 let expect: HashSet<_> = common.iter().map(|s| s.to_string()).collect();
141 assert_eq!(expect, intersection)
142 }
143 }
144}