1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
use self::private::Sealed;

/// An index specified at compile time.
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct Index<const I: usize, const J: usize>;

/// An marker trait indicating a compile-time index is valid for a specific order. This trait is sealed.
pub trait SupportedIndex<const ORDER: usize>: Sealed {}

macro_rules! impl_supported_index {
    ($( $order:expr ),* => ($i:expr, $j:expr)) => {
        impl Sealed for Index<$i, $j> {}
        $(
            impl SupportedIndex<$order> for Index<$i, $j> {}
        )*
    };
    ($( $order:expr ),* => ($i:expr) <-> ($j:expr)) => {
        impl Sealed for Index<$i, $j> {}
        impl Sealed for Index<$j, $i> {}
        $(
            impl SupportedIndex<$order> for Index<$i, $j> {}
            impl SupportedIndex<$order> for Index<$j, $i> {}
        )*
    };
}

impl_supported_index!(0, 1, 2, 3 => (0, 0));
impl_supported_index!(1, 2, 3 => (1) <-> (0));
impl_supported_index!(2, 3 => (1, 1));
impl_supported_index!(2, 3 => (2) <-> (0));
impl_supported_index!(3 => (3) <-> (0));
impl_supported_index!(3 => (2) <-> (1));

mod private {
    pub trait Sealed {}
}