Skip to main content

simple_sum_average/
lib.rs

1use core::ops::{Add, AddAssign};
2
3#[derive(Debug, Default)]
4pub struct SimpleSumAverage<T: Default, Count: Default = usize> {
5	sum: T,
6	count: Count
7}
8
9impl<T: Add<Output = T> + Default, Count: Add<u8, Output = Count> + Default> Add<T> for SimpleSumAverage<T, Count> {
10	type Output = Self;
11	fn add(self, rhs: T) -> Self {
12		Self {
13			sum: self.sum + rhs,
14			count: self.count + 1
15		}
16	}
17}
18
19impl<T: Add<Output = T> + Default + Copy, Count: Add<Count, Output = Count> + Default + Copy + From<u8>> AddAssign<T> for SimpleSumAverage<T, Count> {
20	fn add_assign(&mut self, rhs: T) {
21		self.sum = self.sum + rhs;
22		self.count = self.count + 1.into();
23	}
24}
25
26impl<T: Add<Output = T> + Default, Count: Add<Output = Count> + Default> Add<Self> for SimpleSumAverage<T, Count> {
27	type Output = Self;
28	fn add(self, rhs: Self) -> Self {
29		Self {
30			sum: self.sum + rhs.sum,
31			count: self.count + rhs.count
32		}
33	}
34}
35
36macro_rules! implement {
37	($t:ty,$count:ty) => {
38		impl SimpleSumAverage<$t, $count> {
39			pub fn take_mean(&mut self) -> $t {
40				let result = match self.count {
41					0 => 0 as $t,
42					count => self.sum / (count as $t)
43				};
44				self.sum = 0 as $t;
45				self.count = 0 as $count;
46				result
47			}
48		}
49	}
50}
51
52implement!(i8, usize);
53implement!(i16, usize);
54implement!(i32, usize);
55implement!(i64, usize);
56implement!(i128, usize);
57implement!(u8, usize);
58implement!(u16, usize);
59implement!(u32, usize);
60implement!(u64, usize);
61implement!(u128, usize);
62
63implement!(i8, u8);
64implement!(i16, u8);
65implement!(i32, u8);
66implement!(i64, u8);
67implement!(i128, u8);
68implement!(u8, u8);
69implement!(u16, u8);
70implement!(u32, u8);
71implement!(u64, u8);
72implement!(u128, u8);
73
74macro_rules! implement_float {
75	($t:ty,$count:ty) => {
76		impl SimpleSumAverage<$t, $count> {
77			pub fn take_mean(&mut self) -> $t {
78				let result = self.sum / (self.count as $t);
79				self.sum = 0 as $t;
80				self.count = 0 as $count;
81				result
82			}
83		}
84	}
85}
86
87implement_float!(f32, usize);
88implement_float!(f64, usize);
89implement_float!(f32, u8);
90implement_float!(f64, u8);
91
92#[cfg(test)]
93mod tests {
94    use super::*;
95
96	#[test]
97	fn test_basic_f32() {
98		let mut accumulator = SimpleSumAverage::<f32>::default();
99		accumulator += 1.0;
100		accumulator += 1.0;
101		accumulator += 1.0;
102		accumulator += 1.0;
103		accumulator += 1.0;
104		assert_eq!(accumulator.sum, 5.0);
105		assert_eq!(accumulator.count, 5);
106		let average = accumulator.take_mean();
107		assert_eq!(average, 1.0);
108		assert_eq!(accumulator.sum, 0.0);
109		assert_eq!(accumulator.count, 0);
110	}
111
112	#[test]
113	fn test_basic_f32_u8() {
114		let mut accumulator = SimpleSumAverage::<f32, u8>::default();
115		accumulator += 1.0;
116		accumulator += 1.0;
117		accumulator += 1.0;
118		accumulator += 1.0;
119		accumulator += 1.0;
120		assert_eq!(accumulator.sum, 5.0);
121		assert_eq!(accumulator.count, 5);
122		let average = accumulator.take_mean();
123		assert_eq!(average, 1.0);
124		assert_eq!(accumulator.sum, 0.0);
125		assert_eq!(accumulator.count, 0);
126	}
127
128	#[test]
129	fn test_realworld_f32_u8() {
130		let mut accumulator = SimpleSumAverage::<f32, u8>::default();
131		accumulator += 82.3;
132		accumulator += 82.1;
133		accumulator += 82.9;
134		accumulator += 81.7;
135		accumulator += 83.1;
136		accumulator += 82.0;
137		accumulator += 81.8;
138		accumulator += 82.1;
139		accumulator += 82.2;
140		accumulator += 82.4;
141		let average = accumulator.take_mean();
142		assert_eq!(average, 82.26);
143	}
144
145	#[test]
146	fn test_f32_zero() {
147		let mut accumulator = SimpleSumAverage::<f32>::default();
148		accumulator += 10.0;
149		accumulator.count = 0;
150		let average = accumulator.take_mean();
151		assert_eq!(average, f32::INFINITY);
152	}
153
154	#[test]
155	fn test_u16_zero() {
156		let mut accumulator = SimpleSumAverage::<u16>::default();
157		let average = accumulator.take_mean();
158		assert_eq!(average, 0);
159	}
160}