1pub trait FlatIndex<T> {
2 fn flat_len(&self) -> usize;
3 fn flat_index(&self, i: usize) -> &T;
4 fn flat_index_mut(&mut self, i: usize) -> &mut T;
5}
6impl<T> FlatIndex<T> for T {
7 fn flat_len(&self) -> usize {
8 1
9 }
10 fn flat_index(&self, i: usize) -> &T {
11 assert!(i == 0);
12 self
13 }
14 fn flat_index_mut(&mut self, i: usize) -> &mut T {
15 assert!(i == 0);
16 self
17 }
18}
19impl<T> FlatIndex<T> for [T] {
20 fn flat_len(&self) -> usize {
21 self.len()
22 }
23 fn flat_index(&self, i: usize) -> &T {
24 &self[i]
25 }
26 fn flat_index_mut(&mut self, i: usize) -> &mut T {
27 &mut self[i]
28 }
29}
30impl<T> FlatIndex<T> for Option<T> {
31 fn flat_len(&self) -> usize {
32 self.is_some() as usize
33 }
34 fn flat_index(&self, i: usize) -> &T {
35 assert!(i == 0);
36 self.as_ref().unwrap()
37 }
38 fn flat_index_mut(&mut self, i: usize) -> &mut T {
39 assert!(i == 0);
40 self.as_mut().unwrap()
41 }
42}
43impl<T> FlatIndex<T> for Vec<T> {
44 fn flat_len(&self) -> usize {
45 self.len()
46 }
47 fn flat_index(&self, i: usize) -> &T {
48 &self[i]
49 }
50 fn flat_index_mut(&mut self, i: usize) -> &mut T {
51 &mut self[i]
52 }
53}
54impl<T, const N: usize> FlatIndex<T> for [T; N] {
55 fn flat_len(&self) -> usize {
56 N
57 }
58 fn flat_index(&self, i: usize) -> &T {
59 &self[i]
60 }
61 fn flat_index_mut(&mut self, i: usize) -> &mut T {
62 &mut self[i]
63 }
64}
65
66#[macro_export]
67macro_rules! flat_combine_len {
68 (<$t:ty>) => { 0 };
69 (<$t:ty> <$e:expr, $le:ident, $re:ident> $(, $($tt:tt)*)?) => {
70 $e.$le() + $crate::flat_combine_len!(<$t> $($($tt)*)?)
71 };
72 (<$t:ty> $e:expr $(, $($tt:tt)*)?) => {
73 $crate::flatindex::FlatIndex::<$t>::flat_len($e) + $crate::flat_combine_len!(<$t> $($($tt)*)?)
74 };
75 }
79
80#[macro_export]
81macro_rules! flat_combine {
82 (<$t:ty> $idx:expr $(,)?) => { panic!("Index out of bounds") };
83 (<$t:ty> $idx:expr, <$e:expr, $le:ident, $re:ident> $(, $($tt:tt)*)?) => {{
84 let __idx: usize = $idx;
85 let __len = $e.$le();
86 if __idx < __len {
87 $e.$re(__idx)
88 } else {
89 $crate::flat_combine!(<$t> __idx - __len $(, $($tt)*)?)
90 }
91 }};
92 (<$t:ty> $idx:expr, $e:expr $(, $($tt:tt)*)?) => {{
93 let __idx: usize = $idx;
94 let __len = $crate::flatindex::FlatIndex::<$t>::flat_len($e);
95 if __idx < __len {
96 $crate::flatindex::FlatIndex::<$t>::flat_index($e, __idx)
97 } else {
98 $crate::flat_combine!(<$t> __idx - __len $(, $($tt)*)?)
99 }
100 }};
101 }
111
112#[macro_export]
113macro_rules! flat_combine_mut {
114 (<$t:ty> $idx:expr $(,)?) => { panic!("Index out of bounds") };
115 (<$t:ty> $idx:expr, <$e:expr, $le:ident, $re:ident> $(, $($tt:tt)*)?) => {{
116 let __idx: usize = $idx;
117 let __len = $e.$le();
118 if __idx < __len {
119 $e.$re(__idx)
120 } else {
121 $crate::flat_combine_mut!(<$t> __idx - __len $(, $($tt)*)?)
122 }
123 }};
124 (<$t:ty> $idx:expr, $e:expr $(, $($tt:tt)*)?) => {{
125 let __idx: usize = $idx;
126 let __len = $crate::flatindex::FlatIndex::<$t>::flat_len($e);
127 if __idx < __len {
128 $crate::flatindex::FlatIndex::<$t>::flat_index_mut($e, __idx)
129 } else {
130 $crate::flat_combine_mut!(<$t> __idx - __len $(, $($tt)*)?)
131 }
132 }};
133 }
143
144#[macro_export]
145macro_rules! flat_combine_deref {
146 (<$t:ty> $idx:expr $(,)?) => { panic!("Index out of bounds") };
147 (<$t:ty> $idx:expr, <$e:expr, $le:ident, $re:ident> $(, $($tt:tt)*)?) => {{
148 let __idx: usize = $idx;
149 let __len = $e.$le();
150 if __idx < __len {
151 $e.$re(__idx)
152 } else {
153 $crate::flat_combine_deref!(<$t> __idx - __len $(, $($tt)*)?)
154 }
155 }};
156 (<$t:ty> $idx:expr, $e:expr $(, $($tt:tt)*)?) => {{
157 let __idx: usize = $idx;
158 let __len = $crate::flatindex::FlatIndex::<$t>::flat_len($e);
159 if __idx < __len {
160 *$crate::flatindex::FlatIndex::<$t>::flat_index($e, __idx)
161 } else {
162 $crate::flat_combine_deref!(<$t> __idx - __len $(, $($tt)*)?)
163 }
164 }};
165}
166
167#[cfg(test)]
168mod tests {
169 use std::ops::Index;
170 #[test]
171 fn combine() {
172 let mut a: Vec<usize> = vec![0, 1, 2, 3, 4, 5];
173 let mut b: Vec<usize> = vec![6, 7, 8, 9, 10, 11];
174 let mut c: Option<usize> = Some(12);
175 let mut d: Option<usize> = None;
176 let mut e: [usize; 3] = [13, 14, 15];
177 assert_eq!(flat_combine_len!(<usize> &a, &b), 12);
178 assert_eq!(flat_combine_len!(<usize> &a, &b, &c, &d, &e), 16);
179 for i in 0..16 {
180 let combined = flat_combine!(<usize> i, &a, <&b, len, index>, &c, &d, &e);
181 assert_eq!(combined, &i);
182 assert_eq!(
183 *flat_combine_mut!(<usize> i, &mut a, <&mut b, len, index>, &mut c, &mut d, &mut e),
184 i
185 );
186 assert_eq!(flat_combine_deref!(<usize> i, &a, &b, &c, &d, &e), i);
187 }
188 }
189
190 #[test]
191 #[should_panic]
192 fn out_of_range() {
193 let a: Vec<usize> = vec![0, 1, 2, 3, 4, 5];
194 let b: Vec<usize> = vec![6, 7, 8, 9, 10, 11];
195 let c: Option<usize> = Some(12);
196 let d: Option<usize> = None;
197 let e: [usize; 3] = [13, 14, 15];
198 flat_combine!(<usize> 16, &a, <&b, len, index>, &c, &d, &e);
199 }
200}