simple-sum-average 0.1.0

An O(1) memory complexity temporal average helper
Documentation
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);
	}
}