use core::ops::{Add, AddAssign};
#[derive(Debug, Default)]
pub struct SimpleSumAverage<T: Default, Count: Default = usize> {
sum: T,
count: Count
}
impl<T: Add<Output = T> + Default, Count: Add<u8, Output = Count> + Default> Add<T> for SimpleSumAverage<T, Count> {
type Output = Self;
fn add(self, rhs: T) -> Self {
Self {
sum: self.sum + rhs,
count: self.count + 1
}
}
}
impl<T: Add<Output = T> + Default + Copy, Count: Add<Count, Output = Count> + Default + Copy + From<u8>> AddAssign<T> for SimpleSumAverage<T, Count> {
fn add_assign(&mut self, rhs: T) {
self.sum = self.sum + rhs;
self.count = self.count + 1.into();
}
}
impl<T: Add<Output = T> + Default, Count: Add<Output = Count> + Default> Add<Self> for SimpleSumAverage<T, Count> {
type Output = Self;
fn add(self, rhs: Self) -> Self {
Self {
sum: self.sum + rhs.sum,
count: self.count + rhs.count
}
}
}
macro_rules! implement {
($t:ty,$count:ty) => {
impl SimpleSumAverage<$t, $count> {
pub fn take_mean(&mut self) -> $t {
let result = match self.count {
0 => 0 as $t,
count => self.sum / (count as $t)
};
self.sum = 0 as $t;
self.count = 0 as $count;
result
}
}
}
}
implement!(i8, usize);
implement!(i16, usize);
implement!(i32, usize);
implement!(i64, usize);
implement!(i128, usize);
implement!(u8, usize);
implement!(u16, usize);
implement!(u32, usize);
implement!(u64, usize);
implement!(u128, usize);
implement!(i8, u8);
implement!(i16, u8);
implement!(i32, u8);
implement!(i64, u8);
implement!(i128, u8);
implement!(u8, u8);
implement!(u16, u8);
implement!(u32, u8);
implement!(u64, u8);
implement!(u128, u8);
macro_rules! implement_float {
($t:ty,$count:ty) => {
impl SimpleSumAverage<$t, $count> {
pub fn take_mean(&mut self) -> $t {
let result = self.sum / (self.count as $t);
self.sum = 0 as $t;
self.count = 0 as $count;
result
}
}
}
}
implement_float!(f32, usize);
implement_float!(f64, usize);
implement_float!(f32, u8);
implement_float!(f64, u8);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_basic_f32() {
let mut accumulator = SimpleSumAverage::<f32>::default();
accumulator += 1.0;
accumulator += 1.0;
accumulator += 1.0;
accumulator += 1.0;
accumulator += 1.0;
assert_eq!(accumulator.sum, 5.0);
assert_eq!(accumulator.count, 5);
let average = accumulator.take_mean();
assert_eq!(average, 1.0);
assert_eq!(accumulator.sum, 0.0);
assert_eq!(accumulator.count, 0);
}
#[test]
fn test_basic_f32_u8() {
let mut accumulator = SimpleSumAverage::<f32, u8>::default();
accumulator += 1.0;
accumulator += 1.0;
accumulator += 1.0;
accumulator += 1.0;
accumulator += 1.0;
assert_eq!(accumulator.sum, 5.0);
assert_eq!(accumulator.count, 5);
let average = accumulator.take_mean();
assert_eq!(average, 1.0);
assert_eq!(accumulator.sum, 0.0);
assert_eq!(accumulator.count, 0);
}
#[test]
fn test_realworld_f32_u8() {
let mut accumulator = SimpleSumAverage::<f32, u8>::default();
accumulator += 82.3;
accumulator += 82.1;
accumulator += 82.9;
accumulator += 81.7;
accumulator += 83.1;
accumulator += 82.0;
accumulator += 81.8;
accumulator += 82.1;
accumulator += 82.2;
accumulator += 82.4;
let average = accumulator.take_mean();
assert_eq!(average, 82.26);
}
#[test]
fn test_f32_zero() {
let mut accumulator = SimpleSumAverage::<f32>::default();
accumulator += 10.0;
accumulator.count = 0;
let average = accumulator.take_mean();
assert_eq!(average, f32::INFINITY);
}
#[test]
fn test_u16_zero() {
let mut accumulator = SimpleSumAverage::<u16>::default();
let average = accumulator.take_mean();
assert_eq!(average, 0);
}
}