composable_indexes/aggregation/
mean.rs1use num_traits::ToPrimitive;
2
3use crate::{
4 Index, ShallowClone,
5 core::{Insert, Remove, Seal, Update},
6};
7
8#[derive(Clone)]
10pub struct Mean<T> {
11 sum: f64,
12 count: usize,
13 _phantom: core::marker::PhantomData<T>,
14}
15
16impl<T> Default for Mean<T> {
17 fn default() -> Self {
18 Self::new()
19 }
20}
21
22impl<T> Mean<T> {
23 pub fn new() -> Self {
24 Mean {
25 sum: 0.0,
26 count: 0,
27 _phantom: core::marker::PhantomData,
28 }
29 }
30}
31
32impl<T> Index<T> for Mean<T>
33where
34 T: ToPrimitive + Copy + 'static,
35{
36 #[inline]
37 fn insert(&mut self, _seal: Seal, op: &Insert<T>) {
38 if let Some(val) = op.new.to_f64() {
39 self.sum += val;
40 self.count += 1;
41 }
42 }
43
44 #[inline]
45 fn remove(&mut self, _seal: Seal, op: &Remove<T>) {
46 if let Some(val) = op.existing.to_f64() {
47 self.sum -= val;
48 self.count -= 1;
49 }
50 }
51
52 #[inline]
53 fn update(&mut self, _seal: Seal, op: &Update<T>) {
54 if let (Some(old_val), Some(new_val)) = (op.existing.to_f64(), op.new.to_f64()) {
55 self.sum = self.sum - old_val + new_val;
56 }
57 }
58}
59
60impl<T> Mean<T> {
61 #[inline]
62 pub fn mean(&self) -> Option<f64> {
63 if self.count > 0 {
64 Some(self.sum / self.count as f64)
65 } else {
66 None
67 }
68 }
69
70 #[inline]
71 pub fn count(&self) -> usize {
72 self.count
73 }
74
75 #[inline]
76 pub fn sum(&self) -> f64 {
77 self.sum
78 }
79}
80
81impl<T> ShallowClone for Mean<T> where T: Clone {}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86 use crate::testutils::prop_assert_reference;
87
88 #[test]
89 fn test_mean() {
90 prop_assert_reference(
91 Mean::<u32>::new,
92 |db| db.query(|ix| ix.mean()),
93 |xs| {
94 if !xs.is_empty() {
95 let sum: f64 = xs.iter().map(|x| *x as f64).sum();
96 let count = xs.len() as f64;
97 Some(sum / count)
98 } else {
99 None
100 }
101 },
102 None,
103 );
104 }
105}