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