dd_sds/observability/
labels.rs1use 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 `{element:?}` contains a single element, two elements (key and value) are required"
71 )));
72 }
73 if element.len() > 2 {
74 return Err(Error::custom(format!(
75 "list `{element:?}` contains more than two elements, only two elements (key and value) are allowed"
76 )));
77 }
78 label_list.push((
79 element.first().unwrap().clone(),
80 element.last().unwrap().clone(),
81 ))
82 }
83
84 Ok(Labels::new(&label_list))
85 }
86 }
87 deserializer.deserialize_seq(LabelsVisitor)
88 }
89}
90
91impl Serialize for Labels {
92 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
93 where
94 S: Serializer,
95 {
96 let mut seq = serializer.serialize_seq(Some(self.0.len()))?;
97 for label in self.clone().into_labels() {
98 seq.serialize_element(&vec![label.key(), label.value()])?;
99 }
100 seq.end()
101 }
102}
103
104#[cfg(test)]
105mod test {
106 use crate::observability::labels::Labels;
107 use metrics::{IntoLabels, Label};
108
109 #[test]
110 fn test_clone_labels() {
111 let labels = Labels::new(&[("key_1", "value_1")]);
112
113 let labels_2 = labels.clone_with_labels(Labels::new(&[("key_2", "value_2")]));
114 let label_list = labels_2.into_labels();
115 assert!(label_list.contains(&Label::new("key_1", "value_1")));
116 assert!(label_list.contains(&Label::new("key_2", "value_2")));
117
118 let labels_3 =
119 labels.clone_with_labels(Labels::new(&[("key_3", "value_3"), ("key_4", "value_4")]));
120 let label_list = labels_3.into_labels();
121 assert!(label_list.contains(&Label::new("key_1", "value_1")));
122 assert!(!label_list.contains(&Label::new("key_2", "value_2")));
123 assert!(label_list.contains(&Label::new("key_3", "value_3")));
124 assert!(label_list.contains(&Label::new("key_4", "value_4")));
125 }
126
127 use serde_test::{assert_de_tokens_error, assert_tokens, Token};
128
129 #[test]
130 fn test_deserialization_empty() {
131 assert_tokens(
132 &Labels::empty(),
133 &[Token::Seq { len: Some(0) }, Token::SeqEnd],
134 );
135 }
136
137 #[test]
138 fn test_ser_de() {
139 let labels = Labels::new(&[("key_1", "value_1"), ("key_2", "value_2")]);
140
141 assert_tokens(
142 &labels,
143 &[
144 Token::Seq { len: Some(2) },
145 Token::Seq { len: Some(2) },
146 Token::String("key_1"),
147 Token::String("value_1"),
148 Token::SeqEnd,
149 Token::Seq { len: Some(2) },
150 Token::String("key_2"),
151 Token::String("value_2"),
152 Token::SeqEnd,
153 Token::SeqEnd,
154 ],
155 );
156 }
157 #[test]
158 fn test_too_many_elements_for_a_label_should_fail_de() {
159 assert_de_tokens_error::<Labels>(
160 &[
161 Token::Seq { len: Some(1) },
162 Token::Seq { len: Some(3) },
163 Token::String("key_1"),
164 Token::String("value_1"),
165 Token::String("value_2"),
166 Token::SeqEnd,
167 Token::SeqEnd,
168 ],
169 "list `[\"key_1\", \"value_1\", \"value_2\"]` contains more than two elements, only two elements (key and value) are allowed",
170 );
171 }
172 #[test]
173 fn test_single_element_for_a_label_should_fail_de() {
174 assert_de_tokens_error::<Labels>(
175 &[
176 Token::Seq { len: Some(1) },
177 Token::Seq { len: Some(1) },
178 Token::String("key_1"),
179 Token::SeqEnd,
180 Token::SeqEnd,
181 ],
182 "list `[\"key_1\"]` contains a single element, two elements (key and value) are required",
183 );
184 }
185 #[test]
186 fn test_non_string_element_for_a_label_should_fail_de() {
187 assert_de_tokens_error::<Labels>(
188 &[
189 Token::Seq { len: Some(1) },
190 Token::Seq { len: Some(2) },
191 Token::String("key_1"),
192 Token::I8(1),
193 ],
197 "invalid type: integer `1`, expected a string",
198 );
199 }
200}