glean_core/
common_metric_data.rs1use std::ops::Deref;
6use std::sync::atomic::{AtomicU8, Ordering};
7
8use malloc_size_of_derive::MallocSizeOf;
9
10use crate::error::{Error, ErrorKind};
11use crate::metrics::dual_labeled_counter::validate_dynamic_key_and_or_category;
12use crate::metrics::labeled::validate_dynamic_label;
13use crate::Glean;
14use serde::{Deserialize, Serialize};
15
16#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default, MallocSizeOf)]
20#[repr(i32)] #[serde(rename_all = "lowercase")]
22pub enum Lifetime {
23 #[default]
25 Ping,
26 Application,
28 User,
30}
31
32impl Lifetime {
33 pub fn as_str(self) -> &'static str {
35 match self {
36 Lifetime::Ping => "ping",
37 Lifetime::Application => "app",
38 Lifetime::User => "user",
39 }
40 }
41}
42
43impl TryFrom<i32> for Lifetime {
44 type Error = Error;
45
46 fn try_from(value: i32) -> Result<Lifetime, Self::Error> {
47 match value {
48 0 => Ok(Lifetime::Ping),
49 1 => Ok(Lifetime::Application),
50 2 => Ok(Lifetime::User),
51 e => Err(ErrorKind::Lifetime(e).into()),
52 }
53 }
54}
55
56#[derive(Default, Debug, Clone, Deserialize, Serialize, MallocSizeOf)]
58pub struct CommonMetricData {
59 pub name: String,
61 pub category: String,
63 pub send_in_pings: Vec<String>,
65 pub lifetime: Lifetime,
67 pub disabled: bool,
71 pub dynamic_label: Option<DynamicLabelType>,
78 pub in_session: bool,
85}
86
87#[derive(Debug, Clone, Deserialize, Serialize, MallocSizeOf, uniffi::Enum)]
90pub enum DynamicLabelType {
91 Label(String),
93 KeyOnly(String),
95 CategoryOnly(String),
97 KeyAndCategory(String),
99}
100
101impl Default for DynamicLabelType {
102 fn default() -> Self {
103 Self::Label(String::new())
104 }
105}
106
107impl Deref for DynamicLabelType {
108 type Target = str;
109
110 fn deref(&self) -> &Self::Target {
111 match self {
112 DynamicLabelType::Label(label) => label,
113 DynamicLabelType::KeyOnly(key) => key,
114 DynamicLabelType::CategoryOnly(category) => category,
115 DynamicLabelType::KeyAndCategory(key_and_category) => key_and_category,
116 }
117 }
118}
119
120#[derive(Default, Debug, MallocSizeOf)]
121pub struct CommonMetricDataInternal {
122 pub inner: CommonMetricData,
123 pub disabled: AtomicU8,
124}
125
126impl Clone for CommonMetricDataInternal {
127 fn clone(&self) -> Self {
128 Self {
129 inner: self.inner.clone(),
130 disabled: AtomicU8::new(self.disabled.load(Ordering::Relaxed)),
131 }
132 }
133}
134
135impl From<CommonMetricData> for CommonMetricDataInternal {
136 fn from(input_data: CommonMetricData) -> Self {
137 let disabled = input_data.disabled;
138 Self {
139 inner: input_data,
140 disabled: AtomicU8::new(u8::from(disabled)),
141 }
142 }
143}
144
145impl CommonMetricDataInternal {
146 pub fn new<A: Into<String>, B: Into<String>, C: Into<String>>(
148 category: A,
149 name: B,
150 ping_name: C,
151 ) -> CommonMetricDataInternal {
152 CommonMetricDataInternal {
153 inner: CommonMetricData {
154 name: name.into(),
155 category: category.into(),
156 send_in_pings: vec![ping_name.into()],
157 ..Default::default()
158 },
159 disabled: AtomicU8::new(0),
160 }
161 }
162
163 pub(crate) fn base_identifier(&self) -> String {
168 if self.inner.category.is_empty() {
169 self.inner.name.clone()
170 } else {
171 format!("{}.{}", self.inner.category, self.inner.name)
172 }
173 }
174
175 pub(crate) fn identifier(&self, glean: &Glean) -> String {
180 let base_identifier = self.base_identifier();
181
182 if let Some(label) = &self.inner.dynamic_label {
183 match label {
184 DynamicLabelType::Label(label) => {
185 validate_dynamic_label(glean, self, &base_identifier, label)
186 }
187 _ => validate_dynamic_key_and_or_category(
188 glean,
189 self,
190 &base_identifier,
191 label.clone(),
192 ),
193 }
194 } else {
195 base_identifier
196 }
197 }
198
199 pub fn in_session(&self) -> bool {
205 self.inner.in_session
206 }
207
208 pub fn storage_names(&self) -> &[String] {
210 &self.inner.send_in_pings
211 }
212}