libdd_profiling/internal/
label.rs

1// Copyright 2023-Present Datadog, Inc. https://www.datadoghq.com/
2// SPDX-License-Identifier: Apache-2.0
3
4use super::*;
5use libdd_profiling_protobuf::{prost_impls, Record, StringOffset};
6
7#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
8pub enum LabelValue {
9    Str(StringId),
10    Num { num: i64, num_unit: StringId },
11}
12
13#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
14pub struct Label {
15    key: StringId,
16    value: LabelValue,
17}
18
19impl Label {
20    pub fn has_num_value(&self) -> bool {
21        matches!(self.value, LabelValue::Num { .. })
22    }
23
24    pub fn has_string_value(&self) -> bool {
25        matches!(self.value, LabelValue::Str(_))
26    }
27
28    pub fn get_key(&self) -> StringId {
29        self.key
30    }
31
32    pub fn get_value(&self) -> &LabelValue {
33        &self.value
34    }
35
36    pub fn num(key: StringId, num: i64, num_unit: StringId) -> Self {
37        Self {
38            key,
39            value: LabelValue::Num { num, num_unit },
40        }
41    }
42
43    pub fn str(key: StringId, v: StringId) -> Self {
44        Self {
45            key,
46            value: LabelValue::Str(v),
47        }
48    }
49}
50
51impl From<Label> for prost_impls::Label {
52    fn from(l: Label) -> Self {
53        Self::from(&l)
54    }
55}
56
57impl From<&Label> for prost_impls::Label {
58    fn from(l: &Label) -> prost_impls::Label {
59        let key = l.key.to_raw_id();
60        match l.value {
61            LabelValue::Str(str) => Self {
62                key,
63                str: str.to_raw_id(),
64                num: 0,
65                num_unit: 0,
66            },
67            LabelValue::Num { num, num_unit } => Self {
68                key,
69                str: 0,
70                num,
71                num_unit: num_unit.into_raw_id(),
72            },
73        }
74    }
75}
76
77impl From<Label> for libdd_profiling_protobuf::Label {
78    fn from(label: Label) -> Self {
79        Self::from(&label)
80    }
81}
82
83impl From<&Label> for libdd_profiling_protobuf::Label {
84    fn from(label: &Label) -> Self {
85        let (str, num, num_unit) = match label.value {
86            LabelValue::Str(str) => (str, 0, StringOffset::ZERO),
87            LabelValue::Num { num, num_unit } => (StringOffset::ZERO, num, num_unit),
88        };
89        Self {
90            key: Record::from(label.key),
91            str: Record::from(str),
92            num: Record::from(num),
93            num_unit: Record::from(num_unit),
94        }
95    }
96}
97
98impl Item for Label {
99    type Id = LabelId;
100}
101
102#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
103#[repr(C)]
104pub struct LabelId(u32);
105
106impl Id for LabelId {
107    type RawId = usize;
108
109    fn from_offset(inner: usize) -> Self {
110        #[allow(clippy::expect_used)]
111        let index: u32 = inner.try_into().expect("LabelId to fit into a u32");
112        Self(index)
113    }
114
115    fn to_raw_id(&self) -> Self::RawId {
116        self.0 as Self::RawId
117    }
118}
119impl LabelId {
120    #[inline]
121    pub fn to_offset(&self) -> usize {
122        self.0 as usize
123    }
124}
125
126/// A canonical representation for sets of labels.
127/// You should only use the impl functions to modify this.
128#[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]
129pub struct LabelSet {
130    labels: Box<[LabelId]>,
131}
132
133impl LabelSet {
134    pub fn is_empty(&self) -> bool {
135        self.labels.is_empty()
136    }
137
138    pub fn iter(&self) -> core::slice::Iter<'_, LabelId> {
139        self.labels.iter()
140    }
141
142    pub fn labels(&self) -> &[LabelId] {
143        &self.labels
144    }
145
146    pub fn len(&self) -> usize {
147        self.labels.len()
148    }
149
150    pub fn new(labels: Box<[LabelId]>) -> Self {
151        // Once upon a time label ids were guaranteed to be sorted. However,
152        // this makes testing difficult because the order of input labels and
153        // output labels can make a difference.
154        // Unless there is some reason lost to time, we do not need to sort
155        // these. Save some cycles, and if a given language increases memory,
156        // then it means they aren't adding labels in the same order every
157        // time, and they should examine that--but it shouldn't be a
158        // correctness issue, as far as I know.
159        Self { labels }
160    }
161}
162
163impl Item for LabelSet {
164    type Id = LabelSetId;
165}
166
167#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
168#[repr(C)]
169#[cfg_attr(test, derive(bolero::generator::TypeGenerator))]
170pub struct LabelSetId(u32);
171
172impl Id for LabelSetId {
173    type RawId = usize;
174
175    fn from_offset(inner: usize) -> Self {
176        #[allow(clippy::expect_used)]
177        let index: u32 = inner.try_into().expect("LabelSetId to fit into a u32");
178        Self(index)
179    }
180
181    fn to_raw_id(&self) -> Self::RawId {
182        self.0 as Self::RawId
183    }
184}
185
186impl LabelSetId {
187    #[inline]
188    pub fn to_offset(&self) -> usize {
189        self.0 as usize
190    }
191}
192
193impl From<LabelSetId> for u32 {
194    fn from(value: LabelSetId) -> Self {
195        value.0
196    }
197}