amonoid 0.1.2

A general-purpose monoid library
Documentation
//! Monoids constructed from existing operations.
//!
//! Note that these are not implemented for arbitrary types `T` that implement the respective traits.
//! This has two reasons:
//! 1. We cannot be sure that those impls actually follow the monoid laws.
//! 2. None of the traits actually include the identity element.
//!    For `Add` and `Mul`, there would be `Zero` and `One` in `num_traits`,
//!    but that should remain an optional dependency.

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

/// A monoid from the [`BitAnd`](std::ops::BitAnd) operation.
///
/// For `bool`, this is the same as the `&&` (logical and) operation.
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct BitAnd<T>(pub T);

/// A monoid from the [`BitOr`](std::ops::BitOr) operation.
///
/// For `bool`, this is the same as the `||` (logical or) operation.
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct BitOr<T>(pub T);

/// A monoid from the [`BitXor`](std::ops::BitXor) operation.
///
/// For `bool`, this is the same as the `!=` operation.
#[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;
	}

	// note: Self::combine is commutative
	#[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;
	}

	// note: Self::combine is commutative
	#[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;
	}

	// note: Self::combine is commutative
	#[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;
	}

	// note: Self::combine is commutative
	#[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;
	}

	// note: Self::combine is commutative
	#[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;
	}

	// note: Self::combine is commutative
	#[inline]
	fn combine_assign_to(self, rhs: &mut Self) {
		rhs.0 ^= self.0;
	}
});

/// A monoid from the [`Add`](std::ops::Add) operation.
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct Add<T>(pub T);

/// A monoid from the [`Mul`](std::ops::Mul) operation.
#[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;
	}

	// note: Self::combine is commutative
	#[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;
	}

	// note: Self::combine is commutative
	#[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;
	}

	// note: Self::combine is commutative
	#[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;
	}

	// note: Self::combine is commutative
	#[inline]
	fn combine_assign_to(self, rhs: &mut Self) {
		rhs.0 *= self.0;
	}
});