downsample 0.0.4

keep downsampled history of data over long period of time
Documentation
use core::marker::ConstParamTy;

#[derive(PartialEq, Eq, Debug, Clone, ConstParamTy)]
pub enum Algorithm {
    Average,
    Min,
    Max,
}

pub trait Aggregatable<const M: Algorithm> {
    fn aggregate<I: Iterator<Item = Self>>(list: I) -> Self;
}

#[cfg(feature = "derive_aggregatable")]
mod int {
    use super::*;

    macro_rules! impl_by_into {
        ( $t:ty ) => {
            impl Aggregatable<{ Algorithm::Average }> for $t {
                fn aggregate<I: Iterator<Item = Self>>(list: I) -> Self {
                    let mut total = <$t>::default();
                    let mut count = 0;
                    for e in list {
                        total += e;
                        count += 1;
                    }
                    total / count as $t
                }
            }

            impl Aggregatable<{ Algorithm::Min }> for $t {
                fn aggregate<I: Iterator<Item = Self>>(list: I) -> Self {
                    let mut min = None;
                    for e in list {
                        if min.map(|m| e < m).unwrap_or(true) {
                            min = Some(e);
                        }
                    }
                    min.unwrap_or_default()
                }
            }

            impl Aggregatable<{ Algorithm::Max }> for $t {
                fn aggregate<I: Iterator<Item = Self>>(list: I) -> Self {
                    let mut max = None;
                    for e in list {
                        if max.map(|m| e > m).unwrap_or(true) {
                            max = Some(e);
                        }
                    }
                    max.unwrap_or_default()
                }
            }
        };
    }

    impl_by_into!(f32);
    impl_by_into!(f64);
    impl_by_into!(u8);
    impl_by_into!(u16);
    impl_by_into!(u32);
    impl_by_into!(u64);
    impl_by_into!(u128);
    impl_by_into!(i8);
    impl_by_into!(i16);
    impl_by_into!(i32);
    impl_by_into!(i64);
    impl_by_into!(i128);
    impl_by_into!(usize);
    impl_by_into!(isize);
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::Algorithm;

    #[test]
    fn average_f32() {
        assert_eq!(
            Aggregatable::<{ Algorithm::Average }>::aggregate((0..10).map(|x| x as f32)),
            4.5
        )
    }

    #[test]
    fn min_f32() {
        assert_eq!(
            Aggregatable::<{ Algorithm::Min }>::aggregate((-10..10).map(|x| x as f32)),
            -10.0
        )
    }

    #[test]
    fn max_f32() {
        assert_eq!(
            Aggregatable::<{ Algorithm::Max }>::aggregate((-10..10).map(|x| x as f32)),
            9.0
        )
    }
}