use ops::{Op, Additive, Multiplicative};
use structure::MagmaApprox;
use structure::Magma;
pub trait SemigroupApprox<O: Op>
: MagmaApprox<O>
{
fn prop_is_associative_approx(args: (Self, Self, Self)) -> bool {
let (a, b, c) = (|| args.0.clone(), || args.1.clone(), || args.2.clone());
(a().approx(b()).approx(c())).approx_eq(&a().approx(b().approx(c())))
}
}
impl_marker!(SemigroupApprox<Additive>; u8, u16, u32, u64, i8, i16, i32, i64);
impl_marker!(SemigroupApprox<Multiplicative>; u8, u16, u32, u64, i8, i16, i32, i64);
pub trait Semigroup<O: Op>
: SemigroupApprox<O>
+ Magma<O>
{
fn prop_is_associative(args: (Self, Self, Self)) -> bool {
let (a, b, c) = (|| args.0.clone(), || args.1.clone(), || args.2.clone());
a().operate(b()).operate(c()) == a().operate(b().operate(c()))
}
}
impl_marker!(Semigroup<Additive>; u8, u16, u32, u64, i8, i16, i32, i64);
impl_marker!(Semigroup<Multiplicative>; u8, u16, u32, u64, i8, i16, i32, i64);
#[cfg(test)]
mod tests {
macro_rules! check_int {
($($T:ident),* $(,)*) => {
$(mod $T {
use ops::{Additive, Multiplicative};
use structure::SemigroupApprox;
use structure::Semigroup;
#[quickcheck]
fn prop_add_is_associative_approx(args: ($T, $T, $T)) -> bool {
SemigroupApprox::<Additive>::prop_is_associative_approx(args)
}
#[quickcheck]
fn prop_add_is_associative(args: ($T, $T, $T)) -> bool {
Semigroup::<Additive>::prop_is_associative(args)
}
#[quickcheck]
fn prop_mul_is_associative_approx(args: ($T, $T, $T)) -> bool {
SemigroupApprox::<Multiplicative>::prop_is_associative_approx(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);
}