Skip to main content

torrust_metrics/
gauge.rs

1use derive_more::Display;
2use serde::{Deserialize, Serialize};
3
4use super::prometheus::PrometheusSerializable;
5
6#[derive(Debug, Display, Clone, Default, PartialEq, Serialize, Deserialize)]
7pub struct Gauge(f64);
8
9impl Gauge {
10    #[must_use]
11    pub fn new(value: f64) -> Self {
12        Self(value)
13    }
14
15    #[must_use]
16    pub fn value(&self) -> f64 {
17        self.0
18    }
19
20    #[must_use]
21    pub fn primitive(&self) -> f64 {
22        self.value()
23    }
24
25    pub fn set(&mut self, value: f64) {
26        self.0 = value;
27    }
28
29    pub fn increment(&mut self, value: f64) {
30        self.0 += value;
31    }
32
33    pub fn decrement(&mut self, value: f64) {
34        self.0 -= value;
35    }
36}
37
38impl From<f32> for Gauge {
39    fn from(value: f32) -> Self {
40        Self(f64::from(value))
41    }
42}
43
44impl From<f64> for Gauge {
45    fn from(value: f64) -> Self {
46        Self(value)
47    }
48}
49
50impl From<Gauge> for f64 {
51    fn from(counter: Gauge) -> Self {
52        counter.value()
53    }
54}
55
56impl PrometheusSerializable for Gauge {
57    fn to_prometheus(&self) -> String {
58        format!("{}", self.value())
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use approx::assert_relative_eq;
65
66    use super::*;
67
68    #[test]
69    fn it_should_be_created_from_integer_values() {
70        let gauge = Gauge::new(0.0);
71        assert_relative_eq!(gauge.value(), 0.0);
72    }
73
74    #[test]
75    fn it_could_be_converted_from_u64() {
76        let gauge: Gauge = 42.0.into();
77        assert_relative_eq!(gauge.value(), 42.0);
78    }
79
80    #[test]
81    fn it_could_be_converted_into_i64() {
82        let gauge = Gauge::new(42.0);
83        let value: f64 = gauge.into();
84        assert_relative_eq!(value, 42.0);
85    }
86
87    #[test]
88    fn it_could_be_set() {
89        let mut gauge = Gauge::new(0.0);
90        gauge.set(1.0);
91        assert_relative_eq!(gauge.value(), 1.0);
92    }
93
94    #[test]
95    fn it_could_be_incremented() {
96        let mut gauge = Gauge::new(0.0);
97        gauge.increment(1.0);
98        assert_relative_eq!(gauge.value(), 1.0);
99    }
100
101    #[test]
102    fn it_could_be_decremented() {
103        let mut gauge = Gauge::new(1.0);
104        gauge.decrement(1.0);
105        assert_relative_eq!(gauge.value(), 0.0);
106    }
107
108    #[test]
109    fn it_serializes_to_prometheus() {
110        let counter = Gauge::new(42.0);
111        assert_eq!(counter.to_prometheus(), "42");
112
113        let counter = Gauge::new(42.1);
114        assert_eq!(counter.to_prometheus(), "42.1");
115    }
116
117    #[test]
118    fn it_could_be_converted_from_f32() {
119        let gauge: Gauge = 42.5f32.into();
120        assert_relative_eq!(gauge.value(), 42.5);
121    }
122
123    #[test]
124    fn it_should_return_primitive_value() {
125        let gauge = Gauge::new(123.456);
126        assert_relative_eq!(gauge.primitive(), 123.456);
127    }
128
129    #[test]
130    fn it_should_handle_zero_value() {
131        let gauge = Gauge::new(0.0);
132        assert_relative_eq!(gauge.value(), 0.0);
133        assert_relative_eq!(gauge.primitive(), 0.0);
134    }
135
136    #[test]
137    fn it_should_handle_negative_values() {
138        let gauge = Gauge::new(-42.5);
139        assert_relative_eq!(gauge.value(), -42.5);
140    }
141
142    #[test]
143    fn it_should_handle_large_values() {
144        let gauge = Gauge::new(f64::MAX);
145        assert_relative_eq!(gauge.value(), f64::MAX);
146    }
147
148    #[test]
149    fn it_should_handle_infinity() {
150        let gauge = Gauge::new(f64::INFINITY);
151        assert_relative_eq!(gauge.value(), f64::INFINITY);
152    }
153
154    #[test]
155    fn it_should_handle_nan() {
156        let gauge = Gauge::new(f64::NAN);
157        assert!(gauge.value().is_nan());
158    }
159
160    #[test]
161    fn it_should_be_displayable() {
162        let gauge = Gauge::new(42.5);
163        assert_eq!(gauge.to_string(), "42.5");
164
165        let gauge = Gauge::new(0.0);
166        assert_eq!(gauge.to_string(), "0");
167    }
168
169    #[test]
170    fn it_should_be_debuggable() {
171        let gauge = Gauge::new(42.5);
172        let debug_string = format!("{gauge:?}");
173        assert_eq!(debug_string, "Gauge(42.5)");
174    }
175
176    #[test]
177    fn it_should_be_cloneable() {
178        let gauge = Gauge::new(42.5);
179        let cloned_gauge = gauge.clone();
180        assert_eq!(gauge, cloned_gauge);
181        assert_relative_eq!(gauge.value(), cloned_gauge.value());
182    }
183
184    #[test]
185    fn it_should_support_equality_comparison() {
186        let gauge1 = Gauge::new(42.5);
187        let gauge2 = Gauge::new(42.5);
188        let gauge3 = Gauge::new(43.0);
189
190        assert_eq!(gauge1, gauge2);
191        assert_ne!(gauge1, gauge3);
192    }
193
194    #[test]
195    fn it_should_have_default_value() {
196        let gauge = Gauge::default();
197        assert_relative_eq!(gauge.value(), 0.0);
198    }
199
200    #[test]
201    fn it_should_handle_conversion_roundtrip() {
202        let original_value = 12345.678;
203        let gauge = Gauge::from(original_value);
204        let converted_back: f64 = gauge.into();
205        assert_relative_eq!(original_value, converted_back);
206    }
207
208    #[test]
209    fn it_should_handle_f32_conversion_roundtrip() {
210        let original_value = 12345.5f32;
211        let gauge = Gauge::from(original_value);
212        assert_relative_eq!(gauge.value(), f64::from(original_value));
213    }
214
215    #[test]
216    fn it_should_handle_multiple_operations() {
217        let mut gauge = Gauge::new(100.0);
218
219        gauge.increment(50.0);
220        assert_relative_eq!(gauge.value(), 150.0);
221
222        gauge.decrement(25.0);
223        assert_relative_eq!(gauge.value(), 125.0);
224
225        gauge.set(200.0);
226        assert_relative_eq!(gauge.value(), 200.0);
227    }
228
229    #[test]
230    fn it_should_serialize_special_values_to_prometheus() {
231        let gauge = Gauge::new(f64::INFINITY);
232        assert_eq!(gauge.to_prometheus(), "inf");
233
234        let gauge = Gauge::new(f64::NEG_INFINITY);
235        assert_eq!(gauge.to_prometheus(), "-inf");
236
237        let gauge = Gauge::new(f64::NAN);
238        assert_eq!(gauge.to_prometheus(), "NaN");
239    }
240}