use std::iter::{Product, Sum};
use std::ops::{Add, Mul};
use crate::Monoid;
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct Additive<M>(pub M);
impl<M: Monoid> Add for Additive<M> {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(self.0.combine(rhs.0))
}
}
#[cfg(feature = "num-traits")]
impl<M: Monoid + Eq> num_traits::Zero for Additive<M> {
fn zero() -> Self {
Self(M::ident())
}
fn is_zero(&self) -> bool {
self.0 == M::ident()
}
}
impl<M: Monoid> Sum<M> for Additive<M> {
fn sum<I: Iterator<Item = M>>(iter: I) -> Self {
Self(M::combine_iter(iter))
}
}
impl<M: Monoid> Sum<Self> for Additive<M> {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.map(|a| a.0).sum()
}
}
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct Multiplicative<M>(pub M);
impl<M: Monoid> Mul for Multiplicative<M> {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
Self(self.0.combine(rhs.0))
}
}
#[cfg(feature = "num-traits")]
impl<M: Monoid + Eq> num_traits::One for Multiplicative<M> {
fn one() -> Self {
Self(M::ident())
}
fn is_one(&self) -> bool {
self.0 == M::ident()
}
}
impl<M: Monoid> Product<M> for Multiplicative<M> {
fn product<I: Iterator<Item = M>>(iter: I) -> Self {
Self(M::combine_iter(iter))
}
}
impl<M: Monoid> Product<Self> for Multiplicative<M> {
fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.map(|a| a.0).product()
}
}