1use std::fmt::Debug;
2
3use super::{stride_offset, stride_offset_checked};
4use crate::itertools::zip;
5use crate::{Dim, Dimension, IntoDimension, Ix, Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, Ix6, IxDyn, IxDynImpl};
6
7#[allow(clippy::missing_safety_doc)] pub unsafe trait NdIndex<E>: Debug
21{
22 #[doc(hidden)]
23 fn index_checked(&self, dim: &E, strides: &E) -> Option<isize>;
24 #[doc(hidden)]
25 fn index_unchecked(&self, strides: &E) -> isize;
26}
27
28unsafe impl<D> NdIndex<D> for D
29where D: Dimension
30{
31 fn index_checked(&self, dim: &D, strides: &D) -> Option<isize>
32 {
33 dim.stride_offset_checked(strides, self)
34 }
35 fn index_unchecked(&self, strides: &D) -> isize
36 {
37 D::stride_offset(self, strides)
38 }
39}
40
41unsafe impl NdIndex<Ix0> for ()
42{
43 #[inline]
44 fn index_checked(&self, dim: &Ix0, strides: &Ix0) -> Option<isize>
45 {
46 dim.stride_offset_checked(strides, &Ix0())
47 }
48 #[inline(always)]
49 fn index_unchecked(&self, _strides: &Ix0) -> isize
50 {
51 0
52 }
53}
54
55unsafe impl NdIndex<Ix2> for (Ix, Ix)
56{
57 #[inline]
58 fn index_checked(&self, dim: &Ix2, strides: &Ix2) -> Option<isize>
59 {
60 dim.stride_offset_checked(strides, &Ix2(self.0, self.1))
61 }
62 #[inline]
63 fn index_unchecked(&self, strides: &Ix2) -> isize
64 {
65 stride_offset(self.0, get!(strides, 0)) + stride_offset(self.1, get!(strides, 1))
66 }
67}
68unsafe impl NdIndex<Ix3> for (Ix, Ix, Ix)
69{
70 #[inline]
71 fn index_checked(&self, dim: &Ix3, strides: &Ix3) -> Option<isize>
72 {
73 dim.stride_offset_checked(strides, &self.into_dimension())
74 }
75
76 #[inline]
77 fn index_unchecked(&self, strides: &Ix3) -> isize
78 {
79 stride_offset(self.0, get!(strides, 0))
80 + stride_offset(self.1, get!(strides, 1))
81 + stride_offset(self.2, get!(strides, 2))
82 }
83}
84
85unsafe impl NdIndex<Ix4> for (Ix, Ix, Ix, Ix)
86{
87 #[inline]
88 fn index_checked(&self, dim: &Ix4, strides: &Ix4) -> Option<isize>
89 {
90 dim.stride_offset_checked(strides, &self.into_dimension())
91 }
92 #[inline]
93 fn index_unchecked(&self, strides: &Ix4) -> isize
94 {
95 zip(strides.ix(), self.into_dimension().ix())
96 .map(|(&s, &i)| stride_offset(i, s))
97 .sum()
98 }
99}
100unsafe impl NdIndex<Ix5> for (Ix, Ix, Ix, Ix, Ix)
101{
102 #[inline]
103 fn index_checked(&self, dim: &Ix5, strides: &Ix5) -> Option<isize>
104 {
105 dim.stride_offset_checked(strides, &self.into_dimension())
106 }
107 #[inline]
108 fn index_unchecked(&self, strides: &Ix5) -> isize
109 {
110 zip(strides.ix(), self.into_dimension().ix())
111 .map(|(&s, &i)| stride_offset(i, s))
112 .sum()
113 }
114}
115
116unsafe impl NdIndex<Ix6> for (Ix, Ix, Ix, Ix, Ix, Ix)
117{
118 #[inline]
119 fn index_checked(&self, dim: &Ix6, strides: &Ix6) -> Option<isize>
120 {
121 dim.stride_offset_checked(strides, &self.into_dimension())
122 }
123 #[inline]
124 fn index_unchecked(&self, strides: &Ix6) -> isize
125 {
126 zip(strides.ix(), self.into_dimension().ix())
127 .map(|(&s, &i)| stride_offset(i, s))
128 .sum()
129 }
130}
131
132unsafe impl NdIndex<Ix1> for Ix
133{
134 #[inline]
135 fn index_checked(&self, dim: &Ix1, strides: &Ix1) -> Option<isize>
136 {
137 dim.stride_offset_checked(strides, &Ix1(*self))
138 }
139 #[inline(always)]
140 fn index_unchecked(&self, strides: &Ix1) -> isize
141 {
142 stride_offset(*self, get!(strides, 0))
143 }
144}
145
146unsafe impl NdIndex<IxDyn> for Ix
147{
148 #[inline]
149 fn index_checked(&self, dim: &IxDyn, strides: &IxDyn) -> Option<isize>
150 {
151 debug_assert_eq!(dim.ndim(), 1);
152 stride_offset_checked(dim.ix(), strides.ix(), &[*self])
153 }
154 #[inline(always)]
155 fn index_unchecked(&self, strides: &IxDyn) -> isize
156 {
157 debug_assert_eq!(strides.ndim(), 1);
158 stride_offset(*self, get!(strides, 0))
159 }
160}
161
162macro_rules! ndindex_with_array {
163 ($([$n:expr, $ix_n:ident $($index:tt)*])+) => {
164 $(
165 unsafe impl NdIndex<$ix_n> for [Ix; $n] {
167 #[inline]
168 fn index_checked(&self, dim: &$ix_n, strides: &$ix_n) -> Option<isize> {
169 dim.stride_offset_checked(strides, &self.into_dimension())
170 }
171
172 #[inline]
173 fn index_unchecked(&self, _strides: &$ix_n) -> isize {
174 $(
175 stride_offset(self[$index], get!(_strides, $index)) +
176 )*
177 0
178 }
179 }
180 )+
181 };
182}
183
184ndindex_with_array! {
185 [0, Ix0]
186 [1, Ix1 0]
187 [2, Ix2 0 1]
188 [3, Ix3 0 1 2]
189 [4, Ix4 0 1 2 3]
190 [5, Ix5 0 1 2 3 4]
191 [6, Ix6 0 1 2 3 4 5]
192}
193
194unsafe impl<const N: usize> NdIndex<IxDyn> for Dim<[Ix; N]>
196{
197 #[inline]
198 fn index_checked(&self, dim: &IxDyn, strides: &IxDyn) -> Option<isize>
199 {
200 debug_assert_eq!(
201 strides.ndim(),
202 N,
203 "Attempted to index with {:?} in array with {} axes",
204 self,
205 strides.ndim()
206 );
207 stride_offset_checked(dim.ix(), strides.ix(), self.ix())
208 }
209
210 #[inline]
211 fn index_unchecked(&self, strides: &IxDyn) -> isize
212 {
213 debug_assert_eq!(
214 strides.ndim(),
215 N,
216 "Attempted to index with {:?} in array with {} axes",
217 self,
218 strides.ndim()
219 );
220 (0..N)
221 .map(|i| stride_offset(get!(self, i), get!(strides, i)))
222 .sum()
223 }
224}
225
226unsafe impl<const N: usize> NdIndex<IxDyn> for [Ix; N]
228{
229 #[inline]
230 fn index_checked(&self, dim: &IxDyn, strides: &IxDyn) -> Option<isize>
231 {
232 debug_assert_eq!(
233 strides.ndim(),
234 N,
235 "Attempted to index with {:?} in array with {} axes",
236 self,
237 strides.ndim()
238 );
239 stride_offset_checked(dim.ix(), strides.ix(), self)
240 }
241
242 #[inline]
243 fn index_unchecked(&self, strides: &IxDyn) -> isize
244 {
245 debug_assert_eq!(
246 strides.ndim(),
247 N,
248 "Attempted to index with {:?} in array with {} axes",
249 self,
250 strides.ndim()
251 );
252 (0..N)
253 .map(|i| stride_offset(self[i], get!(strides, i)))
254 .sum()
255 }
256}
257
258impl<'a> IntoDimension for &'a [Ix]
259{
260 type Dim = IxDyn;
261 fn into_dimension(self) -> Self::Dim
262 {
263 Dim(IxDynImpl::from(self))
264 }
265}
266
267unsafe impl<'a> NdIndex<IxDyn> for &'a IxDyn
268{
269 fn index_checked(&self, dim: &IxDyn, strides: &IxDyn) -> Option<isize>
270 {
271 (**self).index_checked(dim, strides)
272 }
273 fn index_unchecked(&self, strides: &IxDyn) -> isize
274 {
275 (**self).index_unchecked(strides)
276 }
277}
278
279unsafe impl<'a> NdIndex<IxDyn> for &'a [Ix]
280{
281 fn index_checked(&self, dim: &IxDyn, strides: &IxDyn) -> Option<isize>
282 {
283 stride_offset_checked(dim.ix(), strides.ix(), self)
284 }
285 fn index_unchecked(&self, strides: &IxDyn) -> isize
286 {
287 zip(strides.ix(), *self)
288 .map(|(&s, &i)| stride_offset(i, s))
289 .sum()
290 }
291}