harmos_storage/signal/
aggregates.rs1use super::{Series, Summary};
22use crate::{Aggregate, aggregate};
23
24pub trait Aggregates {
40 fn aggregate(&self, kind: Aggregate) -> Option<f64>;
41}
42
43impl Aggregates for Series<'_> {
46 fn aggregate(&self, kind: Aggregate) -> Option<f64> {
47 aggregate::of_series(self, kind)
48 }
49}
50
51impl Aggregates for Summary {
52 fn aggregate(&self, kind: Aggregate) -> Option<f64> {
53 aggregate::of_summary(self, kind)
54 }
55}
56
57#[cfg(test)]
64mod tests {
65 use super::{Aggregate, Aggregates, Series, Summary};
66
67 const EVERY: [Aggregate; 11] = [
68 Aggregate::Count,
69 Aggregate::Sum,
70 Aggregate::Mean,
71 Aggregate::Median,
72 Aggregate::Min,
73 Aggregate::Max,
74 Aggregate::Rms,
75 Aggregate::Std,
76 Aggregate::Percentile(0),
77 Aggregate::Percentile(25),
78 Aggregate::Percentile(100),
79 ];
80
81 #[test]
82 fn series_answers_all() {
83 let series = Series::new(&[4.0, f64::NAN, 1.0, 3.0, 2.0]);
84 let mut answers = Vec::new();
85 for kind in EVERY {
86 answers.push(series.aggregate(kind));
87 }
88
89 assert_eq!(
90 answers,
91 vec![
92 Some(4.0),
93 Some(10.0),
94 Some(2.5),
95 Some(2.5),
96 Some(1.0),
97 Some(4.0),
98 series.rms(),
99 series.std(),
100 Some(1.0),
101 Some(1.75),
102 Some(4.0),
103 ]
104 );
105 assert!((series.std().unwrap() - 1.25_f64.sqrt()).abs() < 1e-12);
106 assert!((series.rms().unwrap() - 7.5_f64.sqrt()).abs() < 1e-12);
107 }
108
109 #[test]
110 fn empty_input() {
111 let series = Series::new(&[]);
112 let summary = Summary::new();
113
114 for kind in EVERY {
115 let expected = matches!(kind, Aggregate::Count | Aggregate::Sum).then_some(0.0);
116 assert_eq!(series.aggregate(kind), expected, "{kind:?} of a series");
117 assert_eq!(summary.aggregate(kind), expected, "{kind:?} of a summary");
118 }
119 }
120
121 #[test]
122 fn summary_refuses_order() {
123 let values = [7.5, -2.0, 3.25, 0.0, 11.0, -6.5];
124 let series = Series::new(&values);
125 let summary = Summary::of(&values[..2]).merge(&Summary::of(&values[2..]));
126
127 for kind in EVERY {
128 if !kind.mergeable() {
129 assert_eq!(summary.aggregate(kind), None, "{kind:?} needs the values");
130 assert!(series.aggregate(kind).is_some());
131 continue;
132 }
133 let (exact, merged) = (series.aggregate(kind).unwrap(), summary.aggregate(kind).unwrap());
134 assert!((exact - merged).abs() < 1e-12, "{kind:?}: {exact} and {merged}");
135 }
136 }
137}