1use metrics::{IntoLabels, Label};
2use std::fmt;
3
4use serde::de::{Deserializer, Error, SeqAccess, Visitor};
5use serde::ser::SerializeSeq;
6use serde::{Deserialize, Serialize, Serializer};
7
8#[derive(Clone, Debug, PartialEq)]
10pub struct Labels(Vec<Label>);
11
12impl Labels {
13 pub fn clone_with_labels(&self, additional_labels: Labels) -> Labels {
15 let mut tags = self.0.clone();
16 tags.extend(additional_labels.into_labels());
17 Labels(tags)
18 }
19
20 pub fn new<'a, T: 'a>(labels: impl IntoIterator<Item = &'a T>) -> Self
21 where
22 Label: From<&'a T>,
23 {
24 Labels(labels.into_iter().map(Label::from).collect())
25 }
26
27 pub const fn empty() -> Self {
28 Labels(vec![])
29 }
30}
31
32impl Default for Labels {
33 fn default() -> Self {
34 Self::empty()
35 }
36}
37
38impl IntoLabels for Labels {
39 fn into_labels(self) -> Vec<Label> {
40 self.0
41 }
42}
43
44impl<'de> Deserialize<'de> for Labels {
45 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
46 where
47 D: Deserializer<'de>,
48 {
49 struct LabelsVisitor;
50
51 impl<'de> Visitor<'de> for LabelsVisitor {
52 type Value = Labels;
53
54 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
55 formatter.write_str("List of pairs of strings")
56 }
57
58 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
59 where
60 A: SeqAccess<'de>,
61 {
62 let mut label_list: Vec<(String, String)> =
63 Vec::with_capacity(seq.size_hint().unwrap_or(0));
64
65 while let Some(element) = seq.next_element::<Vec<String>>()? {
68 if element.len() < 2 {
69 return Err(Error::custom(format!(
70 "list `{:?}` contains a single element, two elements (key and value) are required",
71 element
72 )));
73 }
74 if element.len() > 2 {
75 return Err(Error::custom(format!(
76 "list `{:?}` contains more than two elements, only two elements (key and value) are allowed",
77 element
78 )));
79 }
80 label_list.push((
81 element.first().unwrap().clone(),
82 element.last().unwrap().clone(),
83 ))
84 }
85
86 Ok(Labels::new(&label_list))
87 }
88 }
89 deserializer.deserialize_seq(LabelsVisitor)
90 }
91}
92
93impl Serialize for Labels {
94 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
95 where
96 S: Serializer,
97 {
98 let mut seq = serializer.serialize_seq(Some(self.0.len()))?;
99 for label in self.clone().into_labels() {
100 seq.serialize_element(&vec![label.key(), label.value()])?;
101 }
102 seq.end()
103 }
104}
105
106#[cfg(test)]
107mod test {
108 use crate::observability::labels::Labels;
109 use metrics::{IntoLabels, Label};
110
111 #[test]
112 fn test_clone_labels() {
113 let labels = Labels::new(&[("key_1", "value_1")]);
114
115 let labels_2 = labels.clone_with_labels(Labels::new(&[("key_2", "value_2")]));
116 let label_list = labels_2.into_labels();
117 assert!(label_list.contains(&Label::new("key_1", "value_1")));
118 assert!(label_list.contains(&Label::new("key_2", "value_2")));
119
120 let labels_3 =
121 labels.clone_with_labels(Labels::new(&[("key_3", "value_3"), ("key_4", "value_4")]));
122 let label_list = labels_3.into_labels();
123 assert!(label_list.contains(&Label::new("key_1", "value_1")));
124 assert!(!label_list.contains(&Label::new("key_2", "value_2")));
125 assert!(label_list.contains(&Label::new("key_3", "value_3")));
126 assert!(label_list.contains(&Label::new("key_4", "value_4")));
127 }
128
129 use serde_test::{assert_de_tokens_error, assert_tokens, Token};
130
131 #[test]
132 fn test_deserialization_empty() {
133 assert_tokens(
134 &Labels::empty(),
135 &[Token::Seq { len: Some(0) }, Token::SeqEnd],
136 );
137 }
138
139 #[test]
140 fn test_ser_de() {
141 let labels = Labels::new(&[("key_1", "value_1"), ("key_2", "value_2")]);
142
143 assert_tokens(
144 &labels,
145 &[
146 Token::Seq { len: Some(2) },
147 Token::Seq { len: Some(2) },
148 Token::String("key_1"),
149 Token::String("value_1"),
150 Token::SeqEnd,
151 Token::Seq { len: Some(2) },
152 Token::String("key_2"),
153 Token::String("value_2"),
154 Token::SeqEnd,
155 Token::SeqEnd,
156 ],
157 );
158 }
159 #[test]
160 fn test_too_many_elements_for_a_label_should_fail_de() {
161 assert_de_tokens_error::<Labels>(
162 &[
163 Token::Seq { len: Some(1) },
164 Token::Seq { len: Some(3) },
165 Token::String("key_1"),
166 Token::String("value_1"),
167 Token::String("value_2"),
168 Token::SeqEnd,
169 Token::SeqEnd,
170 ],
171 "list `[\"key_1\", \"value_1\", \"value_2\"]` contains more than two elements, only two elements (key and value) are allowed",
172 );
173 }
174 #[test]
175 fn test_single_element_for_a_label_should_fail_de() {
176 assert_de_tokens_error::<Labels>(
177 &[
178 Token::Seq { len: Some(1) },
179 Token::Seq { len: Some(1) },
180 Token::String("key_1"),
181 Token::SeqEnd,
182 Token::SeqEnd,
183 ],
184 "list `[\"key_1\"]` contains a single element, two elements (key and value) are required",
185 );
186 }
187 #[test]
188 fn test_non_string_element_for_a_label_should_fail_de() {
189 assert_de_tokens_error::<Labels>(
190 &[
191 Token::Seq { len: Some(1) },
192 Token::Seq { len: Some(2) },
193 Token::String("key_1"),
194 Token::I8(1),
195 ],
199 "invalid type: integer `1`, expected a string",
200 );
201 }
202}