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,
40 pub end: Option<isize>,
41 pub step: isize,
42}
43
44impl Slice {
45 pub fn new(start: isize, end: Option<isize>, step: isize) -> Slice {
53 debug_assert_ne!(step, 0, "Slice::new: step must be nonzero");
54 Slice { start, end, step }
55 }
56
57 #[inline]
63 pub fn step_by(self, step: isize) -> Self {
64 debug_assert_ne!(step, 0, "Slice::step_by: step must be nonzero");
65 Slice {
66 step: self.step * step,
67 ..self
68 }
69 }
70}
71
72#[derive(Clone, Copy, Debug)]
76pub struct NewAxis;
77
78#[derive(Debug, PartialEq, Eq, Hash)]
107pub enum SliceInfoElem {
108 Slice {
112 start: isize,
113 end: Option<isize>,
114 step: isize,
115 },
116 Index(isize),
118 NewAxis,
120}
121
122copy_and_clone! {SliceInfoElem}
123
124impl SliceInfoElem {
125 pub fn is_slice(&self) -> bool {
127 matches!(self, SliceInfoElem::Slice { .. })
128 }
129
130 pub fn is_index(&self) -> bool {
132 matches!(self, SliceInfoElem::Index(_))
133 }
134
135 pub fn is_new_axis(&self) -> bool {
137 matches!(self, SliceInfoElem::NewAxis)
138 }
139}
140
141impl fmt::Display for SliceInfoElem {
142 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143 match *self {
144 SliceInfoElem::Index(index) => write!(f, "{}", index)?,
145 SliceInfoElem::Slice { start, end, step } => {
146 if start != 0 {
147 write!(f, "{}", start)?;
148 }
149 write!(f, "..")?;
150 if let Some(i) = end {
151 write!(f, "{}", i)?;
152 }
153 if step != 1 {
154 write!(f, ";{}", step)?;
155 }
156 }
157 SliceInfoElem::NewAxis => write!(f, stringify!(NewAxis))?,
158 }
159 Ok(())
160 }
161}
162
163macro_rules! impl_slice_variant_from_range {
164 ($self:ty, $constructor:path, $index:ty) => {
165 impl From<Range<$index>> for $self {
166 #[inline]
167 fn from(r: Range<$index>) -> $self {
168 $constructor {
169 start: r.start as isize,
170 end: Some(r.end as isize),
171 step: 1,
172 }
173 }
174 }
175
176 impl From<RangeInclusive<$index>> for $self {
177 #[inline]
178 fn from(r: RangeInclusive<$index>) -> $self {
179 let end = *r.end() as isize;
180 $constructor {
181 start: *r.start() as isize,
182 end: if end == -1 { None } else { Some(end + 1) },
183 step: 1,
184 }
185 }
186 }
187
188 impl From<RangeFrom<$index>> for $self {
189 #[inline]
190 fn from(r: RangeFrom<$index>) -> $self {
191 $constructor {
192 start: r.start as isize,
193 end: None,
194 step: 1,
195 }
196 }
197 }
198
199 impl From<RangeTo<$index>> for $self {
200 #[inline]
201 fn from(r: RangeTo<$index>) -> $self {
202 $constructor {
203 start: 0,
204 end: Some(r.end as isize),
205 step: 1,
206 }
207 }
208 }
209
210 impl From<RangeToInclusive<$index>> for $self {
211 #[inline]
212 fn from(r: RangeToInclusive<$index>) -> $self {
213 let end = r.end as isize;
214 $constructor {
215 start: 0,
216 end: if end == -1 { None } else { Some(end + 1) },
217 step: 1,
218 }
219 }
220 }
221 };
222}
223impl_slice_variant_from_range!(Slice, Slice, isize);
224impl_slice_variant_from_range!(Slice, Slice, usize);
225impl_slice_variant_from_range!(Slice, Slice, i32);
226impl_slice_variant_from_range!(SliceInfoElem, SliceInfoElem::Slice, isize);
227impl_slice_variant_from_range!(SliceInfoElem, SliceInfoElem::Slice, usize);
228impl_slice_variant_from_range!(SliceInfoElem, SliceInfoElem::Slice, i32);
229
230impl From<RangeFull> for Slice {
231 #[inline]
232 fn from(_: RangeFull) -> Slice {
233 Slice {
234 start: 0,
235 end: None,
236 step: 1,
237 }
238 }
239}
240
241impl From<RangeFull> for SliceInfoElem {
242 #[inline]
243 fn from(_: RangeFull) -> SliceInfoElem {
244 SliceInfoElem::Slice {
245 start: 0,
246 end: None,
247 step: 1,
248 }
249 }
250}
251
252impl From<Slice> for SliceInfoElem {
253 #[inline]
254 fn from(s: Slice) -> SliceInfoElem {
255 SliceInfoElem::Slice {
256 start: s.start,
257 end: s.end,
258 step: s.step,
259 }
260 }
261}
262
263macro_rules! impl_sliceinfoelem_from_index {
264 ($index:ty) => {
265 impl From<$index> for SliceInfoElem {
266 #[inline]
267 fn from(r: $index) -> SliceInfoElem {
268 SliceInfoElem::Index(r as isize)
269 }
270 }
271 };
272}
273impl_sliceinfoelem_from_index!(isize);
274impl_sliceinfoelem_from_index!(usize);
275impl_sliceinfoelem_from_index!(i32);
276
277impl From<NewAxis> for SliceInfoElem {
278 #[inline]
279 fn from(_: NewAxis) -> SliceInfoElem {
280 SliceInfoElem::NewAxis
281 }
282}
283
284pub unsafe trait SliceArg<D: Dimension>: AsRef<[SliceInfoElem]> {
291 type OutDim: Dimension;
293
294 fn in_ndim(&self) -> usize;
296
297 fn out_ndim(&self) -> usize;
299
300 private_decl! {}
301}
302
303unsafe impl<T, D> SliceArg<D> for &T
304where
305 T: SliceArg<D> + ?Sized,
306 D: Dimension,
307{
308 type OutDim = T::OutDim;
309
310 fn in_ndim(&self) -> usize {
311 T::in_ndim(self)
312 }
313
314 fn out_ndim(&self) -> usize {
315 T::out_ndim(self)
316 }
317
318 private_impl! {}
319}
320
321macro_rules! impl_slicearg_samedim {
322 ($in_dim:ty) => {
323 unsafe impl<T, Dout> SliceArg<$in_dim> for SliceInfo<T, $in_dim, Dout>
324 where
325 T: AsRef<[SliceInfoElem]>,
326 Dout: Dimension,
327 {
328 type OutDim = Dout;
329
330 fn in_ndim(&self) -> usize {
331 self.in_ndim()
332 }
333
334 fn out_ndim(&self) -> usize {
335 self.out_ndim()
336 }
337
338 private_impl! {}
339 }
340 };
341}
342impl_slicearg_samedim!(Ix0);
343impl_slicearg_samedim!(Ix1);
344impl_slicearg_samedim!(Ix2);
345impl_slicearg_samedim!(Ix3);
346impl_slicearg_samedim!(Ix4);
347impl_slicearg_samedim!(Ix5);
348impl_slicearg_samedim!(Ix6);
349
350unsafe impl<T, Din, Dout> SliceArg<IxDyn> for SliceInfo<T, Din, Dout>
351where
352 T: AsRef<[SliceInfoElem]>,
353 Din: Dimension,
354 Dout: Dimension,
355{
356 type OutDim = Dout;
357
358 fn in_ndim(&self) -> usize {
359 self.in_ndim()
360 }
361
362 fn out_ndim(&self) -> usize {
363 self.out_ndim()
364 }
365
366 private_impl! {}
367}
368
369unsafe impl SliceArg<IxDyn> for [SliceInfoElem] {
370 type OutDim = IxDyn;
371
372 fn in_ndim(&self) -> usize {
373 self.iter().filter(|s| !s.is_new_axis()).count()
374 }
375
376 fn out_ndim(&self) -> usize {
377 self.iter().filter(|s| !s.is_index()).count()
378 }
379
380 private_impl! {}
381}
382
383#[derive(Debug)]
394pub struct SliceInfo<T, Din: Dimension, Dout: Dimension> {
395 in_dim: PhantomData<Din>,
396 out_dim: PhantomData<Dout>,
397 indices: T,
398}
399
400impl<T, Din, Dout> Deref for SliceInfo<T, Din, Dout>
401where
402 Din: Dimension,
403 Dout: Dimension,
404{
405 type Target = T;
406 fn deref(&self) -> &Self::Target {
407 &self.indices
408 }
409}
410
411fn check_dims_for_sliceinfo<Din, Dout>(indices: &[SliceInfoElem]) -> Result<(), ShapeError>
412where
413 Din: Dimension,
414 Dout: Dimension,
415{
416 if let Some(in_ndim) = Din::NDIM {
417 if in_ndim != indices.in_ndim() {
418 return Err(ShapeError::from_kind(ErrorKind::IncompatibleShape));
419 }
420 }
421 if let Some(out_ndim) = Dout::NDIM {
422 if out_ndim != indices.out_ndim() {
423 return Err(ShapeError::from_kind(ErrorKind::IncompatibleShape));
424 }
425 }
426 Ok(())
427}
428
429impl<T, Din, Dout> SliceInfo<T, Din, Dout>
430where
431 T: AsRef<[SliceInfoElem]>,
432 Din: Dimension,
433 Dout: Dimension,
434{
435 #[doc(hidden)]
445 pub unsafe fn new_unchecked(
446 indices: T,
447 in_dim: PhantomData<Din>,
448 out_dim: PhantomData<Dout>,
449 ) -> SliceInfo<T, Din, Dout> {
450 if cfg!(debug_assertions) {
451 check_dims_for_sliceinfo::<Din, Dout>(indices.as_ref())
452 .expect("`Din` and `Dout` must be consistent with `indices`.");
453 }
454 SliceInfo {
455 in_dim,
456 out_dim,
457 indices,
458 }
459 }
460
461 pub unsafe fn new(indices: T) -> Result<SliceInfo<T, Din, Dout>, ShapeError> {
472 check_dims_for_sliceinfo::<Din, Dout>(indices.as_ref())?;
473 Ok(SliceInfo {
474 in_dim: PhantomData,
475 out_dim: PhantomData,
476 indices,
477 })
478 }
479
480 pub fn in_ndim(&self) -> usize {
487 if let Some(ndim) = Din::NDIM {
488 ndim
489 } else {
490 self.indices.as_ref().in_ndim()
491 }
492 }
493
494 pub fn out_ndim(&self) -> usize {
502 if let Some(ndim) = Dout::NDIM {
503 ndim
504 } else {
505 self.indices.as_ref().out_ndim()
506 }
507 }
508}
509
510impl<'a, Din, Dout> TryFrom<&'a [SliceInfoElem]> for SliceInfo<&'a [SliceInfoElem], Din, Dout>
511where
512 Din: Dimension,
513 Dout: Dimension,
514{
515 type Error = ShapeError;
516
517 fn try_from(
518 indices: &'a [SliceInfoElem],
519 ) -> Result<SliceInfo<&'a [SliceInfoElem], Din, Dout>, ShapeError> {
520 unsafe {
521 Self::new(indices)
524 }
525 }
526}
527
528impl<Din, Dout> TryFrom<Vec<SliceInfoElem>> for SliceInfo<Vec<SliceInfoElem>, Din, Dout>
529where
530 Din: Dimension,
531 Dout: Dimension,
532{
533 type Error = ShapeError;
534
535 fn try_from(
536 indices: Vec<SliceInfoElem>,
537 ) -> Result<SliceInfo<Vec<SliceInfoElem>, Din, Dout>, ShapeError> {
538 unsafe {
539 Self::new(indices)
542 }
543 }
544}
545
546macro_rules! impl_tryfrom_array_for_sliceinfo {
547 ($len:expr) => {
548 impl<Din, Dout> TryFrom<[SliceInfoElem; $len]>
549 for SliceInfo<[SliceInfoElem; $len], Din, Dout>
550 where
551 Din: Dimension,
552 Dout: Dimension,
553 {
554 type Error = ShapeError;
555
556 fn try_from(
557 indices: [SliceInfoElem; $len],
558 ) -> Result<SliceInfo<[SliceInfoElem; $len], Din, Dout>, ShapeError> {
559 unsafe {
560 Self::new(indices)
563 }
564 }
565 }
566 };
567}
568impl_tryfrom_array_for_sliceinfo!(0);
569impl_tryfrom_array_for_sliceinfo!(1);
570impl_tryfrom_array_for_sliceinfo!(2);
571impl_tryfrom_array_for_sliceinfo!(3);
572impl_tryfrom_array_for_sliceinfo!(4);
573impl_tryfrom_array_for_sliceinfo!(5);
574impl_tryfrom_array_for_sliceinfo!(6);
575impl_tryfrom_array_for_sliceinfo!(7);
576impl_tryfrom_array_for_sliceinfo!(8);
577
578impl<T, Din, Dout> AsRef<[SliceInfoElem]> for SliceInfo<T, Din, Dout>
579where
580 T: AsRef<[SliceInfoElem]>,
581 Din: Dimension,
582 Dout: Dimension,
583{
584 fn as_ref(&self) -> &[SliceInfoElem] {
585 self.indices.as_ref()
586 }
587}
588
589impl<'a, T, Din, Dout> From<&'a SliceInfo<T, Din, Dout>>
590 for SliceInfo<&'a [SliceInfoElem], Din, Dout>
591where
592 T: AsRef<[SliceInfoElem]>,
593 Din: Dimension,
594 Dout: Dimension,
595{
596 fn from(info: &'a SliceInfo<T, Din, Dout>) -> SliceInfo<&'a [SliceInfoElem], Din, Dout> {
597 SliceInfo {
598 in_dim: info.in_dim,
599 out_dim: info.out_dim,
600 indices: info.indices.as_ref(),
601 }
602 }
603}
604
605impl<T, Din, Dout> Copy for SliceInfo<T, Din, Dout>
606where
607 T: Copy,
608 Din: Dimension,
609 Dout: Dimension,
610{
611}
612
613impl<T, Din, Dout> Clone for SliceInfo<T, Din, Dout>
614where
615 T: Clone,
616 Din: Dimension,
617 Dout: Dimension,
618{
619 fn clone(&self) -> Self {
620 SliceInfo {
621 in_dim: PhantomData,
622 out_dim: PhantomData,
623 indices: self.indices.clone(),
624 }
625 }
626}
627
628#[doc(hidden)]
630pub trait SliceNextDim {
631 type InDim: Dimension;
633 type OutDim: Dimension;
635
636 fn next_in_dim<D>(&self, _: PhantomData<D>) -> PhantomData<<D as DimAdd<Self::InDim>>::Output>
637 where
638 D: Dimension + DimAdd<Self::InDim>,
639 {
640 PhantomData
641 }
642
643 fn next_out_dim<D>(&self, _: PhantomData<D>) -> PhantomData<<D as DimAdd<Self::OutDim>>::Output>
644 where
645 D: Dimension + DimAdd<Self::OutDim>,
646 {
647 PhantomData
648 }
649}
650
651macro_rules! impl_slicenextdim {
652 (($($generics:tt)*), $self:ty, $in:ty, $out:ty) => {
653 impl<$($generics)*> SliceNextDim for $self {
654 type InDim = $in;
655 type OutDim = $out;
656 }
657 };
658}
659
660impl_slicenextdim!((), isize, Ix1, Ix0);
661impl_slicenextdim!((), usize, Ix1, Ix0);
662impl_slicenextdim!((), i32, Ix1, Ix0);
663
664impl_slicenextdim!((T), Range<T>, Ix1, Ix1);
665impl_slicenextdim!((T), RangeInclusive<T>, Ix1, Ix1);
666impl_slicenextdim!((T), RangeFrom<T>, Ix1, Ix1);
667impl_slicenextdim!((T), RangeTo<T>, Ix1, Ix1);
668impl_slicenextdim!((T), RangeToInclusive<T>, Ix1, Ix1);
669impl_slicenextdim!((), RangeFull, Ix1, Ix1);
670impl_slicenextdim!((), Slice, Ix1, Ix1);
671
672impl_slicenextdim!((), NewAxis, Ix0, Ix1);
673
674#[macro_export]
769macro_rules! s(
770 (@parse $in_dim:expr, $out_dim:expr, [$($stack:tt)*] $r:expr;$s:expr) => {
772 match $r {
773 r => {
774 let in_dim = $crate::SliceNextDim::next_in_dim(&r, $in_dim);
775 let out_dim = $crate::SliceNextDim::next_out_dim(&r, $out_dim);
776 #[allow(unsafe_code)]
777 unsafe {
778 $crate::SliceInfo::new_unchecked(
779 [$($stack)* $crate::s!(@convert r, $s)],
780 in_dim,
781 out_dim,
782 )
783 }
784 }
785 }
786 };
787 (@parse $in_dim:expr, $out_dim:expr, [$($stack:tt)*] $r:expr) => {
789 match $r {
790 r => {
791 let in_dim = $crate::SliceNextDim::next_in_dim(&r, $in_dim);
792 let out_dim = $crate::SliceNextDim::next_out_dim(&r, $out_dim);
793 #[allow(unsafe_code)]
794 unsafe {
795 $crate::SliceInfo::new_unchecked(
796 [$($stack)* $crate::s!(@convert r)],
797 in_dim,
798 out_dim,
799 )
800 }
801 }
802 }
803 };
804 (@parse $in_dim:expr, $out_dim:expr, [$($stack:tt)*] $r:expr;$s:expr ,) => {
806 $crate::s![@parse $in_dim, $out_dim, [$($stack)*] $r;$s]
807 };
808 (@parse $in_dim:expr, $out_dim:expr, [$($stack:tt)*] $r:expr ,) => {
810 $crate::s![@parse $in_dim, $out_dim, [$($stack)*] $r]
811 };
812 (@parse $in_dim:expr, $out_dim:expr, [$($stack:tt)*] $r:expr;$s:expr, $($t:tt)*) => {
814 match $r {
815 r => {
816 $crate::s![@parse
817 $crate::SliceNextDim::next_in_dim(&r, $in_dim),
818 $crate::SliceNextDim::next_out_dim(&r, $out_dim),
819 [$($stack)* $crate::s!(@convert r, $s),]
820 $($t)*
821 ]
822 }
823 }
824 };
825 (@parse $in_dim:expr, $out_dim:expr, [$($stack:tt)*] $r:expr, $($t:tt)*) => {
827 match $r {
828 r => {
829 $crate::s![@parse
830 $crate::SliceNextDim::next_in_dim(&r, $in_dim),
831 $crate::SliceNextDim::next_out_dim(&r, $out_dim),
832 [$($stack)* $crate::s!(@convert r),]
833 $($t)*
834 ]
835 }
836 }
837 };
838 (@parse ::std::marker::PhantomData::<$crate::Ix0>, ::std::marker::PhantomData::<$crate::Ix0>, []) => {
840 {
841 #[allow(unsafe_code)]
842 unsafe {
843 $crate::SliceInfo::new_unchecked(
844 [],
845 ::std::marker::PhantomData::<$crate::Ix0>,
846 ::std::marker::PhantomData::<$crate::Ix0>,
847 )
848 }
849 }
850 };
851 (@parse $($t:tt)*) => { compile_error!("Invalid syntax in s![] call.") };
853 (@convert $r:expr) => {
855 <$crate::SliceInfoElem as ::std::convert::From<_>>::from($r)
856 };
857 (@convert $r:expr, $s:expr) => {
859 <$crate::SliceInfoElem as ::std::convert::From<_>>::from(
860 <$crate::Slice as ::std::convert::From<_>>::from($r).step_by($s as isize)
861 )
862 };
863 ($($t:tt)*) => {
864 $crate::s![@parse
865 ::std::marker::PhantomData::<$crate::Ix0>,
866 ::std::marker::PhantomData::<$crate::Ix0>,
867 []
868 $($t)*
869 ]
870 };
871);
872
873pub trait MultiSliceArg<'a, A, D>
878where
879 A: 'a,
880 D: Dimension,
881{
882 type Output;
884
885 fn multi_slice_move(&self, view: ArrayViewMut<'a, A, D>) -> Self::Output;
890
891 private_decl! {}
892}
893
894impl<'a, A, D> MultiSliceArg<'a, A, D> for ()
895where
896 A: 'a,
897 D: Dimension,
898{
899 type Output = ();
900
901 fn multi_slice_move(&self, _view: ArrayViewMut<'a, A, D>) -> Self::Output {}
902
903 private_impl! {}
904}
905
906impl<'a, A, D, I0> MultiSliceArg<'a, A, D> for (I0,)
907where
908 A: 'a,
909 D: Dimension,
910 I0: SliceArg<D>,
911{
912 type Output = (ArrayViewMut<'a, A, I0::OutDim>,);
913
914 fn multi_slice_move(&self, view: ArrayViewMut<'a, A, D>) -> Self::Output {
915 (view.slice_move(&self.0),)
916 }
917
918 private_impl! {}
919}
920
921macro_rules! impl_multislice_tuple {
922 ([$($but_last:ident)*] $last:ident) => {
923 impl_multislice_tuple!(@def_impl ($($but_last,)* $last,), [$($but_last)*] $last);
924 };
925 (@def_impl ($($all:ident,)*), [$($but_last:ident)*] $last:ident) => {
926 impl<'a, A, D, $($all,)*> MultiSliceArg<'a, A, D> for ($($all,)*)
927 where
928 A: 'a,
929 D: Dimension,
930 $($all: SliceArg<D>,)*
931 {
932 type Output = ($(ArrayViewMut<'a, A, $all::OutDim>,)*);
933
934 fn multi_slice_move(&self, view: ArrayViewMut<'a, A, D>) -> Self::Output {
935 #[allow(non_snake_case)]
936 let ($($all,)*) = self;
937
938 let shape = view.raw_dim();
939 assert!(!impl_multislice_tuple!(@intersects_self &shape, ($($all,)*)));
940
941 let raw_view = view.into_raw_view_mut();
942 unsafe {
943 (
944 $(raw_view.clone().slice_move($but_last).deref_into_view_mut(),)*
945 raw_view.slice_move($last).deref_into_view_mut(),
946 )
947 }
948 }
949
950 private_impl! {}
951 }
952 };
953 (@intersects_self $shape:expr, ($head:expr,)) => {
954 false
955 };
956 (@intersects_self $shape:expr, ($head:expr, $($tail:expr,)*)) => {
957 $(slices_intersect($shape, $head, $tail)) ||*
958 || impl_multislice_tuple!(@intersects_self $shape, ($($tail,)*))
959 };
960}
961
962impl_multislice_tuple!([I0] I1);
963impl_multislice_tuple!([I0 I1] I2);
964impl_multislice_tuple!([I0 I1 I2] I3);
965impl_multislice_tuple!([I0 I1 I2 I3] I4);
966impl_multislice_tuple!([I0 I1 I2 I3 I4] I5);
967
968impl<'a, A, D, T> MultiSliceArg<'a, A, D> for &T
969where
970 A: 'a,
971 D: Dimension,
972 T: MultiSliceArg<'a, A, D>,
973{
974 type Output = T::Output;
975
976 fn multi_slice_move(&self, view: ArrayViewMut<'a, A, D>) -> Self::Output {
977 T::multi_slice_move(self, view)
978 }
979
980 private_impl! {}
981}