finit 0.4.0

Finit is a library for defining sets of data, and then performing set operations on them. It is designed to be used for permission systems, but can be used for any kind of data that can be represented as a set.
Documentation
use crate::{Set, operations::*};

macro_rules! impl_set_tuple {
    ($($ty:ident),*) => {
        impl<$($ty: Set),*> Set for ($($ty,)*) {
            type Empty = ($($ty::Empty,)*);

            fn is_empty(&self) -> bool {
                #[allow(non_snake_case)]
                let ($($ty,)+) = self;

                $($ty.is_empty())&&*
            }

            fn empty() -> Self::Empty {
                ($($ty::empty(),)*)
            }
        }
    };
}

macro_rules! impl_op_tuple {
    ($op:ident, $func_name:ident, $(($ty:ident, $rest_ty:ident)),*) => {
        impl<$($ty: $op<$rest_ty>, $rest_ty),*> $op<($($rest_ty,)*)> for ($($ty,)*) {
            type Output = ($($ty::Output,)*);

            fn $func_name(self, other: ($($rest_ty,)*)) -> Self::Output {
                #[allow(non_snake_case)]
                let ($($ty,)+) = self;
                #[allow(non_snake_case)]
                let ($($rest_ty,)+) = other;


                ($($ty.$func_name($rest_ty),)*)
            }
        }
    };
}

macro_rules! impl_op_assign_tuple {
    ($op:ident, $func_name:ident, $(($ty:ident, $rest_ty:ident)),+) => {
        impl<$($ty: $op<$rest_ty>, $rest_ty),*> $op<($($rest_ty,)*)> for ($($ty,)*) {
            fn $func_name(&mut self, other: ($($rest_ty,)*)) {
                #[allow(non_snake_case)]
                let ($($ty,)+) = self;
                #[allow(non_snake_case)]
                let ($($rest_ty,)+) = other;

                $($ty.$func_name($rest_ty);)*
            }
        }
    };
}
macro_rules! impl_op_ref_tuple {
    ($op:ident, $func_name:ident, $(($ty:ident, $rest_ty:ident)),*) => {
        impl<'a, $($ty: $op<&'a $rest_ty>, $rest_ty),*> $op<&'a ($($rest_ty,)*)> for ($($ty,)*) {
            type Output = ($(<$ty as $op<&'a $rest_ty>>::Output,)*);

            fn $func_name(self, other: &'a ($($rest_ty,)*)) -> Self::Output {
                #[allow(non_snake_case)]
                let ($($ty,)+) = self;
                #[allow(non_snake_case)]
                let ($($rest_ty,)+) = other;


                ($($ty.$func_name($rest_ty),)*)
            }
        }
    };
}

macro_rules! impl_op_assign_ref_tuple {
    ($op:ident, $func_name:ident, $(($ty:ident, $rest_ty:ident)),+) => {
        impl<'a, $($ty: $op<&'a $rest_ty>, $rest_ty),*> $op<&'a ($($rest_ty,)*)> for ($($ty,)*) {
            fn $func_name(&mut self, other: &'a ($($rest_ty,)*)) {
                #[allow(non_snake_case)]
                let ($($ty,)+) = self;
                #[allow(non_snake_case)]
                let ($($rest_ty,)+) = other;

                $($ty.$func_name($rest_ty);)*
            }
        }
    };
}

macro_rules! impl_comparison_tuple {
    ($op:ident, $func_name:ident, $(($ty:ident, $rest_ty:ident)),+) => {
        impl<$($ty: $crate::comparisons::$op<$rest_ty>, $rest_ty),*> $crate::comparisons::$op<($($rest_ty,)*)> for ($($ty,)*) {
            fn $func_name(&self, other: &($($rest_ty,)*)) -> bool {
                #[allow(non_snake_case)]
                let ($($ty,)+) = self;
                #[allow(non_snake_case)]
                let ($($rest_ty,)+) = other;

                $($ty.$func_name($rest_ty))&&*
            }
        }
    };
}

