1use crate::dimension::slices_intersect;
9use crate::error::{ErrorKind, ShapeError};
10use crate::{ArrayViewMut, DimAdd, Dimension, Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, Ix6, IxDyn};
11use alloc::vec::Vec;
12use std::convert::TryFrom;
13use std::fmt;
14use std::marker::PhantomData;
15use std::ops::{Deref, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive};
16
17#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
38pub struct Slice {
39 pub start: isize,
41 pub end: Option<isize>,
44 pub step: isize,
46}
47
48impl Slice {
49 pub fn new(start: isize, end: Option<isize>, step: isize) -> Slice {
57 debug_assert_ne!(step, 0, "Slice::new: step must be nonzero");
58 Slice { start, end, step }
59 }
60
61 #[inline]
67 pub fn step_by(self, step: isize) -> Self {
68 debug_assert_ne!(step, 0, "Slice::step_by: step must be nonzero");
69 Slice {
70 step: self.step * step,
71 ..self
72 }
73 }
74}
75
76#[derive(Clone, Copy, Debug)]
80pub struct NewAxis;
81
82#[derive(Debug, PartialEq, Eq, Hash)]
111pub enum SliceInfoElem {
112 Slice {
116 start: isize,
118 end: Option<isize>,
121 step: isize,
123 },
124 Index(isize),
126 NewAxis,
128}
129
130copy_and_clone! {SliceInfoElem}
131
132impl SliceInfoElem {
133 pub fn is_slice(&self) -> bool {
135 matches!(self, SliceInfoElem::Slice { .. })
136 }
137
138 pub fn is_index(&self) -> bool {
140 matches!(self, SliceInfoElem::Index(_))
141 }
142
143 pub fn is_new_axis(&self) -> bool {
145 matches!(self, SliceInfoElem::NewAxis)
146 }
147}
148
149impl fmt::Display for SliceInfoElem {
150 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
151 match *self {
152 SliceInfoElem::Index(index) => write!(f, "{}", index)?,
153 SliceInfoElem::Slice { start, end, step } => {
154 if start != 0 {
155 write!(f, "{}", start)?;
156 }
157 write!(f, "..")?;
158 if let Some(i) = end {
159 write!(f, "{}", i)?;
160 }
161 if step != 1 {
162 write!(f, ";{}", step)?;
163 }
164 }
165 SliceInfoElem::NewAxis => write!(f, stringify!(NewAxis))?,
166 }
167 Ok(())
168 }
169}
170
171macro_rules! impl_slice_variant_from_range {
172 ($self:ty, $constructor:path, $index:ty) => {
173 impl From<Range<$index>> for $self {
174 #[inline]
175 fn from(r: Range<$index>) -> $self {
176 $constructor {
177 start: r.start as isize,
178 end: Some(r.end as isize),
179 step: 1,
180 }
181 }
182 }
183
184 impl From<RangeInclusive<$index>> for $self {
185 #[inline]
186 fn from(r: RangeInclusive<$index>) -> $self {
187 let end = *r.end() as isize;
188 $constructor {
189 start: *r.start() as isize,
190 end: if end == -1 { None } else { Some(end + 1) },
191 step: 1,
192 }
193 }
194 }
195
196 impl From<RangeFrom<$index>> for $self {
197 #[inline]
198 fn from(r: RangeFrom<$index>) -> $self {
199 $constructor {
200 start: r.start as isize,
201 end: None,
202 step: 1,
203 }
204 }
205 }
206
207 impl From<RangeTo<$index>> for $self {
208 #[inline]
209 fn from(r: RangeTo<$index>) -> $self {
210 $constructor {
211 start: 0,
212 end: Some(r.end as isize),
213 step: 1,
214 }
215 }
216 }
217
218 impl From<RangeToInclusive<$index>> for $self {
219 #[inline]
220 fn from(r: RangeToInclusive<$index>) -> $self {
221 let end = r.end as isize;
222 $constructor {
223 start: 0,
224 end: if end == -1 { None } else { Some(end + 1) },
225 step: 1,
226 }
227 }
228 }
229 };
230}
231impl_slice_variant_from_range!(Slice, Slice, isize);
232impl_slice_variant_from_range!(Slice, Slice, usize);
233impl_slice_variant_from_range!(Slice, Slice, i32);
234impl_slice_variant_from_range!(SliceInfoElem, SliceInfoElem::Slice, isize);
235impl_slice_variant_from_range!(SliceInfoElem, SliceInfoElem::Slice, usize);
236impl_slice_variant_from_range!(SliceInfoElem, SliceInfoElem::Slice, i32);
237
238impl From<RangeFull> for Slice {
239 #[inline]
240 fn from(_: RangeFull) -> Slice {
241 Slice {
242 start: 0,
243 end: None,
244 step: 1,
245 }
246 }
247}
248
249impl From<RangeFull> for SliceInfoElem {
250 #[inline]
251 fn from(_: RangeFull) -> SliceInfoElem {
252 SliceInfoElem::Slice {
253 start: 0,
254 end: None,
255 step: 1,
256 }
257 }
258}
259
260impl From<Slice> for SliceInfoElem {
261 #[inline]
262 fn from(s: Slice) -> SliceInfoElem {
263 SliceInfoElem::Slice {
264 start: s.start,
265 end: s.end,
266 step: s.step,
267 }
268 }
269}
270
271macro_rules! impl_sliceinfoelem_from_index {
272 ($index:ty) => {
273 impl From<$index> for SliceInfoElem {
274 #[inline]
275 fn from(r: $index) -> SliceInfoElem {
276 SliceInfoElem::Index(r as isize)
277 }
278 }
279 };
280}
281impl_sliceinfoelem_from_index!(isize);
282impl_sliceinfoelem_from_index!(usize);
283impl_sliceinfoelem_from_index!(i32);
284
285impl From<NewAxis> for SliceInfoElem {
286 #[inline]
287 fn from(_: NewAxis) -> SliceInfoElem {
288 SliceInfoElem::NewAxis
289 }
290}
291
292#[allow(clippy::missing_safety_doc)] pub unsafe trait SliceArg<D: Dimension>: AsRef<[SliceInfoElem]> {
300 type OutDim: Dimension;
302
303 fn in_ndim(&self) -> usize;
305
306 fn out_ndim(&self) -> usize;
308
309 private_decl! {}
310}
311
312unsafe impl<T, D> SliceArg<D> for &T
313where
314 T: SliceArg<D> + ?Sized,
315 D: Dimension,
316{
317 type OutDim = T::OutDim;
318
319 fn in_ndim(&self) -> usize {
320 T::in_ndim(self)
321 }
322
323 fn out_ndim(&self) -> usize {
324 T::out_ndim(self)
325 }
326
327 private_impl! {}
328}
329
330macro_rules! impl_slicearg_samedim {
331 ($in_dim:ty) => {
332 unsafe impl<T, Dout> SliceArg<$in_dim> for SliceInfo<T, $in_dim, Dout>
333 where
334 T: AsRef<[SliceInfoElem]>,
335 Dout: Dimension,
336 {
337 type OutDim = Dout;
338
339 fn in_ndim(&self) -> usize {
340 self.in_ndim()
341 }
342
343 fn out_ndim(&self) -> usize {
344 self.out_ndim()
345 }
346
347 private_impl! {}
348 }
349 };
350}
351impl_slicearg_samedim!(Ix0);
352impl_slicearg_samedim!(Ix1);
353impl_slicearg_samedim!(Ix2);
354impl_slicearg_samedim!(Ix3);
355impl_slicearg_samedim!(Ix4);
356impl_slicearg_samedim!(Ix5);
357impl_slicearg_samedim!(Ix6);
358
359unsafe impl<T, Din, Dout> SliceArg<IxDyn> for SliceInfo<T, Din, Dout>
360where
361 T: AsRef<[SliceInfoElem]>,
362 Din: Dimension,
363 Dout: Dimension,
364{
365 type OutDim = Dout;
366
367 fn in_ndim(&self) -> usize {
368 self.in_ndim()
369 }
370
371 fn out_ndim(&self) -> usize {
372 self.out_ndim()
373 }
374
375 private_impl! {}
376}
377
378unsafe impl SliceArg<IxDyn> for [SliceInfoElem] {
379 type OutDim = IxDyn;
380
381 fn in_ndim(&self) -> usize {
382 self.iter().filter(|s| !s.is_new_axis()).count()
383 }
384
385 fn out_ndim(&self) -> usize {
386 self.iter().filter(|s| !s.is_index()).count()
387 }
388
389 private_impl! {}
390}
391
392#[derive(Debug)]
403pub struct SliceInfo<T, Din: Dimension, Dout: Dimension> {
404 in_dim: PhantomData<Din>,
405 out_dim: PhantomData<Dout>,
406 indices: T,
407}
408
409impl<T, Din, Dout> Deref for SliceInfo<T, Din, Dout>
410where
411 Din: Dimension,
412 Dout: Dimension,
413{
414 type Target = T;
415 fn deref(&self) -> &Self::Target {
416 &self.indices
417 }
418}
419
420fn check_dims_for_sliceinfo<Din, Dout>(indices: &[SliceInfoElem]) -> Result<(), ShapeError>
421where
422 Din: Dimension,
423 Dout: Dimension,
424{
425 if let Some(in_ndim) = Din::NDIM {
426 if in_ndim != indices.in_ndim() {
427 return Err(ShapeError::from_kind(ErrorKind::IncompatibleShape));
428 }
429 }
430 if let Some(out_ndim) = Dout::NDIM {
431 if out_ndim != indices.out_ndim() {
432 return Err(ShapeError::from_kind(ErrorKind::IncompatibleShape));
433 }
434 }
435 Ok(())
436}
437
438impl<T, Din, Dout> SliceInfo<T, Din, Dout>
439where
440 T: AsRef<[SliceInfoElem]>,
441 Din: Dimension,
442 Dout: Dimension,
443{
444 #[doc(hidden)]
454 pub unsafe fn new_unchecked(
455 indices: T,
456 in_dim: PhantomData<Din>,
457 out_dim: PhantomData<Dout>,
458 ) -> SliceInfo<T, Din, Dout> {
459 if cfg!(debug_assertions) {
460 check_dims_for_sliceinfo::<Din, Dout>(indices.as_ref())
461 .expect("`Din` and `Dout` must be consistent with `indices`.");
462 }
463 SliceInfo {
464 in_dim,
465 out_dim,
466 indices,
467 }
468 }
469
470 pub unsafe fn new(indices: T) -> Result<SliceInfo<T, Din, Dout>, ShapeError> {
481 check_dims_for_sliceinfo::<Din, Dout>(indices.as_ref())?;
482 Ok(SliceInfo {
483 in_dim: PhantomData,
484 out_dim: PhantomData,
485 indices,
486 })
487 }
488
489 pub fn in_ndim(&self) -> usize {
496 if let Some(ndim) = Din::NDIM {
497 ndim
498 } else {
499 self.indices.as_ref().in_ndim()
500 }
501 }
502
503 pub fn out_ndim(&self) -> usize {
511 if let Some(ndim) = Dout::NDIM {
512 ndim
513 } else {
514 self.indices.as_ref().out_ndim()
515 }
516 }
517}
518
519impl<'a, Din, Dout> TryFrom<&'a [SliceInfoElem]> for SliceInfo<&'a [SliceInfoElem], Din, Dout>
520where
521 Din: Dimension,
522 Dout: Dimension,
523{
524 type Error = ShapeError;
525
526 fn try_from(
527 indices: &'a [SliceInfoElem],
528 ) -> Result<SliceInfo<&'a [SliceInfoElem], Din, Dout>, ShapeError> {
529 unsafe {
530 Self::new(indices)
533 }
534 }
535}
536
537impl<Din, Dout> TryFrom<Vec<SliceInfoElem>> for SliceInfo<Vec<SliceInfoElem>, Din, Dout>
538where
539 Din: Dimension,
540 Dout: Dimension,
541{
542 type Error = ShapeError;
543
544 fn try_from(
545 indices: Vec<SliceInfoElem>,
546 ) -> Result<SliceInfo<Vec<SliceInfoElem>, Din, Dout>, ShapeError> {
547 unsafe {
548 Self::new(indices)
551 }
552 }
553}
554
555macro_rules! impl_tryfrom_array_for_sliceinfo {
556 ($len:expr) => {
557 impl<Din, Dout> TryFrom<[SliceInfoElem; $len]>
558 for SliceInfo<[SliceInfoElem; $len], Din, Dout>
559 where
560 Din: Dimension,
561 Dout: Dimension,
562 {
563 type Error = ShapeError;
564
565 fn try_from(
566 indices: [SliceInfoElem; $len],
567 ) -> Result<SliceInfo<[SliceInfoElem; $len], Din, Dout>, ShapeError> {
568 unsafe {
569 Self::new(indices)
572 }
573 }
574 }
575 };
576}
577impl_tryfrom_array_for_sliceinfo!(0);
578impl_tryfrom_array_for_sliceinfo!(1);
579impl_tryfrom_array_for_sliceinfo!(2);
580impl_tryfrom_array_for_sliceinfo!(3);
581impl_tryfrom_array_for_sliceinfo!(4);
582impl_tryfrom_array_for_sliceinfo!(5);
583impl_tryfrom_array_for_sliceinfo!(6);
584impl_tryfrom_array_for_sliceinfo!(7);
585impl_tryfrom_array_for_sliceinfo!(8);
586
587impl<T, Din, Dout> AsRef<[SliceInfoElem]> for SliceInfo<T, Din, Dout>
588where
589 T: AsRef<[SliceInfoElem]>,
590 Din: Dimension,
591 Dout: Dimension,
592{
593 fn as_ref(&self) -> &[SliceInfoElem] {
594 self.indices.as_ref()
595 }
596}
597
598impl<'a, T, Din, Dout> From<&'a SliceInfo<T, Din, Dout>>
599 for SliceInfo<&'a [SliceInfoElem], Din, Dout>
600where
601 T: AsRef<[SliceInfoElem]>,
602 Din: Dimension,
603 Dout: Dimension,
604{
605 fn from(info: &'a SliceInfo<T, Din, Dout>) -> SliceInfo<&'a [SliceInfoElem], Din, Dout> {
606 SliceInfo {
607 in_dim: info.in_dim,
608 out_dim: info.out_dim,
609 indices: info.indices.as_ref(),
610 }
611 }
612}
613
614impl<T, Din, Dout> Copy for SliceInfo<T, Din, Dout>
615where
616 T: Copy,
617 Din: Dimension,
618 Dout: Dimension,
619{
620}
621
622impl<T, Din, Dout> Clone for SliceInfo<T, Din, Dout>
623where
624 T: Clone,
625 Din: Dimension,
626 Dout: Dimension,
627{
628 fn clone(&self) -> Self {
629 SliceInfo {
630 in_dim: PhantomData,
631 out_dim: PhantomData,
632 indices: self.indices.clone(),
633 }
634 }
635}
636
637#[doc(hidden)]
639pub trait SliceNextDim {
640 type InDim: Dimension;
642 type OutDim: Dimension;
644
645 fn next_in_dim<D>(&self, _: PhantomData<D>) -> PhantomData<<D as DimAdd<Self::InDim>>::Output>
646 where
647 D: Dimension + DimAdd<Self::InDim>,
648 {
649 PhantomData
650 }
651
652 fn next_out_dim<D>(&self, _: PhantomData<D>) -> PhantomData<<D as DimAdd<Self::OutDim>>::Output>
653 where
654 D: Dimension + DimAdd<Self::OutDim>,
655 {
656 PhantomData
657 }
658}
659
660macro_rules! impl_slicenextdim {
661 (($($generics:tt)*), $self:ty, $in:ty, $out:ty) => {
662 impl<$($generics)*> SliceNextDim for $self {
663 type InDim = $in;
664 type OutDim = $out;
665 }
666 };
667}
668
669impl_slicenextdim!((), isize, Ix1, Ix0);
670impl_slicenextdim!((), usize, Ix1, Ix0);
671impl_slicenextdim!((), i32, Ix1, Ix0);
672
673impl_slicenextdim!((T), Range<T>, Ix1, Ix1);
674impl_slicenextdim!((T), RangeInclusive<T>, Ix1, Ix1);
675impl_slicenextdim!((T), RangeFrom<T>, Ix1, Ix1);
676impl_slicenextdim!((T), RangeTo<T>, Ix1, Ix1);
677impl_slicenextdim!((T), RangeToInclusive<T>, Ix1, Ix1);
678impl_slicenextdim!((), RangeFull, Ix1, Ix1);
679impl_slicenextdim!((), Slice, Ix1, Ix1);
680
681impl_slicenextdim!((), NewAxis, Ix0, Ix1);
682
683#[macro_export]
775macro_rules! s(
776 (@parse $in_dim:expr, $out_dim:expr, [$($stack:tt)*] $r:expr;$s:expr) => {
778 match $r {
779 r => {
780 let in_dim = $crate::SliceNextDim::next_in_dim(&r, $in_dim);
781 let out_dim = $crate::SliceNextDim::next_out_dim(&r, $out_dim);
782 #[allow(unsafe_code)]
783 unsafe {
784 $crate::SliceInfo::new_unchecked(
785 [$($stack)* $crate::s!(@convert r, $s)],
786 in_dim,
787 out_dim,
788 )
789 }
790 }
791 }
792 };
793 (@parse $in_dim:expr, $out_dim:expr, [$($stack:tt)*] $r:expr) => {
795 match $r {
796 r => {
797 let in_dim = $crate::SliceNextDim::next_in_dim(&r, $in_dim);
798 let out_dim = $crate::SliceNextDim::next_out_dim(&r, $out_dim);
799 #[allow(unsafe_code)]
800 unsafe {
801 $crate::SliceInfo::new_unchecked(
802 [$($stack)* $crate::s!(@convert r)],
803 in_dim,
804 out_dim,
805 )
806 }
807 }
808 }
809 };
810 (@parse $in_dim:expr, $out_dim:expr, [$($stack:tt)*] $r:expr;$s:expr ,) => {
812 $crate::s![@parse $in_dim, $out_dim, [$($stack)*] $r;$s]
813 };
814 (@parse $in_dim:expr, $out_dim:expr, [$($stack:tt)*] $r:expr ,) => {
816 $crate::s![@parse $in_dim, $out_dim, [$($stack)*] $r]
817 };
818 (@parse $in_dim:expr, $out_dim:expr, [$($stack:tt)*] $r:expr;$s:expr, $($t:tt)*) => {
820 match $r {
821 r => {
822 $crate::s![@parse
823 $crate::SliceNextDim::next_in_dim(&r, $in_dim),
824 $crate::SliceNextDim::next_out_dim(&r, $out_dim),
825 [$($stack)* $crate::s!(@convert r, $s),]
826 $($t)*
827 ]
828 }
829 }
830 };
831 (@parse $in_dim:expr, $out_dim:expr, [$($stack:tt)*] $r:expr, $($t:tt)*) => {
833 match $r {
834 r => {
835 $crate::s![@parse
836 $crate::SliceNextDim::next_in_dim(&r, $in_dim),
837 $crate::SliceNextDim::next_out_dim(&r, $out_dim),
838 [$($stack)* $crate::s!(@convert r),]
839 $($t)*
840 ]
841 }
842 }
843 };
844 (@parse ::core::marker::PhantomData::<$crate::Ix0>, ::core::marker::PhantomData::<$crate::Ix0>, []) => {
846 {
847 #[allow(unsafe_code)]
848 unsafe {
849 $crate::SliceInfo::new_unchecked(
850 [],
851 ::core::marker::PhantomData::<$crate::Ix0>,
852 ::core::marker::PhantomData::<$crate::Ix0>,
853 )
854 }
855 }
856 };
857 (@parse $($t:tt)*) => { compile_error!("Invalid syntax in s![] call.") };
859 (@convert $r:expr) => {
861 <$crate::SliceInfoElem as ::core::convert::From<_>>::from($r)
862 };
863 (@convert $r:expr, $s:expr) => {
865 <$crate::SliceInfoElem as ::core::convert::From<_>>::from(
866 <$crate::Slice as ::core::convert::From<_>>::from($r).step_by($s as isize)
867 )
868 };
869 ($($t:tt)*) => {
870 $crate::s![@parse
871 ::core::marker::PhantomData::<$crate::Ix0>,
872 ::core::marker::PhantomData::<$crate::Ix0>,
873 []
874 $($t)*
875 ]
876 };
877);
878
879pub trait MultiSliceArg<'a, A, D>
884where
885 A: 'a,
886 D: Dimension,
887{
888 type Output;
890
891 fn multi_slice_move(&self, view: ArrayViewMut<'a, A, D>) -> Self::Output;
896
897 private_decl! {}
898}
899
900impl<'a, A, D> MultiSliceArg<'a, A, D> for ()
901where
902 A: 'a,
903 D: Dimension,
904{
905 type Output = ();
906
907 fn multi_slice_move(&self, _view: ArrayViewMut<'a, A, D>) -> Self::Output {}
908
909 private_impl! {}
910}
911
912impl<'a, A, D, I0> MultiSliceArg<'a, A, D> for (I0,)
913where
914 A: 'a,
915 D: Dimension,
916 I0: SliceArg<D>,
917{
918 type Output = (ArrayViewMut<'a, A, I0::OutDim>,);
919
920 fn multi_slice_move(&self, view: ArrayViewMut<'a, A, D>) -> Self::Output {
921 (view.slice_move(&self.0),)
922 }
923
924 private_impl! {}
925}
926
927macro_rules! impl_multislice_tuple {
928 ([$($but_last:ident)*] $last:ident) => {
929 impl_multislice_tuple!(@def_impl ($($but_last,)* $last,), [$($but_last)*] $last);
930 };
931 (@def_impl ($($all:ident,)*), [$($but_last:ident)*] $last:ident) => {
932 impl<'a, A, D, $($all,)*> MultiSliceArg<'a, A, D> for ($($all,)*)
933 where
934 A: 'a,
935 D: Dimension,
936 $($all: SliceArg<D>,)*
937 {
938 type Output = ($(ArrayViewMut<'a, A, $all::OutDim>,)*);
939
940 fn multi_slice_move(&self, view: ArrayViewMut<'a, A, D>) -> Self::Output {
941 #[allow(non_snake_case)]
942 let ($($all,)*) = self;
943
944 let shape = view.raw_dim();
945 assert!(!impl_multislice_tuple!(@intersects_self &shape, ($($all,)*)));
946
947 let raw_view = view.into_raw_view_mut();
948 unsafe {
949 (
950 $(raw_view.clone().slice_move($but_last).deref_into_view_mut(),)*
951 raw_view.slice_move($last).deref_into_view_mut(),
952 )
953 }
954 }
955
956 private_impl! {}
957 }
958 };
959 (@intersects_self $shape:expr, ($head:expr,)) => {
960 false
961 };
962 (@intersects_self $shape:expr, ($head:expr, $($tail:expr,)*)) => {
963 $(slices_intersect($shape, $head, $tail)) ||*
964 || impl_multislice_tuple!(@intersects_self $shape, ($($tail,)*))
965 };
966}
967
968impl_multislice_tuple!([I0] I1);
969impl_multislice_tuple!([I0 I1] I2);
970impl_multislice_tuple!([I0 I1 I2] I3);
971impl_multislice_tuple!([I0 I1 I2 I3] I4);
972impl_multislice_tuple!([I0 I1 I2 I3 I4] I5);
973
974impl<'a, A, D, T> MultiSliceArg<'a, A, D> for &T
975where
976 A: 'a,
977 D: Dimension,
978 T: MultiSliceArg<'a, A, D>,
979{
980 type Output = T::Output;
981
982 fn multi_slice_move(&self, view: ArrayViewMut<'a, A, D>) -> Self::Output {
983 T::multi_slice_move(self, view)
984 }
985
986 private_impl! {}
987}