use crate::{Generator, ValueResult};
use core::num::Wrapping;
pub trait Sum<A = Self>: Sized {
fn sum<G>(gen: G) -> Self
where
G: Generator<Output = A>;
}
pub trait Product<A = Self>: Sized {
fn product<G>(gen: G) -> Self
where
G: Generator<Output = A>;
}
macro_rules! integer_sum_product {
(@impls $zero:expr, $one:expr, $($a:ty)*) => ($(
impl Sum for $a {
#[inline]
fn sum<G: Generator<Output=Self>>(mut gen: G) -> Self {
let mut ret = $zero;
gen.run(
|x| {
ret += x;
ValueResult::MoreValues
}
);
ret
}
}
impl<'a> Sum<&'a $a> for $a {
#[inline]
fn sum<G: Generator<Output=&'a Self>>(mut gen: G) -> Self {
let mut ret = $zero;
gen.run(
|x| {
ret += x;
ValueResult::MoreValues
}
);
ret
}
}
impl Product for $a {
#[inline]
fn product<G: Generator<Output=Self>>(mut gen: G) -> Self {
let mut ret = $one;
gen.run(|x| {
ret *= x;
ValueResult::MoreValues
}
);
ret
}
}
impl<'a> Product<&'a $a> for $a {
#[inline]
fn product<G: Generator<Output=&'a Self>>(mut gen: G) -> Self {
let mut ret = $one;
gen.run(|x| {
ret *= x;
ValueResult::MoreValues
}
);
ret
}
}
)*);
($($a:ty)*) => (
integer_sum_product!(@impls 0, 1,
$($a)*);
integer_sum_product!(@impls Wrapping(0), Wrapping(1),
$(Wrapping<$a>)*);
);
}
macro_rules! float_sum_product {
($($a:ty)*) => ($(
impl Sum for $a {
#[inline]
fn sum<G: Generator<Output=Self>>(mut gen: G) -> Self {
let mut ret = 0.0;
gen.run(
|x| {
ret += x;
ValueResult::MoreValues
}
);
ret
}
}
impl<'a> Sum<&'a $a> for $a {
#[inline]
fn sum<G: Generator<Output=&'a Self>>(mut gen: G) -> Self {
let mut ret = 0.0;
gen.run(
|x| {
ret += x;
ValueResult::MoreValues
}
);
ret
}
}
impl Product for $a {
#[inline]
fn product<G: Generator<Output=Self>>(mut gen: G) -> Self {
let mut ret = 1.0;
gen.run(|x| {
ret *= x;
ValueResult::MoreValues
}
);
ret
}
}
impl<'a> Product<&'a $a> for $a {
#[inline]
fn product<G: Generator<Output=&'a Self>>(mut gen: G) -> Self {
let mut ret = 1.0;
gen.run(|x| {
ret *= x;
ValueResult::MoreValues
}
);
ret
}
})*)
}
integer_sum_product! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }
float_sum_product! { f32 f64 }
#[cfg(test)]
mod tests {
use super::*;
use crate::{GeneratorExt, IntoGenerator};
#[test]
fn sum() {
let data = [1, 2, 3, 4];
assert_eq!(i32::sum(data.into_gen().copied()), 10);
assert_eq!(i32::sum(data.into_gen()), 10);
let data = [Wrapping(u32::MAX), Wrapping(1)];
assert_eq!(Wrapping::<u32>::sum(data.into_gen()), Wrapping(0));
}
#[test]
fn product() {
let data = [2, 3, 4];
let expected = 2 * 3 * 4;
assert_eq!(i32::product(data.into_gen().copied()), expected);
assert_eq!(i32::product(data.into_gen()), expected);
}
}