1use std::iter::zip;
10
11use serde::Deserialize;
12use serde::Serialize;
13
14#[derive(Debug, thiserror::Error)]
16#[non_exhaustive]
17pub enum SliceError {
18 #[error("invalid dims: expected {expected}, got {got}")]
19 InvalidDims { expected: usize, got: usize },
20
21 #[error("nonrectangular shape")]
22 NonrectangularShape,
23
24 #[error("nonunique strides")]
25 NonuniqueStrides,
26
27 #[error("stride {stride} must be larger than size of previous space {space}")]
28 StrideTooSmall { stride: usize, space: usize },
29
30 #[error("index {index} out of range {total}")]
31 IndexOutOfRange { index: usize, total: usize },
32
33 #[error("value {value} not in slice")]
34 ValueNotInSlice { value: usize },
35
36 #[error("incompatible view: {reason}")]
37 IncompatibleView { reason: String },
38
39 #[error("noncontiguous shape")]
40 NonContiguous,
41
42 #[error("empty range: {begin}..{end} (step {step})")]
43 EmptyRange {
44 begin: usize,
45 end: usize,
46 step: usize,
47 },
48
49 #[error("dimension {dim} out of range for {ndims}-dimensional slice")]
50 DimensionOutOfRange { dim: usize, ndims: usize },
51
52 #[error("slice arithmetic overflow")]
53 ArithmeticOverflow,
54}
55
56#[derive(Serialize, Deserialize, Clone, Eq, PartialEq, Hash, Debug)]
89pub struct Slice {
90 offset: usize,
91 sizes: Vec<usize>,
92 strides: Vec<usize>,
93}
94
95impl Slice {
96 pub fn new(offset: usize, sizes: Vec<usize>, strides: Vec<usize>) -> Result<Self, SliceError> {
103 if sizes.len() != strides.len() {
104 return Err(SliceError::InvalidDims {
105 expected: sizes.len(),
106 got: strides.len(),
107 });
108 }
109 let mut combined: Vec<(usize, usize)> =
110 strides.iter().cloned().zip(sizes.iter().cloned()).collect();
111 combined.sort();
112
113 let mut prev_stride: Option<usize> = None;
114 let mut prev_size: Option<usize> = None;
115 let mut total: usize = 1;
116 for (stride, size) in combined {
117 if let Some(prev_stride) = prev_stride {
118 if stride % prev_stride != 0 {
119 return Err(SliceError::NonrectangularShape);
120 }
121 if stride == prev_stride && size != 1 && prev_size.unwrap_or(1) != 1 {
123 return Err(SliceError::NonuniqueStrides);
124 }
125 }
126 if total > stride {
127 return Err(SliceError::StrideTooSmall {
128 stride,
129 space: total,
130 });
131 }
132 total = stride * size;
133 prev_stride = Some(stride);
134 prev_size = Some(size);
135 }
136
137 Ok(Slice {
138 offset,
139 sizes,
140 strides,
141 })
142 }
143
144 pub fn into_inner(self) -> (usize, Vec<usize>, Vec<usize>) {
146 let Slice {
147 offset,
148 sizes,
149 strides,
150 } = self;
151 (offset, sizes, strides)
152 }
153
154 pub fn new_row_major(sizes: impl Into<Vec<usize>>) -> Self {
156 let sizes = sizes.into();
157 let mut strides: Vec<usize> = sizes.clone();
159 let _ = strides.iter_mut().rev().fold(1, |acc, n| {
160 let next = *n * acc;
161 *n = acc;
162 next
163 });
164 Self {
165 offset: 0,
166 sizes,
167 strides,
168 }
169 }
170
171 pub fn new_single_multi_dim_cell(dims: usize) -> Self {
173 Self {
174 offset: 0,
175 sizes: vec![1; dims],
176 strides: vec![1; dims],
177 }
178 }
179
180 pub fn num_dim(&self) -> usize {
182 self.sizes.len()
183 }
184
185 pub fn offset(&self) -> usize {
187 self.offset
188 }
189
190 pub fn sizes(&self) -> &[usize] {
192 &self.sizes
193 }
194
195 pub fn strides(&self) -> &[usize] {
198 &self.strides
199 }
200
201 pub fn relative_ordinal_slice(&self, parent: &Self) -> Option<Self> {
219 if parent.num_dim() != self.num_dim() {
220 return None;
221 }
222
223 let parent_coordinates = parent.coordinates(self.offset()).ok()?;
225 let offset = parent.index(self.offset()).ok()?;
227 let parent_ordinal_strides = Slice::new_row_major(parent.sizes().to_vec());
229 let strides = self
230 .sizes()
231 .iter()
232 .enumerate()
233 .map(|(dimension, &extent)| -> Option<usize> {
234 if extent == 1 {
235 return Some(parent_ordinal_strides.strides()[dimension]);
236 }
237
238 let parent_stride = parent.strides()[dimension];
239 let selected_stride = self.strides()[dimension];
240 if !selected_stride.is_multiple_of(parent_stride) {
241 return None;
242 }
243
244 let step = selected_stride / parent_stride;
245 {
246 let last_coordinate = parent_coordinates[dimension].checked_add(
247 extent
248 .checked_sub(1)
249 .and_then(|extent| extent.checked_mul(step))?,
250 )?;
251
252 if last_coordinate >= parent.sizes()[dimension] {
253 return None;
254 }
255 }
256
257 parent_ordinal_strides.strides()[dimension].checked_mul(step)
258 })
259 .collect::<Option<_>>()?;
260
261 Self::new(offset, self.sizes().to_vec(), strides).ok()
262 }
263
264 pub fn is_contiguous(&self) -> bool {
265 let mut expected_stride = 1;
266 for (stride, size) in zip(self.strides.iter(), self.sizes.iter()).rev() {
267 if *stride != expected_stride {
268 return false;
269 }
270 expected_stride *= *size
271 }
272 true
273 }
274
275 pub fn at(&self, dim: usize, index: usize) -> Result<Self, SliceError> {
310 if dim >= self.sizes.len() {
311 return Err(SliceError::DimensionOutOfRange {
312 dim,
313 ndims: self.num_dim(),
314 });
315 }
316 if index >= self.sizes[dim] {
317 return Err(SliceError::IndexOutOfRange {
318 index,
319 total: self.sizes[dim],
320 });
321 }
322
323 let new_offset = self.offset + index * self.strides[dim];
324 let mut new_sizes = self.sizes.clone();
325 let mut new_strides = self.strides.clone();
326 new_sizes.remove(dim);
327 new_strides.remove(dim);
328 let slice = Slice::new(new_offset, new_sizes, new_strides)?;
329 Ok(slice)
330 }
331
332 pub fn select(
358 &self,
359 dim: usize,
360 begin: usize,
361 end: usize,
362 step: usize,
363 ) -> Result<Self, SliceError> {
364 if dim >= self.sizes.len() {
365 return Err(SliceError::IndexOutOfRange {
366 index: dim,
367 total: self.sizes.len(),
368 });
369 }
370 if begin >= self.sizes[dim] {
371 return Err(SliceError::IndexOutOfRange {
372 index: begin,
373 total: self.sizes[dim],
374 });
375 }
376 if end <= begin {
377 return Err(SliceError::EmptyRange { begin, end, step });
378 }
379
380 let mut offset = self.offset();
381 let mut sizes = self.sizes().to_vec();
382 let mut strides = self.strides().to_vec();
383
384 offset += begin * strides[dim];
385 sizes[dim] = (end - begin).div_ceil(step);
389 strides[dim] *= step;
390
391 let slice = Slice::new(offset, sizes, strides)?;
392 Ok(slice)
393 }
394
395 pub fn location(&self, coord: &[usize]) -> Result<usize, SliceError> {
397 if coord.len() != self.sizes.len() {
398 return Err(SliceError::InvalidDims {
399 expected: self.sizes.len(),
400 got: coord.len(),
401 });
402 }
403 Ok(self.offset
404 + coord
405 .iter()
406 .zip(&self.strides)
407 .map(|(pos, stride)| pos * stride)
408 .sum::<usize>())
409 }
410
411 pub fn coordinates(&self, value: usize) -> Result<Vec<usize>, SliceError> {
414 let mut pos = value
415 .checked_sub(self.offset)
416 .ok_or(SliceError::ValueNotInSlice { value })?;
417 let mut result = vec![0; self.sizes.len()];
418 let mut sorted_info: Vec<_> = self
419 .strides
420 .iter()
421 .zip(self.sizes.iter().enumerate())
422 .collect();
423 sorted_info.sort_by_key(|&(stride, _)| *stride);
424 for &(stride, (i, &size)) in sorted_info.iter().rev() {
425 let (index, new_pos) = if size > 1 {
426 (pos / stride, pos % stride)
427 } else {
428 (0, pos)
429 };
430 if index >= size {
431 return Err(SliceError::ValueNotInSlice { value });
432 }
433 result[i] = index;
434 pos = new_pos;
435 }
436 if pos != 0 {
437 return Err(SliceError::ValueNotInSlice { value });
438 }
439 Ok(result)
440 }
441
442 pub fn contains(&self, value: usize) -> bool {
444 self.coordinates(value).is_ok()
445 }
446
447 pub fn len(&self) -> usize {
449 self.sizes.iter().product()
450 }
451
452 pub fn is_empty(&self) -> bool {
453 self.len() == 0
454 }
455
456 pub fn iter(&self) -> SliceIterator {
458 SliceIterator {
459 slice: self.clone(),
460 pos: CartesianIterator::new(self.sizes.clone()),
461 }
462 }
463
464 pub fn dim_iter(&self, dims: usize) -> DimSliceIterator {
466 DimSliceIterator {
467 pos: CartesianIterator::new(self.sizes[0..dims].to_vec()),
468 }
469 }
470
471 pub fn index(&self, value: usize) -> Result<usize, SliceError> {
527 let coords = self.coordinates(value)?;
528 let mut stride = 1;
529 let mut result = 0;
530
531 for (idx, size) in coords.iter().rev().zip(self.sizes.iter().rev()) {
532 result += *idx * stride;
533 stride *= size;
534 }
535
536 Ok(result)
537 }
538
539 pub fn get(&self, index: usize) -> Result<usize, SliceError> {
590 let mut val = self.offset;
591 let mut rest = index;
592 let mut total = 1;
593 for (size, stride) in self.sizes.iter().zip(self.strides.iter()).rev() {
594 total *= size;
595 val += (rest % size) * stride;
596 rest /= size;
597 }
598 if index < total {
599 Ok(val)
600 } else {
601 Err(SliceError::IndexOutOfRange { index, total })
602 }
603 }
604
605 pub fn map<T, F>(&self, mapper: F) -> MapSlice<'_, T, F>
608 where
609 F: Fn(usize) -> T,
610 {
611 MapSlice {
612 slice: self,
613 mapper,
614 }
615 }
616
617 pub fn view(&self, new_sizes: &[usize]) -> Result<Slice, SliceError> {
646 let view_elems: usize = new_sizes.iter().product();
647 let base_elems: usize = self.sizes().iter().product();
648
649 if view_elems != base_elems {
661 return Err(SliceError::IncompatibleView {
662 reason: format!(
663 "element count mismatch: base has {}, view wants {}",
664 base_elems, view_elems
665 ),
666 });
667 }
668 if self.offset != 0 {
669 return Err(SliceError::IncompatibleView {
670 reason: format!("view requires base offset = 0, but found {}", self.offset),
671 });
672 }
673 let mut new_strides = vec![1; new_sizes.len()];
675 for i in (0..new_sizes.len().saturating_sub(1)).rev() {
676 new_strides[i] = new_strides[i + 1] * new_sizes[i + 1];
677 }
678
679 for coord in CartesianIterator::new(new_sizes.to_vec()) {
682 #[allow(clippy::identity_op)]
683 let offset_in_view = 0 + coord
684 .iter()
685 .zip(&new_strides)
686 .map(|(i, s)| i * s)
687 .sum::<usize>();
688
689 if self.coordinates(offset_in_view).is_err() {
690 return Err(SliceError::IncompatibleView {
691 reason: format!("offset {} not reachable in base", offset_in_view),
692 });
693 }
694 }
695
696 Ok(Slice {
697 offset: 0,
698 sizes: new_sizes.to_vec(),
699 strides: new_strides,
700 })
701 }
702
703 pub fn subview(&self, starts: &[usize], lens: &[usize]) -> Result<Slice, SliceError> {
705 if starts.len() != self.num_dim() || lens.len() != self.num_dim() {
706 return Err(SliceError::InvalidDims {
707 expected: self.num_dim(),
708 got: starts.len().max(lens.len()),
709 });
710 }
711
712 for (d, (&start, &len)) in starts.iter().zip(lens).enumerate() {
713 if start + len > self.sizes[d] {
714 return Err(SliceError::IndexOutOfRange {
715 index: start + len,
716 total: self.sizes[d],
717 });
718 }
719 }
720
721 let offset = self.location(starts)?;
722 Ok(Slice {
723 offset,
724 sizes: lens.to_vec(),
725 strides: self.strides.clone(),
726 })
727 }
728
729 pub fn enforce_embedding<'a>(&'a self, other: &'_ Slice) -> Result<&'a Slice, SliceError> {
750 self.iter()
751 .try_for_each(|loc| other.coordinates(loc).map(|_| ()))?;
752 Ok(self)
753 }
754}
755
756impl std::fmt::Display for Slice {
757 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
758 write!(f, "{:?}", self)
759 }
760}
761
762impl IntoIterator for &Slice {
763 type Item = usize;
764 type IntoIter = SliceIterator;
765 fn into_iter(self) -> Self::IntoIter {
766 self.iter()
767 }
768}
769
770pub struct SliceIterator {
771 pub(crate) slice: Slice,
772 pos: CartesianIterator,
773}
774
775impl Iterator for SliceIterator {
776 type Item = usize;
777
778 fn next(&mut self) -> Option<Self::Item> {
779 match self.pos.next() {
780 None => None,
781 Some(pos) => Some(self.slice.location(&pos).unwrap()),
782 }
783 }
784}
785
786pub struct DimSliceIterator {
795 pos: CartesianIterator,
796}
797
798impl Iterator for DimSliceIterator {
799 type Item = Vec<usize>;
800
801 fn next(&mut self) -> Option<Self::Item> {
802 self.pos.next()
803 }
804}
805
806pub(crate) struct CartesianIterator {
820 dims: Vec<usize>,
821 index: usize,
822}
823
824impl CartesianIterator {
825 pub(crate) fn new(dims: Vec<usize>) -> Self {
826 CartesianIterator { dims, index: 0 }
827 }
828}
829
830impl Iterator for CartesianIterator {
831 type Item = Vec<usize>;
832
833 fn next(&mut self) -> Option<Self::Item> {
834 if self.index >= self.dims.iter().product::<usize>() {
835 return None;
836 }
837
838 let mut result: Vec<usize> = vec![0; self.dims.len()];
839 let mut rest = self.index;
840 for (i, dim) in self.dims.iter().enumerate().rev() {
841 result[i] = rest % dim;
842 rest /= dim;
843 }
844 self.index += 1;
845 Some(result)
846 }
847}
848
849pub struct MapSlice<'a, T, F>
852where
853 F: Fn(usize) -> T,
854{
855 slice: &'a Slice,
856 mapper: F,
857}
858
859impl<T, F> MapSlice<'_, T, F>
860where
861 F: Fn(usize) -> T,
862{
863 pub fn sizes(&self) -> &[usize] {
865 &self.slice.sizes
866 }
867
868 pub fn strides(&self) -> &[usize] {
870 &self.slice.strides
871 }
872
873 pub fn location(&self, coord: &[usize]) -> Result<T, SliceError> {
875 self.slice.location(coord).map(&self.mapper)
876 }
877
878 pub fn get(&self, index: usize) -> Result<T, SliceError> {
880 self.slice.get(index).map(&self.mapper)
881 }
882
883 pub fn len(&self) -> usize {
885 self.slice.len()
886 }
887
888 pub fn is_empty(&self) -> bool {
890 self.slice.is_empty()
891 }
892}
893
894#[cfg(test)]
895mod tests {
896 use std::assert_matches;
897 use std::vec;
898
899 use super::*;
900
901 #[test]
902 fn test_cartesian_iterator() {
903 let dims = vec![2, 2, 2];
904 let iter = CartesianIterator::new(dims);
905 let products: Vec<Vec<usize>> = iter.collect();
906 assert_eq!(
907 products,
908 vec![
909 vec![0, 0, 0],
910 vec![0, 0, 1],
911 vec![0, 1, 0],
912 vec![0, 1, 1],
913 vec![1, 0, 0],
914 vec![1, 0, 1],
915 vec![1, 1, 0],
916 vec![1, 1, 1],
917 ]
918 );
919 }
920
921 #[test]
922 #[allow(clippy::explicit_counter_loop)]
923 fn test_slice() {
924 let s = Slice::new(0, vec![2, 3], vec![3, 1]).unwrap();
925 for i in 0..4 {
926 assert_eq!(s.get(i).unwrap(), i);
927 }
928
929 {
930 let mut current = 0;
932 for index in &s {
933 assert_eq!(index, current);
934 current += 1;
935 }
936 }
937
938 let s = Slice::new(0, vec![3, 4, 5], vec![20, 5, 1]).unwrap();
939 assert_eq!(s.get(3 * 4 + 1).unwrap(), 13);
940
941 let s = Slice::new(0, vec![2, 2, 2], vec![4, 32, 1]).unwrap();
942 assert_eq!(s.get(0).unwrap(), 0);
943 assert_eq!(s.get(1).unwrap(), 1);
944 assert_eq!(s.get(2).unwrap(), 32);
945 assert_eq!(s.get(3).unwrap(), 33);
946 assert_eq!(s.get(4).unwrap(), 4);
947 assert_eq!(s.get(5).unwrap(), 5);
948 assert_eq!(s.get(6).unwrap(), 36);
949 assert_eq!(s.get(7).unwrap(), 37);
950
951 let s = Slice::new(0, vec![2, 2, 2], vec![32, 4, 1]).unwrap();
952 assert_eq!(s.get(0).unwrap(), 0);
953 assert_eq!(s.get(1).unwrap(), 1);
954 assert_eq!(s.get(2).unwrap(), 4);
955 assert_eq!(s.get(4).unwrap(), 32);
956 }
957
958 #[test]
959 fn test_slice_iter() {
960 let s = Slice::new(0, vec![2, 3], vec![3, 1]).unwrap();
961 assert!(s.iter().eq(0..6));
962
963 let s = Slice::new(10, vec![10, 2], vec![10, 5]).unwrap();
964 assert!(s.iter().eq((10..=105).step_by(5)));
965
966 assert!(s.iter().eq((0..s.len()).map(|i| s.get(i).unwrap())));
968 }
969
970 #[test]
971 fn test_dim_slice_iter() {
972 let s = Slice::new(0, vec![2, 3], vec![3, 1]).unwrap();
973 let sub_dims: Vec<_> = s.dim_iter(1).collect();
974 assert_eq!(sub_dims, vec![vec![0], vec![1]]);
975 }
976
977 #[test]
978 fn test_slice_coordinates() {
979 let s = Slice::new(0, vec![2, 3], vec![3, 1]).unwrap();
980 assert_eq!(s.coordinates(0).unwrap(), vec![0, 0]);
981 assert_eq!(s.coordinates(3).unwrap(), vec![1, 0]);
982 assert_matches!(
983 s.coordinates(6),
984 Err(SliceError::ValueNotInSlice { value: 6 })
985 );
986
987 let s = Slice::new(10, vec![2, 3], vec![3, 1]).unwrap();
988 assert_matches!(
989 s.coordinates(6),
990 Err(SliceError::ValueNotInSlice { value: 6 })
991 );
992 assert_eq!(s.coordinates(10).unwrap(), vec![0, 0]);
993 assert_eq!(s.coordinates(13).unwrap(), vec![1, 0]);
994
995 let s = Slice::new(0, vec![2, 1, 1], vec![1, 1, 1]).unwrap();
996 assert_eq!(s.coordinates(1).unwrap(), vec![1, 0, 0]);
997 }
998
999 #[test]
1000 fn test_slice_index() {
1001 let s = Slice::new(0, vec![2, 3], vec![3, 1]).unwrap();
1002 assert_eq!(s.index(3).unwrap(), 3);
1003 assert!(s.index(14).is_err());
1004
1005 let s = Slice::new(0, vec![2, 2], vec![4, 2]).unwrap();
1006 assert_eq!(s.index(2).unwrap(), 1);
1007 }
1008
1009 #[test]
1010 fn relative_ordinal_slice_maps_selected_ranks_into_parent_ordinals() {
1011 let parent = Slice::new(100, vec![4, 4], vec![8, 2]).expect("parent should be valid");
1012 let selected = Slice::new(110, vec![2, 2], vec![16, 2]).expect("selection should be valid");
1013
1014 assert_eq!(
1015 selected
1016 .relative_ordinal_slice(&parent)
1017 .expect("selection should map into parent ordinals"),
1018 Slice::new(5, vec![2, 2], vec![8, 1]).expect("result should be valid")
1019 );
1020 }
1021
1022 #[test]
1023 fn relative_ordinal_slice_rejects_selection_that_wraps_parent_dimension() {
1024 let parent = Slice::new_row_major(vec![2, 4]);
1025 let selected = Slice::new(1, vec![1, 4], vec![4, 1]).expect("selection should be valid");
1026
1027 assert!(selected.relative_ordinal_slice(&parent).is_none());
1028 }
1029
1030 #[test]
1031 fn test_slice_map() {
1032 let s = Slice::new(0, vec![2, 3], vec![3, 1]).unwrap();
1033 let m = s.map(|i| i * 2);
1034 assert_eq!(m.get(0).unwrap(), 0);
1035 assert_eq!(m.get(3).unwrap(), 6);
1036 assert_eq!(m.get(5).unwrap(), 10);
1037 }
1038
1039 #[test]
1040 fn test_slice_size_one() {
1041 let s = Slice::new(0, vec![1, 1], vec![1, 1]).unwrap();
1042 assert_eq!(s.get(0).unwrap(), 0);
1043 }
1044
1045 #[test]
1046 fn test_row_major() {
1047 let s = Slice::new_row_major(vec![4, 4, 4]);
1048 assert_eq!(s.offset(), 0);
1049 assert_eq!(s.sizes(), &[4, 4, 4]);
1050 assert_eq!(s.strides(), &[16, 4, 1]);
1051 }
1052
1053 #[test]
1054 fn test_slice_view_smoke() {
1055 use crate::Slice;
1056
1057 let base = Slice::new_row_major([2, 3, 4]);
1058
1059 let view = base.view(&[6, 4]).unwrap();
1061 assert_eq!(view.sizes(), &[6, 4]);
1062 assert_eq!(view.offset(), 0);
1063 assert_eq!(view.strides(), &[4, 1]);
1064 assert_eq!(
1065 view.location(&[5, 3]).unwrap(),
1066 base.location(&[1, 2, 3]).unwrap()
1067 );
1068
1069 let view = base.view(&[2, 3, 4]).unwrap();
1071 assert_eq!(view.sizes(), base.sizes());
1072 assert_eq!(view.strides(), base.strides());
1073
1074 let err = base.view(&[5, 4]);
1076 assert!(err.is_err());
1077
1078 let selected = Slice::new(1, vec![2, 3], vec![6, 1]).unwrap(); let err = selected.view(&[3, 2]);
1081 assert!(err.is_err());
1082
1083 let flat = base.view(&[24]).unwrap();
1085 assert_eq!(flat.sizes(), &[24]);
1086 assert_eq!(flat.strides(), &[1]);
1087 assert_eq!(
1088 flat.location(&[23]).unwrap(),
1089 base.location(&[1, 2, 3]).unwrap()
1090 );
1091 }
1092
1093 #[test]
1094 fn test_view_of_view_when_dense() {
1095 let base = Slice::new_row_major([2, 3, 4]);
1097
1098 let flat = base.view(&[24]).unwrap();
1100 assert_eq!(flat.sizes(), &[24]);
1101 assert_eq!(flat.strides(), &[1]);
1102 assert_eq!(flat.offset(), 0); let reshaped = flat.view(&[6, 4]).unwrap();
1106 assert_eq!(reshaped.sizes(), &[6, 4]);
1107 assert_eq!(reshaped.strides(), &[4, 1]);
1108 assert_eq!(reshaped.offset(), 0);
1109
1110 assert_eq!(
1112 reshaped.location(&[5, 3]).unwrap(),
1113 base.location(&[1, 2, 3]).unwrap()
1114 );
1115 }
1116
1117 #[test]
1118 fn test_at_1d_to_0d() {
1119 let slice = Slice::new_row_major(vec![5]);
1120 assert_eq!(slice.num_dim(), 1);
1121 assert_eq!(slice.sizes(), &[5]);
1122 assert_eq!(slice.strides(), &[1]);
1123
1124 let result = slice.at(0, 3).unwrap();
1125 assert_eq!(result.num_dim(), 0);
1126 assert_eq!(result.sizes(), &[] as &[usize]);
1127 assert_eq!(result.strides(), &[] as &[usize]);
1128 assert_eq!(result.offset(), 3);
1129 assert_eq!(result.location(&[] as &[usize]).unwrap(), 3);
1130 }
1131
1132 #[test]
1133 fn test_at_2d_to_1d() {
1134 let slice = Slice::new_row_major(vec![3, 4]);
1135 assert_eq!(slice.num_dim(), 2);
1136 assert_eq!(slice.sizes(), &[3, 4]);
1137 assert_eq!(slice.strides(), &[4, 1]);
1138
1139 let result = slice.at(0, 1).unwrap();
1140 assert_eq!(result.num_dim(), 1);
1141 assert_eq!(result.sizes(), &[4]);
1142 assert_eq!(result.strides(), &[1]);
1143 assert_eq!(result.offset(), 4);
1144 }
1145
1146 #[test]
1147 fn test_at_3d_to_2d() {
1148 let slice = Slice::new_row_major(vec![2, 3, 4]);
1149 assert_eq!(slice.num_dim(), 3);
1150 assert_eq!(slice.sizes(), &[2, 3, 4]);
1151 assert_eq!(slice.strides(), &[12, 4, 1]);
1152
1153 let result = slice.at(0, 1).unwrap();
1154 assert_eq!(result.num_dim(), 2);
1155 assert_eq!(result.sizes(), &[3, 4]);
1156 assert_eq!(result.strides(), &[4, 1]);
1157 assert_eq!(result.offset(), 12);
1158 }
1159
1160 #[test]
1161 fn test_get_index_inverse_relationship() {
1162 let m = Slice::new_row_major([3, 3]);
1168 assert_eq!(m.offset, 0);
1169 assert_eq!(m.sizes(), &[3, 3]);
1170 assert_eq!(m.strides(), &[3, 1]);
1171
1172 for loc in m.iter() {
1174 assert_eq!(m.index(loc).unwrap(), loc);
1176 assert_eq!(m.get(m.index(loc).unwrap()).unwrap(), loc);
1178 }
1179
1180 let c = m.select(1, 1, 2, 1).unwrap();
1185 assert_eq!(c.sizes(), &[3, 1]);
1186 assert_eq!(c.strides(), &[3, 1]);
1187
1188 for loc in c.iter() {
1190 assert_ne!(c.index(loc).unwrap(), loc);
1192 assert_eq!(c.get(c.index(loc).unwrap()).unwrap(), loc);
1194 }
1195 }
1196
1197 #[test]
1198 fn embedding_succeeds_for_contained_view() {
1199 let base = Slice::new(0, vec![4, 4], vec![4, 1]).unwrap(); let view = Slice::new(5, vec![2, 2], vec![4, 1]).unwrap(); assert!(view.enforce_embedding(&base).is_ok());
1203 }
1204
1205 #[test]
1206 fn embedding_fails_for_out_of_bounds_view() {
1207 let base = Slice::new(0, vec![4, 4], vec![4, 1]).unwrap(); let view = Slice::new(14, vec![2, 2], vec![4, 1]).unwrap(); assert!(view.enforce_embedding(&base).is_err());
1211 }
1212}