1use crate::dimension::slices_intersect;
9use crate::error::{ErrorKind, ShapeError};
10#[cfg(doc)]
11use crate::s;
12use crate::{ArrayViewMut, DimAdd, Dimension, Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, Ix6, IxDyn};
13
14#[cfg(not(feature = "std"))]
15use alloc::vec::Vec;
16use std::convert::TryFrom;
17use std::fmt;
18use std::marker::PhantomData;
19use std::ops::{Deref, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive};
20
21#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
42pub struct Slice
43{
44 pub start: isize,
46 pub end: Option<isize>,
49 pub step: isize,
51}
52
53impl Slice
54{
55 pub fn new(start: isize, end: Option<isize>, step: isize) -> Slice
63 {
64 debug_assert_ne!(step, 0, "Slice::new: step must be nonzero");
65 Slice { start, end, step }
66 }
67
68 #[inline]
74 pub fn step_by(self, step: isize) -> Self
75 {
76 debug_assert_ne!(step, 0, "Slice::step_by: step must be nonzero");
77 Slice {
78 step: self.step * step,
79 ..self
80 }
81 }
82}
83
84#[derive(Clone, Copy, Debug)]
88pub struct NewAxis;
89
90#[derive(Debug, PartialEq, Eq, Hash)]
119pub enum SliceInfoElem
120{
121 Slice
125 {
126 start: isize,
128 end: Option<isize>,
131 step: isize,
133 },
134 Index(isize),
136 NewAxis,
138}
139
140copy_and_clone! {SliceInfoElem}
141
142impl SliceInfoElem
143{
144 pub fn is_slice(&self) -> bool
146 {
147 matches!(self, SliceInfoElem::Slice { .. })
148 }
149
150 pub fn is_index(&self) -> bool
152 {
153 matches!(self, SliceInfoElem::Index(_))
154 }
155
156 pub fn is_new_axis(&self) -> bool
158 {
159 matches!(self, SliceInfoElem::NewAxis)
160 }
161}
162
163impl fmt::Display for SliceInfoElem
164{
165 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
166 {
167 match *self {
168 SliceInfoElem::Index(index) => write!(f, "{}", index)?,
169 SliceInfoElem::Slice { start, end, step } => {
170 if start != 0 {
171 write!(f, "{}", start)?;
172 }
173 write!(f, "..")?;
174 if let Some(i) = end {
175 write!(f, "{}", i)?;
176 }
177 if step != 1 {
178 write!(f, ";{}", step)?;
179 }
180 }
181 SliceInfoElem::NewAxis => write!(f, stringify!(NewAxis))?,
182 }
183 Ok(())
184 }
185}
186
187macro_rules! impl_slice_variant_from_range {
188 ($self:ty, $constructor:path, $index:ty) => {
189 impl From<Range<$index>> for $self {
190 #[inline]
191 fn from(r: Range<$index>) -> $self {
192 $constructor {
193 start: r.start as isize,
194 end: Some(r.end as isize),
195 step: 1,
196 }
197 }
198 }
199
200 impl From<RangeInclusive<$index>> for $self {
201 #[inline]
202 fn from(r: RangeInclusive<$index>) -> $self {
203 let end = *r.end() as isize;
204 $constructor {
205 start: *r.start() as isize,
206 end: if end == -1 { None } else { Some(end + 1) },
207 step: 1,
208 }
209 }
210 }
211
212 impl From<RangeFrom<$index>> for $self {
213 #[inline]
214 fn from(r: RangeFrom<$index>) -> $self {
215 $constructor {
216 start: r.start as isize,
217 end: None,
218 step: 1,
219 }
220 }
221 }
222
223 impl From<RangeTo<$index>> for $self {
224 #[inline]
225 fn from(r: RangeTo<$index>) -> $self {
226 $constructor {
227 start: 0,
228 end: Some(r.end as isize),
229 step: 1,
230 }
231 }
232 }
233
234 impl From<RangeToInclusive<$index>> for $self {
235 #[inline]
236 fn from(r: RangeToInclusive<$index>) -> $self {
237 let end = r.end as isize;
238 $constructor {
239 start: 0,
240 end: if end == -1 { None } else { Some(end + 1) },
241 step: 1,
242 }
243 }
244 }
245 };
246}
247impl_slice_variant_from_range!(Slice, Slice, isize);
248impl_slice_variant_from_range!(Slice, Slice, usize);
249impl_slice_variant_from_range!(Slice, Slice, i32);
250impl_slice_variant_from_range!(SliceInfoElem, SliceInfoElem::Slice, isize);
251impl_slice_variant_from_range!(SliceInfoElem, SliceInfoElem::Slice, usize);
252impl_slice_variant_from_range!(SliceInfoElem, SliceInfoElem::Slice, i32);
253
254impl From<RangeFull> for Slice
255{
256 #[inline]
257 fn from(_: RangeFull) -> Slice
258 {
259 Slice {
260 start: 0,
261 end: None,
262 step: 1,
263 }
264 }
265}
266
267impl From<RangeFull> for SliceInfoElem
268{
269 #[inline]
270 fn from(_: RangeFull) -> SliceInfoElem
271 {
272 SliceInfoElem::Slice {
273 start: 0,
274 end: None,
275 step: 1,
276 }
277 }
278}
279
280impl From<Slice> for SliceInfoElem
281{
282 #[inline]
283 fn from(s: Slice) -> SliceInfoElem
284 {
285 SliceInfoElem::Slice {
286 start: s.start,
287 end: s.end,
288 step: s.step,
289 }
290 }
291}
292
293macro_rules! impl_sliceinfoelem_from_index {
294 ($index:ty) => {
295 impl From<$index> for SliceInfoElem {
296 #[inline]
297 fn from(r: $index) -> SliceInfoElem {
298 SliceInfoElem::Index(r as isize)
299 }
300 }
301 };
302}
303impl_sliceinfoelem_from_index!(isize);
304impl_sliceinfoelem_from_index!(usize);
305impl_sliceinfoelem_from_index!(i32);
306
307impl From<NewAxis> for SliceInfoElem
308{
309 #[inline]
310 fn from(_: NewAxis) -> SliceInfoElem
311 {
312 SliceInfoElem::NewAxis
313 }
314}
315
316#[allow(clippy::missing_safety_doc)] pub unsafe trait SliceArg<D: Dimension>: AsRef<[SliceInfoElem]>
324{
325 type OutDim: Dimension;
327
328 fn in_ndim(&self) -> usize;
330
331 fn out_ndim(&self) -> usize;
333
334 private_decl! {}
335}
336
337unsafe impl<T, D> SliceArg<D> for &T
338where
339 T: SliceArg<D> + ?Sized,
340 D: Dimension,
341{
342 type OutDim = T::OutDim;
343
344 fn in_ndim(&self) -> usize
345 {
346 T::in_ndim(self)
347 }
348
349 fn out_ndim(&self) -> usize
350 {
351 T::out_ndim(self)
352 }
353
354 private_impl! {}
355}
356
357macro_rules! impl_slicearg_samedim {
358 ($in_dim:ty) => {
359 unsafe impl<T, Dout> SliceArg<$in_dim> for SliceInfo<T, $in_dim, Dout>
360 where
361 T: AsRef<[SliceInfoElem]>,
362 Dout: Dimension,
363 {
364 type OutDim = Dout;
365
366 fn in_ndim(&self) -> usize {
367 self.in_ndim()
368 }
369
370 fn out_ndim(&self) -> usize {
371 self.out_ndim()
372 }
373
374 private_impl! {}
375 }
376 };
377}
378impl_slicearg_samedim!(Ix0);
379impl_slicearg_samedim!(Ix1);
380impl_slicearg_samedim!(Ix2);
381impl_slicearg_samedim!(Ix3);
382impl_slicearg_samedim!(Ix4);
383impl_slicearg_samedim!(Ix5);
384impl_slicearg_samedim!(Ix6);
385
386unsafe impl<T, Din, Dout> SliceArg<IxDyn> for SliceInfo<T, Din, Dout>
387where
388 T: AsRef<[SliceInfoElem]>,
389 Din: Dimension,
390 Dout: Dimension,
391{
392 type OutDim = Dout;
393
394 fn in_ndim(&self) -> usize
395 {
396 self.in_ndim()
397 }
398
399 fn out_ndim(&self) -> usize
400 {
401 self.out_ndim()
402 }
403
404 private_impl! {}
405}
406
407unsafe impl SliceArg<IxDyn> for [SliceInfoElem]
408{
409 type OutDim = IxDyn;
410
411 fn in_ndim(&self) -> usize
412 {
413 self.iter().filter(|s| !s.is_new_axis()).count()
414 }
415
416 fn out_ndim(&self) -> usize
417 {
418 self.iter().filter(|s| !s.is_index()).count()
419 }
420
421 private_impl! {}
422}
423
424#[derive(Debug)]
435pub struct SliceInfo<T, Din: Dimension, Dout: Dimension>
436{
437 in_dim: PhantomData<Din>,
438 out_dim: PhantomData<Dout>,
439 indices: T,
440}
441
442impl<T, Din, Dout> Deref for SliceInfo<T, Din, Dout>
443where
444 Din: Dimension,
445 Dout: Dimension,
446{
447 type Target = T;
448 fn deref(&self) -> &Self::Target
449 {
450 &self.indices
451 }
452}
453
454fn check_dims_for_sliceinfo<Din, Dout>(indices: &[SliceInfoElem]) -> Result<(), ShapeError>
455where
456 Din: Dimension,
457 Dout: Dimension,
458{
459 if let Some(in_ndim) = Din::NDIM {
460 if in_ndim != indices.in_ndim() {
461 return Err(ShapeError::from_kind(ErrorKind::IncompatibleShape));
462 }
463 }
464 if let Some(out_ndim) = Dout::NDIM {
465 if out_ndim != indices.out_ndim() {
466 return Err(ShapeError::from_kind(ErrorKind::IncompatibleShape));
467 }
468 }
469 Ok(())
470}
471
472impl<T, Din, Dout> SliceInfo<T, Din, Dout>
473where
474 T: AsRef<[SliceInfoElem]>,
475 Din: Dimension,
476 Dout: Dimension,
477{
478 #[doc(hidden)]
488 pub unsafe fn new_unchecked(
489 indices: T, in_dim: PhantomData<Din>, out_dim: PhantomData<Dout>,
490 ) -> SliceInfo<T, Din, Dout>
491 {
492 if cfg!(debug_assertions) {
493 check_dims_for_sliceinfo::<Din, Dout>(indices.as_ref())
494 .expect("`Din` and `Dout` must be consistent with `indices`.");
495 }
496 SliceInfo {
497 in_dim,
498 out_dim,
499 indices,
500 }
501 }
502
503 pub unsafe fn new(indices: T) -> Result<SliceInfo<T, Din, Dout>, ShapeError>
514 {
515 check_dims_for_sliceinfo::<Din, Dout>(indices.as_ref())?;
516 Ok(SliceInfo {
517 in_dim: PhantomData,
518 out_dim: PhantomData,
519 indices,
520 })
521 }
522
523 pub fn in_ndim(&self) -> usize
530 {
531 if let Some(ndim) = Din::NDIM {
532 ndim
533 } else {
534 self.indices.as_ref().in_ndim()
535 }
536 }
537
538 pub fn out_ndim(&self) -> usize
546 {
547 if let Some(ndim) = Dout::NDIM {
548 ndim
549 } else {
550 self.indices.as_ref().out_ndim()
551 }
552 }
553}
554
555impl<'a, Din, Dout> TryFrom<&'a [SliceInfoElem]> for SliceInfo<&'a [SliceInfoElem], Din, Dout>
556where
557 Din: Dimension,
558 Dout: Dimension,
559{
560 type Error = ShapeError;
561
562 fn try_from(indices: &'a [SliceInfoElem]) -> Result<SliceInfo<&'a [SliceInfoElem], Din, Dout>, ShapeError>
563 {
564 unsafe {
565 Self::new(indices)
568 }
569 }
570}
571
572impl<Din, Dout> TryFrom<Vec<SliceInfoElem>> for SliceInfo<Vec<SliceInfoElem>, Din, Dout>
573where
574 Din: Dimension,
575 Dout: Dimension,
576{
577 type Error = ShapeError;
578
579 fn try_from(indices: Vec<SliceInfoElem>) -> Result<SliceInfo<Vec<SliceInfoElem>, Din, Dout>, ShapeError>
580 {
581 unsafe {
582 Self::new(indices)
585 }
586 }
587}
588
589macro_rules! impl_tryfrom_array_for_sliceinfo {
590 ($len:expr) => {
591 impl<Din, Dout> TryFrom<[SliceInfoElem; $len]>
592 for SliceInfo<[SliceInfoElem; $len], Din, Dout>
593 where
594 Din: Dimension,
595 Dout: Dimension,
596 {
597 type Error = ShapeError;
598
599 fn try_from(
600 indices: [SliceInfoElem; $len],
601 ) -> Result<SliceInfo<[SliceInfoElem; $len], Din, Dout>, ShapeError> {
602 unsafe {
603 Self::new(indices)
606 }
607 }
608 }
609 };
610}
611impl_tryfrom_array_for_sliceinfo!(0);
612impl_tryfrom_array_for_sliceinfo!(1);
613impl_tryfrom_array_for_sliceinfo!(2);
614impl_tryfrom_array_for_sliceinfo!(3);
615impl_tryfrom_array_for_sliceinfo!(4);
616impl_tryfrom_array_for_sliceinfo!(5);
617impl_tryfrom_array_for_sliceinfo!(6);
618impl_tryfrom_array_for_sliceinfo!(7);
619impl_tryfrom_array_for_sliceinfo!(8);
620
621impl<T, Din, Dout> AsRef<[SliceInfoElem]> for SliceInfo<T, Din, Dout>
622where
623 T: AsRef<[SliceInfoElem]>,
624 Din: Dimension,
625 Dout: Dimension,
626{
627 fn as_ref(&self) -> &[SliceInfoElem]
628 {
629 self.indices.as_ref()
630 }
631}
632
633impl<'a, T, Din, Dout> From<&'a SliceInfo<T, Din, Dout>> for SliceInfo<&'a [SliceInfoElem], Din, Dout>
634where
635 T: AsRef<[SliceInfoElem]>,
636 Din: Dimension,
637 Dout: Dimension,
638{
639 fn from(info: &'a SliceInfo<T, Din, Dout>) -> SliceInfo<&'a [SliceInfoElem], Din, Dout>
640 {
641 SliceInfo {
642 in_dim: info.in_dim,
643 out_dim: info.out_dim,
644 indices: info.indices.as_ref(),
645 }
646 }
647}
648
649impl<T, Din, Dout> Copy for SliceInfo<T, Din, Dout>
650where
651 T: Copy,
652 Din: Dimension,
653 Dout: Dimension,
654{
655}
656
657impl<T, Din, Dout> Clone for SliceInfo<T, Din, Dout>
658where
659 T: Clone,
660 Din: Dimension,
661 Dout: Dimension,
662{
663 fn clone(&self) -> Self
664 {
665 SliceInfo {
666 in_dim: PhantomData,
667 out_dim: PhantomData,
668 indices: self.indices.clone(),
669 }
670 }
671}
672
673#[doc(hidden)]
675pub trait SliceNextDim
676{
677 type InDim: Dimension;
679 type OutDim: Dimension;
681
682 fn next_in_dim<D>(&self, _: PhantomData<D>) -> PhantomData<<D as DimAdd<Self::InDim>>::Output>
683 where D: Dimension + DimAdd<Self::InDim>
684 {
685 PhantomData
686 }
687
688 fn next_out_dim<D>(&self, _: PhantomData<D>) -> PhantomData<<D as DimAdd<Self::OutDim>>::Output>
689 where D: Dimension + DimAdd<Self::OutDim>
690 {
691 PhantomData
692 }
693}
694
695macro_rules! impl_slicenextdim {
696 (($($generics:tt)*), $self:ty, $in:ty, $out:ty) => {
697 impl<$($generics)*> SliceNextDim for $self {
698 type InDim = $in;
699 type OutDim = $out;
700 }
701 };
702}
703
704impl_slicenextdim!((), isize, Ix1, Ix0);
705impl_slicenextdim!((), usize, Ix1, Ix0);
706impl_slicenextdim!((), i32, Ix1, Ix0);
707
708impl_slicenextdim!((T), Range<T>, Ix1, Ix1);
709impl_slicenextdim!((T), RangeInclusive<T>, Ix1, Ix1);
710impl_slicenextdim!((T), RangeFrom<T>, Ix1, Ix1);
711impl_slicenextdim!((T), RangeTo<T>, Ix1, Ix1);
712impl_slicenextdim!((T), RangeToInclusive<T>, Ix1, Ix1);
713impl_slicenextdim!((), RangeFull, Ix1, Ix1);
714impl_slicenextdim!((), Slice, Ix1, Ix1);
715
716impl_slicenextdim!((), NewAxis, Ix0, Ix1);
717
718#[macro_export]
810macro_rules! s(
811 (@parse $in_dim:expr, $out_dim:expr, [$($stack:tt)*] $r:expr;$s:expr) => {
813 match $r {
814 r => {
815 let in_dim = $crate::SliceNextDim::next_in_dim(&r, $in_dim);
816 let out_dim = $crate::SliceNextDim::next_out_dim(&r, $out_dim);
817 (
818 [$($stack)* $crate::s!(@convert r, $s)],
819 in_dim,
820 out_dim,
821 )
822 }
823 }
824 };
825 (@parse $in_dim:expr, $out_dim:expr, [$($stack:tt)*] $r:expr) => {
827 match $r {
828 r => {
829 let in_dim = $crate::SliceNextDim::next_in_dim(&r, $in_dim);
830 let out_dim = $crate::SliceNextDim::next_out_dim(&r, $out_dim);
831 (
832 [$($stack)* $crate::s!(@convert r)],
833 in_dim,
834 out_dim,
835 )
836 }
837 }
838 };
839 (@parse $in_dim:expr, $out_dim:expr, [$($stack:tt)*] $r:expr;$s:expr ,) => {
841 $crate::s![@parse $in_dim, $out_dim, [$($stack)*] $r;$s]
842 };
843 (@parse $in_dim:expr, $out_dim:expr, [$($stack:tt)*] $r:expr ,) => {
845 $crate::s![@parse $in_dim, $out_dim, [$($stack)*] $r]
846 };
847 (@parse $in_dim:expr, $out_dim:expr, [$($stack:tt)*] $r:expr;$s:expr, $($t:tt)*) => {
849 match $r {
850 r => {
851 $crate::s![@parse
852 $crate::SliceNextDim::next_in_dim(&r, $in_dim),
853 $crate::SliceNextDim::next_out_dim(&r, $out_dim),
854 [$($stack)* $crate::s!(@convert r, $s),]
855 $($t)*
856 ]
857 }
858 }
859 };
860 (@parse $in_dim:expr, $out_dim:expr, [$($stack:tt)*] $r:expr, $($t:tt)*) => {
862 match $r {
863 r => {
864 $crate::s![@parse
865 $crate::SliceNextDim::next_in_dim(&r, $in_dim),
866 $crate::SliceNextDim::next_out_dim(&r, $out_dim),
867 [$($stack)* $crate::s!(@convert r),]
868 $($t)*
869 ]
870 }
871 }
872 };
873 (@parse ::core::marker::PhantomData::<$crate::Ix0>, ::core::marker::PhantomData::<$crate::Ix0>, []) => {
875 (
876 [],
877 ::core::marker::PhantomData::<$crate::Ix0>,
878 ::core::marker::PhantomData::<$crate::Ix0>,
879 )
880 };
881 (@parse $($t:tt)*) => { compile_error!("Invalid syntax in s![] call.") };
883 (@convert $r:expr) => {
885 <$crate::SliceInfoElem as ::core::convert::From<_>>::from($r)
886 };
887 (@convert $r:expr, $s:expr) => {
889 <$crate::SliceInfoElem as ::core::convert::From<_>>::from(
890 <$crate::Slice as ::core::convert::From<_>>::from($r).step_by($s as isize)
891 )
892 };
893 ($($t:tt)*) => {
894 {
895 let (indices, in_dim, out_dim) = $crate::s![@parse
896 ::core::marker::PhantomData::<$crate::Ix0>,
897 ::core::marker::PhantomData::<$crate::Ix0>,
898 []
899 $($t)*
900 ];
901 #[allow(unsafe_code)]
904 unsafe {
905 $crate::SliceInfo::new_unchecked(indices, in_dim, out_dim)
906 }
907 }
908 };
909);
910
911pub trait MultiSliceArg<'a, A, D>
916where
917 A: 'a,
918 D: Dimension,
919{
920 type Output;
922
923 fn multi_slice_move(&self, view: ArrayViewMut<'a, A, D>) -> Self::Output;
928
929 private_decl! {}
930}
931
932impl<'a, A, D> MultiSliceArg<'a, A, D> for ()
933where
934 A: 'a,
935 D: Dimension,
936{
937 type Output = ();
938
939 fn multi_slice_move(&self, _view: ArrayViewMut<'a, A, D>) -> Self::Output {}
940
941 private_impl! {}
942}
943
944impl<'a, A, D, I0> MultiSliceArg<'a, A, D> for (I0,)
945where
946 A: 'a,
947 D: Dimension,
948 I0: SliceArg<D>,
949{
950 type Output = (ArrayViewMut<'a, A, I0::OutDim>,);
951
952 fn multi_slice_move(&self, view: ArrayViewMut<'a, A, D>) -> Self::Output
953 {
954 (view.slice_move(&self.0),)
955 }
956
957 private_impl! {}
958}
959
960macro_rules! impl_multislice_tuple {
961 ([$($but_last:ident)*] $last:ident) => {
962 impl_multislice_tuple!(@def_impl ($($but_last,)* $last,), [$($but_last)*] $last);
963 };
964 (@def_impl ($($all:ident,)*), [$($but_last:ident)*] $last:ident) => {
965 impl<'a, A, D, $($all,)*> MultiSliceArg<'a, A, D> for ($($all,)*)
966 where
967 A: 'a,
968 D: Dimension,
969 $($all: SliceArg<D>,)*
970 {
971 type Output = ($(ArrayViewMut<'a, A, $all::OutDim>,)*);
972
973 fn multi_slice_move(&self, view: ArrayViewMut<'a, A, D>) -> Self::Output {
974 #[allow(non_snake_case)]
975 let ($($all,)*) = self;
976
977 let shape = view.raw_dim();
978 assert!(!impl_multislice_tuple!(@intersects_self &shape, ($($all,)*)));
979
980 let raw_view = view.into_raw_view_mut();
981 unsafe {
982 (
983 $(raw_view.clone().slice_move($but_last).deref_into_view_mut(),)*
984 raw_view.slice_move($last).deref_into_view_mut(),
985 )
986 }
987 }
988
989 private_impl! {}
990 }
991 };
992 (@intersects_self $shape:expr, ($head:expr,)) => {
993 false
994 };
995 (@intersects_self $shape:expr, ($head:expr, $($tail:expr,)*)) => {
996 $(slices_intersect($shape, $head, $tail)) ||*
997 || impl_multislice_tuple!(@intersects_self $shape, ($($tail,)*))
998 };
999}
1000
1001impl_multislice_tuple!([I0] I1);
1002impl_multislice_tuple!([I0 I1] I2);
1003impl_multislice_tuple!([I0 I1 I2] I3);
1004impl_multislice_tuple!([I0 I1 I2 I3] I4);
1005impl_multislice_tuple!([I0 I1 I2 I3 I4] I5);
1006
1007impl<'a, A, D, T> MultiSliceArg<'a, A, D> for &T
1008where
1009 A: 'a,
1010 D: Dimension,
1011 T: MultiSliceArg<'a, A, D>,
1012{
1013 type Output = T::Output;
1014
1015 fn multi_slice_move(&self, view: ArrayViewMut<'a, A, D>) -> Self::Output
1016 {
1017 T::multi_slice_move(self, view)
1018 }
1019
1020 private_impl! {}
1021}