open_metrics_client/metrics/
gauge.rs1use super::{MetricType, TypedMetric};
6use std::marker::PhantomData;
7use std::sync::atomic::{AtomicU32, AtomicU64, Ordering};
8use std::sync::Arc;
9
10pub struct Gauge<N = u64, A = AtomicU64> {
40 value: Arc<A>,
41 phantom: PhantomData<N>,
42}
43
44impl<N, A> Clone for Gauge<N, A> {
45 fn clone(&self) -> Self {
46 Self {
47 value: self.value.clone(),
48 phantom: PhantomData,
49 }
50 }
51}
52
53impl<N, A: Default> Default for Gauge<N, A> {
54 fn default() -> Self {
55 Self {
56 value: Arc::new(A::default()),
57 phantom: PhantomData,
58 }
59 }
60}
61
62impl<N, A: Atomic<N>> Gauge<N, A> {
63 pub fn inc(&self) -> N {
65 self.value.inc()
66 }
67
68 pub fn inc_by(&self, v: N) -> N {
70 self.value.inc_by(v)
71 }
72
73 pub fn dec(&self) -> N {
75 self.value.dec()
76 }
77
78 pub fn dec_by(&self, v: N) -> N {
80 self.value.dec_by(v)
81 }
82
83 pub fn set(&self, v: N) -> N {
85 self.value.set(v)
86 }
87
88 pub fn get(&self) -> N {
90 self.value.get()
91 }
92
93 pub fn inner(&self) -> &A {
98 &self.value
99 }
100}
101
102pub trait Atomic<N> {
103 fn inc(&self) -> N;
104
105 fn inc_by(&self, v: N) -> N;
106
107 fn dec(&self) -> N;
108
109 fn dec_by(&self, v: N) -> N;
110
111 fn set(&self, v: N) -> N;
112
113 fn get(&self) -> N;
114}
115
116impl Atomic<u64> for AtomicU64 {
117 fn inc(&self) -> u64 {
118 self.inc_by(1)
119 }
120
121 fn inc_by(&self, v: u64) -> u64 {
122 self.fetch_add(v, Ordering::Relaxed)
123 }
124
125 fn dec(&self) -> u64 {
126 self.dec_by(1)
127 }
128
129 fn dec_by(&self, v: u64) -> u64 {
130 self.fetch_sub(v, Ordering::Relaxed)
131 }
132
133 fn set(&self, v: u64) -> u64 {
134 self.swap(v, Ordering::Relaxed)
135 }
136
137 fn get(&self) -> u64 {
138 self.load(Ordering::Relaxed)
139 }
140}
141
142impl Atomic<u32> for AtomicU32 {
143 fn inc(&self) -> u32 {
144 self.inc_by(1)
145 }
146
147 fn inc_by(&self, v: u32) -> u32 {
148 self.fetch_add(v, Ordering::Relaxed)
149 }
150
151 fn dec(&self) -> u32 {
152 self.dec_by(1)
153 }
154
155 fn dec_by(&self, v: u32) -> u32 {
156 self.fetch_sub(v, Ordering::Relaxed)
157 }
158
159 fn set(&self, v: u32) -> u32 {
160 self.swap(v, Ordering::Relaxed)
161 }
162
163 fn get(&self) -> u32 {
164 self.load(Ordering::Relaxed)
165 }
166}
167
168impl Atomic<f64> for AtomicU64 {
169 fn inc(&self) -> f64 {
170 self.inc_by(1.0)
171 }
172
173 fn inc_by(&self, v: f64) -> f64 {
174 let mut old_u64 = self.load(Ordering::Relaxed);
175 let mut old_f64;
176 loop {
177 old_f64 = f64::from_bits(old_u64);
178 let new = f64::to_bits(old_f64 + v);
179 match self.compare_exchange_weak(old_u64, new, Ordering::Relaxed, Ordering::Relaxed) {
180 Ok(_) => break,
181 Err(x) => old_u64 = x,
182 }
183 }
184
185 old_f64
186 }
187
188 fn dec(&self) -> f64 {
189 self.dec_by(1.0)
190 }
191
192 fn dec_by(&self, v: f64) -> f64 {
193 let mut old_u64 = self.load(Ordering::Relaxed);
194 let mut old_f64;
195 loop {
196 old_f64 = f64::from_bits(old_u64);
197 let new = f64::to_bits(old_f64 - v);
198 match self.compare_exchange_weak(old_u64, new, Ordering::Relaxed, Ordering::Relaxed) {
199 Ok(_) => break,
200 Err(x) => old_u64 = x,
201 }
202 }
203
204 old_f64
205 }
206
207 fn set(&self, v: f64) -> f64 {
208 f64::from_bits(self.swap(f64::to_bits(v), Ordering::Relaxed))
209 }
210
211 fn get(&self) -> f64 {
212 f64::from_bits(self.load(Ordering::Relaxed))
213 }
214}
215
216impl<N, A> TypedMetric for Gauge<N, A> {
217 const TYPE: MetricType = MetricType::Gauge;
218}
219
220#[cfg(test)]
221mod tests {
222 use super::*;
223
224 #[test]
225 fn inc_dec_and_get() {
226 let gauge: Gauge = Gauge::default();
227 assert_eq!(0, gauge.inc());
228 assert_eq!(1, gauge.get());
229
230 assert_eq!(1, gauge.dec());
231 assert_eq!(0, gauge.get());
232
233 assert_eq!(0, gauge.set(10));
234 assert_eq!(10, gauge.get());
235 }
236}