1use core::fmt;
2use std::collections::BTreeMap;
3use std::ops::{AddAssign, SubAssign};
4
5use relay_base_schema::metrics::MetricNamespace;
6
7pub fn tags_cost(tags: &BTreeMap<String, String>) -> usize {
12 tags.iter().map(|(k, v)| k.len() + v.len()).sum()
13}
14
15#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
17pub struct ByNamespace<T> {
18 pub sessions: T,
20 pub transactions: T,
22 pub spans: T,
24 pub custom: T,
26 pub unsupported: T,
28}
29
30impl<T> ByNamespace<T> {
31 pub fn get(&self, namespace: MetricNamespace) -> &T {
33 match namespace {
34 MetricNamespace::Sessions => &self.sessions,
35 MetricNamespace::Transactions => &self.transactions,
36 MetricNamespace::Spans => &self.spans,
37 MetricNamespace::Custom => &self.custom,
38 MetricNamespace::Unsupported => &self.unsupported,
39 }
40 }
41
42 pub fn get_mut(&mut self, namespace: MetricNamespace) -> &mut T {
44 match namespace {
45 MetricNamespace::Sessions => &mut self.sessions,
46 MetricNamespace::Transactions => &mut self.transactions,
47 MetricNamespace::Spans => &mut self.spans,
48 MetricNamespace::Custom => &mut self.custom,
49 MetricNamespace::Unsupported => &mut self.unsupported,
50 }
51 }
52}
53
54impl<T> IntoIterator for ByNamespace<T> {
55 type Item = (MetricNamespace, T);
56 type IntoIter = std::array::IntoIter<(MetricNamespace, T), 5>;
57
58 fn into_iter(self) -> Self::IntoIter {
59 let Self {
60 sessions,
61 transactions,
62 spans,
63 custom,
64 unsupported,
65 } = self;
66
67 [
68 (MetricNamespace::Sessions, sessions),
69 (MetricNamespace::Transactions, transactions),
70 (MetricNamespace::Spans, spans),
71 (MetricNamespace::Custom, custom),
72 (MetricNamespace::Unsupported, unsupported),
73 ]
74 .into_iter()
75 }
76}
77
78impl<T: fmt::Debug + Default + PartialEq> fmt::Debug for ByNamespace<T> {
79 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80 write!(f, "(")?;
82
83 let mut values = MetricNamespace::all()
84 .into_iter()
85 .map(|ns| (ns, self.get(ns)))
86 .filter(|(_, v)| v != &&T::default())
87 .enumerate()
88 .peekable();
89
90 match values.peek() {
91 None => write!(f, "{:?}", T::default())?,
92 Some(_) => {
93 for (i, (namespace, value)) in values {
94 if i > 0 {
95 write!(f, ", ")?;
96 }
97 write!(f, "{namespace}:{value:?}")?;
98 }
99 }
100 }
101
102 write!(f, ")")
103 }
104}
105
106macro_rules! impl_op {
107 ($op:tt, $opfn:ident) => {
108 impl<T: $op> $op for ByNamespace<T> {
109 fn $opfn(&mut self, rhs: Self) {
110 let Self {
111 sessions,
112 transactions,
113 spans,
114 custom,
115 unsupported,
116 } = self;
117
118 $op::$opfn(sessions, rhs.sessions);
119 $op::$opfn(transactions, rhs.transactions);
120 $op::$opfn(spans, rhs.spans);
121 $op::$opfn(custom, rhs.custom);
122 $op::$opfn(unsupported, rhs.unsupported);
123 }
124 }
125 };
126}
127
128impl_op!(AddAssign, add_assign);
129impl_op!(SubAssign, sub_assign);
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 #[test]
136 fn test_get() {
137 let mut v = ByNamespace::<usize>::default();
138
139 for (i, namespace) in MetricNamespace::all().into_iter().enumerate() {
140 assert_eq!(*v.get(namespace), 0);
141 assert_eq!(*v.get_mut(namespace), 0);
142 *v.get_mut(namespace) += i;
143 assert_eq!(*v.get(namespace), i);
144 }
145
146 for (i, namespace) in MetricNamespace::all().into_iter().enumerate() {
148 assert_eq!(*v.get(namespace), i);
149 assert_eq!(*v.get_mut(namespace), i);
150 }
151 }
152
153 #[test]
154 fn test_add_sub() {
155 let mut v = ByNamespace::<usize>::default();
156 for (i, namespace) in MetricNamespace::all().into_iter().enumerate() {
157 *v.get_mut(namespace) += i;
158 }
159
160 let mut v2 = v;
161 v2 -= v;
162 assert_eq!(v2, Default::default());
163
164 v2 += v;
165 assert_eq!(v2, v);
166 }
167}