use std::marker::PhantomData;
use std::ops::{AddAssign, SubAssign};
use super::{Accumulator, UniCollector};
pub fn sum<A, T, F>(mapper: F) -> SumCollector<A, T, F>
where
A: Send + Sync + 'static,
T: Default + Copy + AddAssign + SubAssign + Send + Sync + 'static,
F: Fn(&A) -> T + Send + Sync + 'static,
{
SumCollector {
mapper,
_phantom: PhantomData,
}
}
pub struct SumCollector<A, T, F> {
mapper: F,
_phantom: PhantomData<fn(&A) -> T>,
}
impl<A, T, F> UniCollector<A> for SumCollector<A, T, F>
where
A: Send + Sync + 'static,
T: Default + Copy + AddAssign + SubAssign + Send + Sync + 'static,
F: Fn(&A) -> T + Send + Sync + 'static,
{
type Value = T;
type Result = T;
type Accumulator = SumAccumulator<T>;
#[inline]
fn extract(&self, entity: &A) -> T {
(self.mapper)(entity)
}
fn create_accumulator(&self) -> Self::Accumulator {
SumAccumulator { sum: T::default() }
}
}
pub struct SumAccumulator<T> {
sum: T,
}
impl<T> Accumulator<T, T> for SumAccumulator<T>
where
T: Default + Copy + AddAssign + SubAssign + Send + Sync,
{
#[inline]
fn accumulate(&mut self, value: &T) {
self.sum += *value;
}
#[inline]
fn retract(&mut self, value: &T) {
self.sum -= *value;
}
#[inline]
fn finish(&self) -> T {
self.sum
}
#[inline]
fn reset(&mut self) {
self.sum = T::default();
}
}