1use std::hash::{Hash, Hasher};
4use std::sync::Arc;
5
6mod instruments;
7mod meter;
8pub(crate) mod noop;
9
10use crate::{Array, KeyValue, Value};
11pub use instruments::{
12 counter::{Counter, ObservableCounter},
13 gauge::{Gauge, ObservableGauge},
14 histogram::Histogram,
15 up_down_counter::{ObservableUpDownCounter, UpDownCounter},
16 AsyncInstrument, AsyncInstrumentBuilder, Callback, HistogramBuilder, InstrumentBuilder,
17 SyncInstrument,
18};
19pub use meter::{Meter, MeterProvider};
20
21struct F64Hashable(f64);
22
23impl PartialEq for F64Hashable {
24 fn eq(&self, other: &Self) -> bool {
25 self.0.to_bits() == other.0.to_bits()
26 }
27}
28
29impl Eq for F64Hashable {}
30
31impl Hash for F64Hashable {
32 fn hash<H: Hasher>(&self, state: &mut H) {
33 self.0.to_bits().hash(state);
34 }
35}
36
37impl Hash for KeyValue {
38 fn hash<H: Hasher>(&self, state: &mut H) {
39 self.key.hash(state);
40 match &self.value {
41 Value::F64(f) => F64Hashable(*f).hash(state),
42 Value::Array(a) => match a {
43 Array::Bool(b) => b.hash(state),
44 Array::I64(i) => i.hash(state),
45 Array::F64(f) => f.iter().for_each(|f| F64Hashable(*f).hash(state)),
46 Array::String(s) => s.hash(state),
47 },
48 Value::Bool(b) => b.hash(state),
49 Value::I64(i) => i.hash(state),
50 Value::String(s) => s.hash(state),
51 };
52 }
53}
54
55impl Eq for KeyValue {}
56
57pub trait InstrumentProvider {
59 fn u64_counter(&self, _builder: InstrumentBuilder<'_, Counter<u64>>) -> Counter<u64> {
61 Counter::new(Arc::new(noop::NoopSyncInstrument::new()))
62 }
63
64 fn f64_counter(&self, _builder: InstrumentBuilder<'_, Counter<f64>>) -> Counter<f64> {
66 Counter::new(Arc::new(noop::NoopSyncInstrument::new()))
67 }
68
69 fn u64_observable_counter(
71 &self,
72 _builder: AsyncInstrumentBuilder<'_, ObservableCounter<u64>, u64>,
73 ) -> ObservableCounter<u64> {
74 ObservableCounter::new()
75 }
76
77 fn f64_observable_counter(
79 &self,
80 _builder: AsyncInstrumentBuilder<'_, ObservableCounter<f64>, f64>,
81 ) -> ObservableCounter<f64> {
82 ObservableCounter::new()
83 }
84
85 fn i64_up_down_counter(
87 &self,
88 _builder: InstrumentBuilder<'_, UpDownCounter<i64>>,
89 ) -> UpDownCounter<i64> {
90 UpDownCounter::new(Arc::new(noop::NoopSyncInstrument::new()))
91 }
92
93 fn f64_up_down_counter(
95 &self,
96 _builder: InstrumentBuilder<'_, UpDownCounter<f64>>,
97 ) -> UpDownCounter<f64> {
98 UpDownCounter::new(Arc::new(noop::NoopSyncInstrument::new()))
99 }
100
101 fn i64_observable_up_down_counter(
103 &self,
104 _builder: AsyncInstrumentBuilder<'_, ObservableUpDownCounter<i64>, i64>,
105 ) -> ObservableUpDownCounter<i64> {
106 ObservableUpDownCounter::new()
107 }
108
109 fn f64_observable_up_down_counter(
111 &self,
112 _builder: AsyncInstrumentBuilder<'_, ObservableUpDownCounter<f64>, f64>,
113 ) -> ObservableUpDownCounter<f64> {
114 ObservableUpDownCounter::new()
115 }
116
117 fn u64_gauge(&self, _builder: InstrumentBuilder<'_, Gauge<u64>>) -> Gauge<u64> {
119 Gauge::new(Arc::new(noop::NoopSyncInstrument::new()))
120 }
121
122 fn f64_gauge(&self, _builder: InstrumentBuilder<'_, Gauge<f64>>) -> Gauge<f64> {
124 Gauge::new(Arc::new(noop::NoopSyncInstrument::new()))
125 }
126
127 fn i64_gauge(&self, _builder: InstrumentBuilder<'_, Gauge<i64>>) -> Gauge<i64> {
129 Gauge::new(Arc::new(noop::NoopSyncInstrument::new()))
130 }
131
132 fn u64_observable_gauge(
134 &self,
135 _builder: AsyncInstrumentBuilder<'_, ObservableGauge<u64>, u64>,
136 ) -> ObservableGauge<u64> {
137 ObservableGauge::new()
138 }
139
140 fn i64_observable_gauge(
142 &self,
143 _builder: AsyncInstrumentBuilder<'_, ObservableGauge<i64>, i64>,
144 ) -> ObservableGauge<i64> {
145 ObservableGauge::new()
146 }
147
148 fn f64_observable_gauge(
150 &self,
151 _builder: AsyncInstrumentBuilder<'_, ObservableGauge<f64>, f64>,
152 ) -> ObservableGauge<f64> {
153 ObservableGauge::new()
154 }
155
156 fn f64_histogram(&self, _builder: HistogramBuilder<'_, Histogram<f64>>) -> Histogram<f64> {
158 Histogram::new(Arc::new(noop::NoopSyncInstrument::new()))
159 }
160
161 fn u64_histogram(&self, _builder: HistogramBuilder<'_, Histogram<u64>>) -> Histogram<u64> {
163 Histogram::new(Arc::new(noop::NoopSyncInstrument::new()))
164 }
165}
166
167#[cfg(test)]
168mod tests {
169 use rand::Rng;
170
171 use crate::KeyValue;
172 use std::collections::hash_map::DefaultHasher;
173 use std::f64;
174 use std::hash::{Hash, Hasher};
175
176 #[test]
177 fn kv_float_equality() {
178 let kv1 = KeyValue::new("key", 1.0);
179 let kv2 = KeyValue::new("key", 1.0);
180 assert_eq!(kv1, kv2);
181
182 let kv1 = KeyValue::new("key", 1.0);
183 let kv2 = KeyValue::new("key", 1.01);
184 assert_ne!(kv1, kv2);
185
186 let kv1 = KeyValue::new("key", f64::NAN);
187 let kv2 = KeyValue::new("key", f64::NAN);
188 assert_ne!(kv1, kv2, "NAN is not equal to itself");
189
190 for float_val in [
191 f64::INFINITY,
192 f64::NEG_INFINITY,
193 f64::MAX,
194 f64::MIN,
195 f64::MIN_POSITIVE,
196 ]
197 .iter()
198 {
199 let kv1 = KeyValue::new("key", *float_val);
200 let kv2 = KeyValue::new("key", *float_val);
201 assert_eq!(kv1, kv2);
202 }
203
204 let mut rng = rand::thread_rng();
205
206 for _ in 0..100 {
207 let random_value = rng.gen::<f64>();
208 let kv1 = KeyValue::new("key", random_value);
209 let kv2 = KeyValue::new("key", random_value);
210 assert_eq!(kv1, kv2);
211 }
212 }
213
214 #[test]
215 fn kv_float_hash() {
216 for float_val in [
217 f64::NAN,
218 f64::INFINITY,
219 f64::NEG_INFINITY,
220 f64::MAX,
221 f64::MIN,
222 f64::MIN_POSITIVE,
223 ]
224 .iter()
225 {
226 let kv1 = KeyValue::new("key", *float_val);
227 let kv2 = KeyValue::new("key", *float_val);
228 assert_eq!(hash_helper(&kv1), hash_helper(&kv2));
229 }
230
231 let mut rng = rand::thread_rng();
232
233 for _ in 0..100 {
234 let random_value = rng.gen::<f64>();
235 let kv1 = KeyValue::new("key", random_value);
236 let kv2 = KeyValue::new("key", random_value);
237 assert_eq!(hash_helper(&kv1), hash_helper(&kv2));
238 }
239 }
240
241 fn hash_helper<T: Hash>(item: &T) -> u64 {
242 let mut hasher = DefaultHasher::new();
243 item.hash(&mut hasher);
244 hasher.finish()
245 }
246}