tuple_traits/
cons.rs

1/// A base type that can be implemented by any type, which is used to build operations on top of.
2/// With this format it can be implemented to an infinite length, meaning that any operations built
3/// from it will work for any given length.
4pub trait Cons {
5    /// Left value of the cons, ideally the next value.
6    type Left;
7    /// Right value of the cons, another cons or unit if there are no more values.
8    type Right;
9}
10
11/// Helper macro to implement cons for all tuples of some length.
12///
13/// Tuple of length 0 (unit) must not implement cons, as it has neither a value nor a right side.
14macro_rules! impl_tuples {
15    // Base case, implement for when there is a single generic value.
16    ($T:ident) => {
17        impl<$T> Cons for ($T,) {
18            type Left = $T;
19            type Right = ();
20        }
21    };
22
23    // Recursive case, implement for when the first value is the left side, and recurse with the
24    // right side and rest of the list.
25    ($T:ident, $($Tail:ident),*) => {
26        impl<$T, $($Tail),*> Cons for ($T, $($Tail),*) {
27            type Left = $T;
28            type Right = ($($Tail),*,);
29        }
30
31        impl_tuples!($($Tail),*);
32    };
33}
34
35crate::tuple_list!(impl_tuples);
36
37#[cfg(test)]
38mod test {
39    use static_assertions::{assert_impl_all, assert_not_impl_all};
40
41    use super::*;
42
43    assert_impl_all!((usize,): Cons<Left = usize, Right = ()>);
44    assert_impl_all!((usize, usize): Cons<Left = usize, Right = (usize,)>);
45    assert_impl_all!((usize, usize, usize): Cons<Left = usize, Right = (usize, usize)>);
46
47    assert_not_impl_all!((): Cons);
48}