use std::num::{Saturating, Wrapping};
use crate::Monoid;
macro_rules! impl_integers {
(@[$($t:ty),*] $Wrapper:ident $impl:tt) => {
$(impl Monoid for $Wrapper<$t> $impl)*
};
($Wrapper:ident $impl:tt) => {
impl_integers!(@[u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize] $Wrapper $impl);
};
}
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct BitAnd<T>(pub T);
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct BitOr<T>(pub T);
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct BitXor<T>(pub T);
impl Monoid for BitAnd<bool> {
#[inline]
fn ident() -> Self {
Self(true)
}
#[inline]
fn combine(self, rhs: Self) -> Self {
Self(self.0 && rhs.0)
}
#[inline]
fn combine_assign(&mut self, rhs: Self) {
self.0 &= rhs.0;
}
#[inline]
fn combine_assign_to(self, rhs: &mut Self) {
rhs.0 &= self.0;
}
fn combine_iter<I: Iterator<Item = Self>>(mut iter: I) -> Self {
Self(iter.all(|x| x.0))
}
}
impl Monoid for BitOr<bool> {
#[inline]
fn ident() -> Self {
Self(false)
}
#[inline]
fn combine(self, rhs: Self) -> Self {
Self(self.0 || rhs.0)
}
#[inline]
fn combine_assign(&mut self, rhs: Self) {
self.0 |= rhs.0;
}
#[inline]
fn combine_assign_to(self, rhs: &mut Self) {
rhs.0 |= self.0;
}
fn combine_iter<I: Iterator<Item = Self>>(mut iter: I) -> Self {
Self(iter.any(|x| x.0))
}
}
impl Monoid for BitXor<bool> {
#[inline]
fn ident() -> Self {
Self(false)
}
#[inline]
fn combine_assign(&mut self, rhs: Self) {
self.0 ^= rhs.0;
}
#[inline]
fn combine_assign_to(self, rhs: &mut Self) {
rhs.0 ^= self.0;
}
#[inline]
fn combine(self, rhs: Self) -> Self {
Self(self.0 != rhs.0)
}
}
impl_integers!(BitAnd {
#[inline]
fn ident() -> Self {
Self(!0)
}
#[inline]
fn combine(self, rhs: Self) -> Self {
Self(self.0 & rhs.0)
}
#[inline]
fn combine_assign(&mut self, rhs: Self) {
self.0 &= rhs.0;
}
#[inline]
fn combine_assign_to(self, rhs: &mut Self) {
rhs.0 &= self.0;
}
});
impl_integers!(BitOr {
#[inline]
fn ident() -> Self {
Self(0)
}
#[inline]
fn combine(self, rhs: Self) -> Self {
Self(self.0 | rhs.0)
}
#[inline]
fn combine_assign(&mut self, rhs: Self) {
self.0 |= rhs.0;
}
#[inline]
fn combine_assign_to(self, rhs: &mut Self) {
rhs.0 |= self.0;
}
});
impl_integers!(BitXor {
#[inline]
fn ident() -> Self {
Self(0)
}
#[inline]
fn combine(self, rhs: Self) -> Self {
Self(self.0 ^ rhs.0)
}
#[inline]
fn combine_assign(&mut self, rhs: Self) {
self.0 ^= rhs.0;
}
#[inline]
fn combine_assign_to(self, rhs: &mut Self) {
rhs.0 ^= self.0;
}
});
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct Add<T>(pub T);
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct Mul<T>(pub T);
type AddWrapping<T> = Add<Wrapping<T>>;
type AddSaturating<T> = Add<Saturating<T>>;
type MulWrapping<T> = Mul<Wrapping<T>>;
type MulSaturating<T> = Mul<Saturating<T>>;
impl_integers!(AddWrapping {
#[inline]
fn ident() -> Self {
Self(Wrapping(0))
}
#[inline]
fn combine(self, rhs: Self) -> Self {
Self(self.0 + rhs.0)
}
#[inline]
fn combine_assign(&mut self, rhs: Self) {
self.0 += rhs.0;
}
#[inline]
fn combine_assign_to(self, rhs: &mut Self) {
rhs.0 += self.0;
}
});
impl_integers!(AddSaturating {
#[inline]
fn ident() -> Self {
Self(Saturating(0))
}
#[inline]
fn combine(self, rhs: Self) -> Self {
Self(self.0 + rhs.0)
}
#[inline]
fn combine_assign(&mut self, rhs: Self) {
self.0 += rhs.0;
}
#[inline]
fn combine_assign_to(self, rhs: &mut Self) {
rhs.0 += self.0;
}
});
impl_integers!(MulWrapping {
#[inline]
fn ident() -> Self {
Self(Wrapping(1))
}
#[inline]
fn combine(self, rhs: Self) -> Self {
Self(self.0 * rhs.0)
}
#[inline]
fn combine_assign(&mut self, rhs: Self) {
self.0 *= rhs.0;
}
#[inline]
fn combine_assign_to(self, rhs: &mut Self) {
rhs.0 *= self.0;
}
});
impl_integers!(MulSaturating {
#[inline]
fn ident() -> Self {
Self(Saturating(1))
}
#[inline]
fn combine(self, rhs: Self) -> Self {
Self(self.0 * rhs.0)
}
#[inline]
fn combine_assign(&mut self, rhs: Self) {
self.0 *= rhs.0;
}
#[inline]
fn combine_assign_to(self, rhs: &mut Self) {
rhs.0 *= self.0;
}
});