array_trait/
array_nd.rs

1use super::*;
2
3/// A trait for N-dimensional arrays with depth up to 64.
4/// 
5/// The associated constants [DIMENSIONS](ArrayNd::DIMENSIONS) and [FLAT_LENGTH](ArrayNd::FLAT_LENGTH) vary depending on the chosen depth.
6/// 
7/// The assiciated type [ItemNd](ArrayNd::ItemNd) represents the innermost type given a chosen depth.
8/// 
9/// # Examples
10/// 
11/// ```rust
12/// #![feature(generic_const_exprs)]
13/// 
14/// use array_trait::*;
15/// 
16/// type Mat2x3 = [[i8; 3]; 2];
17/// 
18/// /// The number of dimensions
19/// const DEPTH: usize = 2;
20/// 
21/// // `FLAT_LENGTH` is the combined length if the N-dimensional array was flattened,
22/// // i.e. the product of the lengths of each dimension.
23/// assert_eq!(<Mat2x3 as ArrayNd<DEPTH>>::FLAT_LENGTH, 6);
24/// 
25/// // `DIMENSIONS` contains the lengths of each dimension ordered outermost to innermost.
26/// assert_eq!(<Mat2x3 as ArrayNd<DEPTH>>::DIMENSIONS, [2, 3]);
27/// ```
28pub trait ArrayNd<const DEPTH: usize>: Array
29{
30    /// The dimensions of the n-dimensional containing the lengths of each level of array from outermost to innermost
31    const DIMENSIONS: [usize; DEPTH];
32    /// The product of the lengths of each dimension.
33    const FLAT_LENGTH: usize;
34    type ElemNd;
35}
36
37macro_rules! count {
38    () => {0};
39    ($a:ident) => {1};
40    ($a:ident $($b:ident)+) => {1 $(+ count!($b))+};
41}
42macro_rules! flat_len {
43    () => {0};
44    ($a:ident $($b:ident)*) => {$a $(* $b)*}
45}
46
47macro_rules! nd {
48    ($t:ty;) => {
49        $t
50    };
51    ($t:ty; $a:ident) => {
52        [$t; $a]
53    };
54    ($t:ty; $a:ident $($b:ident)+) => {
55        [nd!{$t; $($b)+}; $a]
56    };
57}
58
59macro_rules! impl_nd_array {
60    ($a:ident $($($b:ident)+)?) => {
61        impl<T, const $a: usize $($(, const $b: usize)+)?> /*const*/ ArrayNd<{count!{$a $($($b)+)?}}> for nd!{T; $a $($($b)+)?}
62        {
63            const DIMENSIONS: [usize; count!{$a $($($b)+)?}] = [$a $($(, $b)+)?];
64            const FLAT_LENGTH: usize = flat_len!{$a $($($b)+)?};
65            type ElemNd = T;
66        }
67        $(impl_nd_array!($($b)+);)?
68    };
69}
70
71mod r#impl
72{
73    use super::*;
74
75    impl_nd_array!(
76        _0 _1 _2 _3 _4 _5 _6 _7 _8 _9 _10 _11 _12 _13 _14 _15 _16
77        _17 _18 _19 _20 _21 _22 _23 _24 _25 _26 _27 _28 _29 _30 _31 _32
78        _33 _34 _35 _36 _37 _38 _39 _40 _41 _42 _43 _44 _45 _46 _47 _48
79        _49 _50 _51 _52 _53 _54 _55 _56 _57 _58 _59 _60 _61 _62 _63 _64
80    );
81}
82/*
83_65 _66 _67 _68 _69 _70 _71 _72 _73 _74 _75 _76 _77 _78 _79 _80
84_81 _82 _83 _84 _85 _86 _87 _88 _89 _90 _91 _92 _93 _94 _95 _96
85_97 _98 _99 _100 _101 _102 _103 _104 _105 _106 _107 _108 _109 _110 _111 _112
86_113 _114 _115 _116 _117 _118 _119 _120 _121 _122 _123 _124 _125 _126 _127 _128
87*/
88
89#[cfg(test)]
90mod test
91{
92    #[test]
93    fn test()
94    {
95        use crate::*;
96
97        type Mat2x3 = [[i8; 3]; 2];
98
99        /// The number of dimensions
100        const DEPTH: usize = 2;
101        
102        // `FLAT_LENGTH` is the combined length if the N-dimensional array was flattened
103        assert_eq!(<Mat2x3 as ArrayNd<DEPTH>>::FLAT_LENGTH, 6);
104        
105        // `DIMENSIONS` contains the lengths of each dimension ordered outermost to innermost.
106        assert_eq!(<Mat2x3 as ArrayNd<DEPTH>>::DIMENSIONS, [2, 3]);
107    }
108}