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
)
}
}