1use crate::error::{RillError, checked_increment, ensure_finite};
6use crate::traits::OnlineStatistic;
7
8#[derive(Debug, Clone, Default)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11pub struct Min {
12 current: Option<f64>,
13 count: u64,
14}
15
16impl Min {
17 pub const fn new() -> Self {
19 Self {
20 current: None,
21 count: 0,
22 }
23 }
24
25 pub const fn value(&self) -> Option<f64> {
27 self.current
28 }
29}
30
31impl OnlineStatistic for Min {
32 fn update(&mut self, value: f64) -> Result<(), RillError> {
33 ensure_finite("value", value)?;
34 let next_count = checked_increment(self.count, "minimum sample")?;
35 self.current = Some(match self.current {
36 None => value,
37 Some(c) => c.min(value),
38 });
39 self.count = next_count;
40 Ok(())
41 }
42
43 fn samples_seen(&self) -> u64 {
44 self.count
45 }
46
47 fn reset(&mut self) {
48 self.current = None;
49 self.count = 0;
50 }
51}
52
53#[derive(Debug, Clone, Default)]
55#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
56pub struct Max {
57 current: Option<f64>,
58 count: u64,
59}
60
61impl Max {
62 pub const fn new() -> Self {
64 Self {
65 current: None,
66 count: 0,
67 }
68 }
69
70 pub const fn value(&self) -> Option<f64> {
72 self.current
73 }
74}
75
76impl OnlineStatistic for Max {
77 fn update(&mut self, value: f64) -> Result<(), RillError> {
78 ensure_finite("value", value)?;
79 let next_count = checked_increment(self.count, "maximum sample")?;
80 self.current = Some(match self.current {
81 None => value,
82 Some(c) => c.max(value),
83 });
84 self.count = next_count;
85 Ok(())
86 }
87
88 fn samples_seen(&self) -> u64 {
89 self.count
90 }
91
92 fn reset(&mut self) {
93 self.current = None;
94 self.count = 0;
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101
102 #[test]
103 fn min_tracks_minimum() {
104 let mut m = Min::new();
105 assert!(m.value().is_none());
106 for x in [3.0, 1.0, 4.0, 1.0, 5.0, -2.0] {
107 m.update(x).unwrap();
108 }
109 assert_eq!(m.value(), Some(-2.0));
110 }
111
112 #[test]
113 fn max_tracks_maximum() {
114 let mut m = Max::new();
115 for x in [3.0, 1.0, 4.0, 1.0, 5.0, -2.0] {
116 m.update(x).unwrap();
117 }
118 assert_eq!(m.value(), Some(5.0));
119 }
120}