macro_rules! impl_tuples {
    (($first:ident, $first_rest:ident) $(, ($rest:ident, $rest_rest:ident))*) => {
        impl_set_tuple!($first $(, $rest)*);
        impl_op_tuple!(Union, union, ($first, $first_rest) $(, ($rest, $rest_rest))*);
        impl_op_assign_tuple!(UnionAssign, union_assign, ($first, $first_rest) $(, ($rest, $rest_rest))*);
        impl_op_tuple!(Intersection, intersection, ($first, $first_rest) $(, ($rest, $rest_rest))*);
        impl_op_assign_tuple!(IntersectionAssign, intersection_assign, ($first, $first_rest) $(, ($rest, $rest_rest))*);
        impl_op_tuple!(Difference, difference, ($first, $first_rest) $(, ($rest, $rest_rest))*);
        impl_op_assign_tuple!(DifferenceAssign, difference_assign, ($first, $first_rest) $(, ($rest, $rest_rest))*);
        impl_op_tuple!(DisjunctiveUnion, disjunctive_union, ($first, $first_rest) $(, ($rest, $rest_rest))*);
        impl_op_assign_tuple!(DisjunctiveUnionAssign, disjunctive_union_assign, ($first, $first_rest) $(, ($rest, $rest_rest))*);
        impl_op_ref_tuple!(Union, union, ($first, $first_rest) $(, ($rest, $rest_rest))*);
        impl_op_assign_ref_tuple!(UnionAssign, union_assign, ($first, $first_rest) $(, ($rest, $rest_rest))*);
        impl_op_ref_tuple!(Intersection, intersection, ($first, $first_rest) $(, ($rest, $rest_rest))*);
        impl_op_assign_ref_tuple!(IntersectionAssign, intersection_assign, ($first, $first_rest) $(, ($rest, $rest_rest))*);
        impl_op_ref_tuple!(Difference, difference, ($first, $first_rest) $(, ($rest, $rest_rest))*);
        impl_op_assign_ref_tuple!(DifferenceAssign, difference_assign, ($first, $first_rest) $(, ($rest, $rest_rest))*);
        impl_op_ref_tuple!(DisjunctiveUnion, disjunctive_union, ($first, $first_rest) $(, ($rest, $rest_rest))*);
        impl_op_assign_ref_tuple!(DisjunctiveUnionAssign, disjunctive_union_assign, ($first, $first_rest) $(, ($rest, $rest_rest))*);
        impl_comparison_tuple!(SetEq, set_eq, ($first, $first_rest) $(, ($rest, $rest_rest))*);
        impl_comparison_tuple!(SubsetOf, subset_of, ($first, $first_rest) $(, ($rest, $rest_rest))*);
        impl_tuples!($(($rest, $rest_rest)),*);
    };
    () => {};
}

impl_tuples!(
    (T1, R1),
    (T2, R2),
    (T3, R3),
    (T4, R4),
    (T5, R5),
    (T6, R6),
    (T7, R7),
    (T8, R8),
    (T9, R9),
    (T10, R10),
    (T11, R11),
    (T12, R12),
    (T13, R13),
    (T14, R14),
    (T15, R15),
    (T16, R16)
);

#[cfg(test)]
mod tests {
    use crate::operations::{Difference, Intersection, Union};
    use core::fmt::Debug;
    use rstest::rstest;

    #[rstest]
    #[case((true, false, false, true), (false, true, false, true), (true, true, false, true))]
    fn union_list_tests<T, U, V>(#[case] a: T, #[case] b: U, #[case] c: V)
    where
        T: Union<U, Output = V>,
        V: PartialEq + Debug,
    {
        assert_eq!(a.union(b), c);
    }

    #[rstest]
    #[case((true, false, false, true), (false, true, false, true), (true, false, false, false))]
    fn difference_list_tests<T, U, V>(#[case] a: T, #[case] b: U, #[case] c: V)
    where
        T: Difference<U, Output = V>,
        V: PartialEq + Debug,
    {
        assert_eq!(a.difference(b), c);
    }

    #[rstest]
    #[case((true, false, false, true), (false, true, false, true), (false, false, false, true))]
    fn intersection_list_tests<T, U, V>(#[case] a: T, #[case] b: U, #[case] c: V)
    where
        T: Intersection<U, Output = V>,
        V: PartialEq + Debug,
    {
        assert_eq!(a.intersection(b), c);
    }
}