1use serde::{Deserialize, Serialize};
4use std::fmt;
5use time::OffsetDateTime;
6
7#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
12#[cfg_attr(feature = "ts", derive(ts_rs::TS))]
13pub struct MetricKey(String);
14
15impl MetricKey {
16 pub fn new(key: impl Into<String>) -> Self {
17 Self(key.into())
18 }
19
20 pub fn as_str(&self) -> &str {
21 &self.0
22 }
23}
24
25impl fmt::Display for MetricKey {
26 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27 f.write_str(&self.0)
28 }
29}
30
31#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
32#[cfg_attr(feature = "ts", derive(ts_rs::TS))]
33#[serde(rename_all = "snake_case")]
34pub enum Unit {
35 Count,
36 Percent,
37 Bytes,
38 Milliseconds,
39 PerMinute,
40 Custom(String),
42}
43
44#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
45#[cfg_attr(feature = "ts", derive(ts_rs::TS))]
46pub struct Metric {
47 pub key: MetricKey,
48 pub value: f64,
49 pub unit: Unit,
50 #[serde(with = "time::serde::rfc3339")]
51 #[cfg_attr(feature = "ts", ts(type = "string"))]
52 pub at: OffsetDateTime,
53}
54
55impl Metric {
56 pub fn new(key: MetricKey, value: f64, unit: Unit, at: OffsetDateTime) -> Self {
57 Self {
58 key,
59 value,
60 unit,
61 at,
62 }
63 }
64}
65
66#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
68#[cfg_attr(feature = "ts", derive(ts_rs::TS))]
69pub struct Trend {
70 pub current: f64,
71 pub previous: f64,
72}
73
74impl Trend {
75 pub fn new(current: f64, previous: f64) -> Self {
76 Self { current, previous }
77 }
78
79 pub fn change_ratio(&self) -> Option<f64> {
85 if self.previous == 0.0 {
86 None
87 } else {
88 Some((self.current - self.previous) / self.previous)
89 }
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96
97 #[test]
98 fn change_ratio_reports_a_drop() {
99 let trend = Trend::new(60.0, 100.0);
100 assert_eq!(trend.change_ratio(), Some(-0.4));
101 }
102
103 #[test]
104 fn change_ratio_from_zero_is_undefined() {
105 assert_eq!(Trend::new(10.0, 0.0).change_ratio(), None);
106 }
107}