use general::{Magma, Op, Additive, Multiplicative};
use cmp::ApproxEq;
pub trait Semigroup<O: Op>
: Magma<O>
{
fn prop_is_associative(args: (Self, Self, Self)) -> bool
where Self: ApproxEq {
let (a, b, c) = (|| args.0.clone(), || args.1.clone(), || args.2.clone());
(a().operate(b()).operate(c())).approx_eq(&a().operate(b().operate(c())))
}
}
impl_marker!(Semigroup<Additive>; u8, u16, u32, u64, i8, i16, i32, i64, f32, f64);
impl_marker!(Semigroup<Multiplicative>; u8, u16, u32, u64, i8, i16, i32, i64, f32, f64);
#[cfg(test)]
mod tests {
macro_rules! check_int {
($($T:ident),* $(,)*) => {
$(mod $T {
use ops::{Additive, Multiplicative};
use general::Semigroup;
#[quickcheck]
fn prop_add_is_associative(args: ($T, $T, $T)) -> bool {
Semigroup::<Additive>::prop_is_associative(args)
}
#[quickcheck]
fn prop_mul_is_associative(args: ($T, $T, $T)) -> bool {
Semigroup::<Multiplicative>::prop_is_associative(args)
}
})+
}
}
check_int!(u8, u16, u32, u64, i8, i16, i32, i64);
}