1use super::memmap::MemoryMappedArray;
8use crate::error::{CoreError, CoreResult, ErrorContext};
9use ::ndarray::{ArrayBase, Dimension, IxDyn, SliceInfo, SliceInfoElem};
10use std::marker::PhantomData;
11use std::ops::RangeBounds;
12
13pub struct MemoryMappedSlice<A, D>
19where
20 A: Clone + Copy + 'static + Send + Sync,
21 D: Dimension,
22{
23 source: MemoryMappedArray<A>,
25
26 slice_info: SliceInfo<Vec<SliceInfoElem>, D, D>,
28
29 phantom: PhantomData<D>,
31}
32
33impl<A, D> MemoryMappedSlice<A, D>
34where
35 A: Clone + Copy + 'static + Send + Sync,
36 D: Dimension,
37{
38 pub fn new(
40 source: MemoryMappedArray<A>,
41 slice_info: SliceInfo<Vec<SliceInfoElem>, D, D>,
42 ) -> Self {
43 Self {
44 source,
45 slice_info,
46 phantom: PhantomData,
47 }
48 }
49
50 pub fn shape(&self) -> D {
55 self.calculate_slicedshape().unwrap_or_default()
58 }
59
60 pub fn calculatedshape(&self) -> CoreResult<D> {
64 self.calculate_slicedshape()
65 }
66
67 fn calculate_slicedshape(&self) -> CoreResult<D> {
69 let sourceshape = &self.source.shape;
70 let slice_elements = self.slice_info.as_ref();
71
72 let mut result_dims = Vec::new();
73
74 for (dim_idx, &dim_size) in sourceshape.iter().enumerate() {
76 if dim_idx < slice_elements.len() {
77 match &slice_elements[dim_idx] {
78 SliceInfoElem::Slice { start, end, step } => {
79 let start_idx = if *start < 0 {
81 (dim_size as isize + start).max(0) as usize
82 } else {
83 (*start as usize).min(dim_size)
84 };
85
86 let end_idx = if let Some(e) = end {
87 if *e < 0 {
88 (dim_size as isize + e).max(0) as usize
89 } else {
90 (*e as usize).min(dim_size)
91 }
92 } else {
93 dim_size
94 };
95
96 let step_size = step.max(&1).unsigned_abs();
97 let slice_size = if end_idx > start_idx {
98 (end_idx - start_idx).div_ceil(step_size)
99 } else {
100 0
101 };
102
103 result_dims.push(slice_size);
104 }
105 SliceInfoElem::Index(_) => {
106 }
109 _ => {
110 result_dims.push(dim_size);
112 }
113 }
114 } else {
115 result_dims.push(dim_size);
117 }
118 }
119
120 Self::convert_dims_to_target_type(&result_dims)
122 }
123
124 fn convert_dims_to_target_type(resultdims: &[usize]) -> CoreResult<D> {
126 let source_ndim = resultdims.len();
127 let target_ndim = D::NDIM;
128
129 if target_ndim.is_none() {
131 let dyn_dim = IxDyn(resultdims);
133 let converted_dim = unsafe { std::mem::transmute_copy(&dyn_dim) };
136 return Ok(converted_dim);
137 }
138
139 let target_ndim = target_ndim.expect("Operation failed");
140
141 if source_ndim == target_ndim {
143 match target_ndim {
144 1 => {
145 if resultdims.len() == 1 {
146 let dim1 = crate::ndarray::Ix1(resultdims[0]);
147 let converted_dim = unsafe { std::mem::transmute_copy(&dim1) };
148 return Ok(converted_dim);
149 }
150 }
151 2 => {
152 if resultdims.len() == 2 {
153 let dim2 = crate::ndarray::Ix2(resultdims[0], resultdims[1]);
154 let converted_dim = unsafe { std::mem::transmute_copy(&dim2) };
155 return Ok(converted_dim);
156 }
157 }
158 3 => {
159 if resultdims.len() == 3 {
160 let dim3 = crate::ndarray::Ix3(resultdims[0], resultdims[1], resultdims[2]);
161 let converted_dim = unsafe { std::mem::transmute_copy(&dim3) };
162 return Ok(converted_dim);
163 }
164 }
165 4 => {
166 if resultdims.len() == 4 {
167 let dim4 = crate::ndarray::Ix4(
168 resultdims[0],
169 resultdims[1],
170 resultdims[2],
171 resultdims[3],
172 );
173 let converted_dim = unsafe { std::mem::transmute_copy(&dim4) };
174 return Ok(converted_dim);
175 }
176 }
177 _ => {}
178 }
179
180 return Err(CoreError::DimensionError(ErrorContext::new(format!(
181 "Cannot convert {source_ndim} dimensions to target dimension type"
182 ))));
183 }
184
185 if source_ndim < target_ndim {
187 let mut expanded_dims = resultdims.to_vec();
189 expanded_dims.resize(target_ndim, 1);
190
191 match target_ndim {
192 1 => {
193 if expanded_dims.len() == 1 {
194 let dim1 = crate::ndarray::Ix1(expanded_dims[0]);
195 let converted_dim = unsafe { std::mem::transmute_copy(&dim1) };
196 Ok(converted_dim)
197 } else {
198 Err(CoreError::DimensionError(ErrorContext::new(format!(
199 "Cannot expand to 1D from dimensions: {expanded_dims:?}"
200 ))))
201 }
202 }
203 2 => {
204 if expanded_dims.len() == 2 {
205 let dim2 = crate::ndarray::Ix2(expanded_dims[0], expanded_dims[1]);
206 let converted_dim = unsafe { std::mem::transmute_copy(&dim2) };
207 Ok(converted_dim)
208 } else {
209 Err(CoreError::DimensionError(ErrorContext::new(format!(
210 "Cannot expand to 2D from dimensions: {expanded_dims:?}"
211 ))))
212 }
213 }
214 3 => {
215 if expanded_dims.len() == 3 {
216 let dim3 = crate::ndarray::Ix3(
217 expanded_dims[0],
218 expanded_dims[1],
219 expanded_dims[2],
220 );
221 let converted_dim = unsafe { std::mem::transmute_copy(&dim3) };
222 Ok(converted_dim)
223 } else {
224 Err(CoreError::DimensionError(ErrorContext::new(format!(
225 "Cannot expand to 3D from dimensions: {expanded_dims:?}"
226 ))))
227 }
228 }
229 4 => {
230 if expanded_dims.len() == 4 {
231 let dim4 = crate::ndarray::Ix4(
232 expanded_dims[0],
233 expanded_dims[1],
234 expanded_dims[2],
235 expanded_dims[3],
236 );
237 let converted_dim = unsafe { std::mem::transmute_copy(&dim4) };
238 Ok(converted_dim)
239 } else {
240 Err(CoreError::DimensionError(ErrorContext::new(format!(
241 "Cannot expand to 4D from dimensions: {expanded_dims:?}"
242 ))))
243 }
244 }
245 _ => Err(CoreError::DimensionError(ErrorContext::new(format!(
246 "Unsupported target dimension: {target_ndim}"
247 )))),
248 }
249 } else {
250 let mut squeezed_dims = Vec::new();
252 let mut removed_count = 0;
253 let dims_to_remove = source_ndim - target_ndim;
254
255 for &dim_size in resultdims {
256 if dim_size == 1 && removed_count < dims_to_remove {
257 removed_count += 1;
258 } else {
259 squeezed_dims.push(dim_size);
260 }
261 }
262
263 if squeezed_dims.len() != target_ndim {
264 return Err(CoreError::DimensionError(ErrorContext::new(format!(
265 "Sliced shape has {} dimensions but target type expects {} dimensions. \
266 Sliced shape: {:?}, source shape: {:?}, available singleton dimensions: {}",
267 source_ndim,
268 target_ndim,
269 resultdims,
270 resultdims,
271 resultdims.iter().filter(|&&x| x == 1).count()
272 ))));
273 }
274
275 match target_ndim {
276 1 => {
277 if squeezed_dims.len() == 1 {
278 let dim1 = crate::ndarray::Ix1(squeezed_dims[0]);
279 let converted_dim = unsafe { std::mem::transmute_copy(&dim1) };
280 Ok(converted_dim)
281 } else {
282 Err(CoreError::DimensionError(ErrorContext::new(format!(
283 "Cannot squeeze to 1D from dimensions: {squeezed_dims:?}"
284 ))))
285 }
286 }
287 2 => {
288 if squeezed_dims.len() == 2 {
289 let dim2 = crate::ndarray::Ix2(squeezed_dims[0], squeezed_dims[1]);
290 let converted_dim = unsafe { std::mem::transmute_copy(&dim2) };
291 Ok(converted_dim)
292 } else {
293 Err(CoreError::DimensionError(ErrorContext::new(format!(
294 "Cannot squeeze to 2D from dimensions: {squeezed_dims:?}"
295 ))))
296 }
297 }
298 3 => {
299 if squeezed_dims.len() == 3 {
300 let dim3 = crate::ndarray::Ix3(
301 squeezed_dims[0],
302 squeezed_dims[1],
303 squeezed_dims[2],
304 );
305 let converted_dim = unsafe { std::mem::transmute_copy(&dim3) };
306 Ok(converted_dim)
307 } else {
308 Err(CoreError::DimensionError(ErrorContext::new(format!(
309 "Cannot squeeze to 3D from dimensions: {squeezed_dims:?}"
310 ))))
311 }
312 }
313 4 => {
314 if squeezed_dims.len() == 4 {
315 let dim4 = crate::ndarray::Ix4(
316 squeezed_dims[0],
317 squeezed_dims[1],
318 squeezed_dims[2],
319 squeezed_dims[3],
320 );
321 let converted_dim = unsafe { std::mem::transmute_copy(&dim4) };
322 Ok(converted_dim)
323 } else {
324 Err(CoreError::DimensionError(ErrorContext::new(format!(
325 "Cannot squeeze to 4D from dimensions: {squeezed_dims:?}"
326 ))))
327 }
328 }
329 _ => Err(CoreError::DimensionError(ErrorContext::new(format!(
330 "Unsupported target dimension: {target_ndim}"
331 )))),
332 }
333 }
334 }
335
336 pub const fn source(&self) -> &MemoryMappedArray<A> {
338 &self.source
339 }
340
341 pub const fn slice_info(&self) -> &SliceInfo<Vec<SliceInfoElem>, D, D> {
343 &self.slice_info
344 }
345
346 fn safe_dimensionality_conversion(
348 array: crate::ndarray::ArrayBase<crate::ndarray::OwnedRepr<A>, crate::ndarray::IxDyn>,
349 context: &str,
350 ) -> CoreResult<ArrayBase<crate::ndarray::OwnedRepr<A>, D>> {
351 let sourceshape = array.shape().to_vec();
352 let source_ndim = sourceshape.len();
353 let target_ndim = D::NDIM;
354
355 if target_ndim.is_none() {
357 return array.into_dimensionality::<D>().map_err(|_| {
358 CoreError::DimensionError(ErrorContext::new(format!(
359 "Failed to convert {context} array to dynamic dimension type. Source shape: {sourceshape:?}"
360 )))
361 });
362 }
363
364 let target_ndim = target_ndim.expect("Operation failed");
365
366 if source_ndim == target_ndim {
368 return array.into_dimensionality::<D>().map_err(|_| {
369 CoreError::DimensionError(ErrorContext::new(format!(
370 "Dimension conversion failed for {} array despite matching dimensions ({} -> {}). Source shape: {:?}, target dimension type: {}",
371 context, source_ndim, target_ndim, sourceshape, std::any::type_name::<D>()
372 )))
373 });
374 }
375
376 match source_ndim.cmp(&target_ndim) {
378 std::cmp::Ordering::Less => {
379 Self::try_expand_dimensions(array, context, source_ndim, target_ndim)
381 }
382 std::cmp::Ordering::Greater => {
383 Self::try_squeeze_dimensions(array, context, source_ndim, target_ndim)
385 }
386 std::cmp::Ordering::Equal => {
387 array.into_dimensionality::<D>().map_err(|_| {
389 CoreError::DimensionError(ErrorContext::new(format!(
390 "Unexpected dimension conversion failure for {context} array with matching dimensions. Source shape: {sourceshape:?}"
391 )))
392 })
393 }
394 }
395 }
396
397 fn try_expand_dimensions(
399 array: crate::ndarray::ArrayBase<crate::ndarray::OwnedRepr<A>, crate::ndarray::IxDyn>,
400 context: &str,
401 source_dims: usize,
402 target_dims: usize,
403 ) -> CoreResult<ArrayBase<crate::ndarray::OwnedRepr<A>, D>> {
404 let sourceshape = array.shape().to_vec();
405 let dims_to_add = target_dims - source_dims;
406
407 if dims_to_add == 0 {
408 return array.into_dimensionality::<D>().map_err(|_| {
409 CoreError::DimensionError(ErrorContext::new(format!(
410 "Failed to convert {context} array despite equal dimensions"
411 )))
412 });
413 }
414
415 let mut expandedshape = sourceshape.clone();
417 expandedshape.resize(source_dims + dims_to_add, 1);
418
419 match array
421 .clone()
422 .into_shape_with_order(crate::ndarray::IxDyn(&expandedshape))
423 {
424 Ok(reshaped) => reshaped.into_dimensionality::<D>().map_err(|_| {
425 CoreError::DimensionError(ErrorContext::new(format!(
426 "Failed to convert expanded {context} array to target dimension type"
427 )))
428 }),
429 Err(_) => {
430 let mut altshape = vec![1; dims_to_add];
432 altshape.extend_from_slice(&sourceshape);
433
434 array
435 .into_shape_with_order(crate::ndarray::IxDyn(&altshape))
436 .map_err(|_| {
437 CoreError::DimensionError(ErrorContext::new(format!(
438 "Cannot reshape {context} array from shape {sourceshape:?} to any expanded shape"
439 )))
440 })?
441 .into_dimensionality::<D>()
442 .map_err(|_| {
443 CoreError::DimensionError(ErrorContext::new(format!(
444 "Cannot expand {context} array from {source_dims} to {target_dims} dimensions"
445 )))
446 })
447 }
448 }
449 }
450
451 fn try_squeeze_dimensions(
453 array: crate::ndarray::ArrayBase<crate::ndarray::OwnedRepr<A>, crate::ndarray::IxDyn>,
454 context: &str,
455 source_dims: usize,
456 target_dims: usize,
457 ) -> CoreResult<ArrayBase<crate::ndarray::OwnedRepr<A>, D>> {
458 let sourceshape = array.shape().to_vec();
459
460 let mut squeezedshape = Vec::new();
462 let mut removed_dims = 0;
463 let dims_to_remove = source_dims - target_dims;
464
465 for &dim_size in &sourceshape {
466 if dim_size == 1 && removed_dims < dims_to_remove {
467 removed_dims += 1;
469 } else {
470 squeezedshape.push(dim_size);
471 }
472 }
473
474 if squeezedshape.len() != target_dims {
475 return Err(CoreError::DimensionError(ErrorContext::new(format!(
476 "Cannot squeeze {} array from {} to {} dimensions. Source shape: {:?}, only {} singleton dimensions available",
477 context, source_dims, target_dims, sourceshape,
478 sourceshape.iter().filter(|&&x| x == 1).count()
479 ))));
480 }
481
482 array
484 .into_shape_with_order(crate::ndarray::IxDyn(&squeezedshape))
485 .map_err(|_| {
486 CoreError::DimensionError(ErrorContext::new(format!(
487 "Cannot reshape {context} array from shape {sourceshape:?} to squeezed shape {squeezedshape:?}"
488 )))
489 })?
490 .into_dimensionality::<D>()
491 .map_err(|_| {
492 CoreError::DimensionError(ErrorContext::new(format!(
493 "Cannot convert squeezed {context} array from {source_dims} to {target_dims} dimensions"
494 )))
495 })
496 }
497
498 pub fn load(&self) -> CoreResult<ArrayBase<crate::ndarray::OwnedRepr<A>, D>> {
503 let data_slice = self.source.as_slice();
505
506 self.load_slice_generic(data_slice)
508 }
509
510 fn load_slice_generic(
512 &self,
513 data_slice: &[A],
514 ) -> CoreResult<ArrayBase<crate::ndarray::OwnedRepr<A>, D>> {
515 use ::ndarray::IxDyn;
516
517 self.validate_dimension_compatibility()?;
519
520 let sourceshape = IxDyn(&self.source.shape);
522 let source_array =
523 crate::ndarray::ArrayView::from_shape(sourceshape, data_slice).map_err(|e| {
524 CoreError::ShapeError(ErrorContext::new(format!(
525 "Failed to create array view from source shape {:?}: {}",
526 self.source.shape, e
527 )))
528 })?;
529
530 let slice_elements = self.slice_info.as_ref();
532 let sliced = self.apply_slice_safely_owned(source_array, slice_elements)?;
533
534 Self::safe_dimensionality_conversion(sliced, "sliced array")
536 }
537
538 fn validate_dimension_compatibility(&self) -> CoreResult<()> {
540 let source_ndim = self.source.shape.len();
541 let slice_elements = self.slice_info.as_ref();
542
543 let mut resulting_dims = 0;
545 let mut index_operations = 0;
546
547 for (i, elem) in slice_elements.iter().enumerate() {
549 if i >= source_ndim {
550 resulting_dims += 1;
553 } else {
554 match elem {
555 SliceInfoElem::Index(_) => {
556 index_operations += 1;
558 }
559 SliceInfoElem::Slice { .. } => {
560 resulting_dims += 1;
562 }
563 _ => {
566 resulting_dims += 1;
568 }
569 }
570 }
571 }
572
573 if slice_elements.len() < source_ndim {
575 resulting_dims += source_ndim - slice_elements.len();
576 }
577
578 if let Some(target_ndim) = D::NDIM {
580 if resulting_dims != target_ndim {
581 return Err(CoreError::DimensionError(ErrorContext::new(format!(
582 "Dimension mismatch: slice operation will result in {}D array, but target type expects {}D. Source shape: {:?} ({}D), slice elements: {}, index operations: {}",
583 resulting_dims, target_ndim, self.source.shape, source_ndim,
584 slice_elements.len(), index_operations
585 ))));
586 }
587 }
588
589 Ok(())
590 }
591
592 fn apply_slice_safely_owned(
594 &self,
595 source_array: crate::ndarray::ArrayView<A, IxDyn>,
596 slice_elements: &[SliceInfoElem],
597 ) -> CoreResult<crate::ndarray::Array<A, IxDyn>> {
598 if slice_elements.is_empty() {
599 return Ok(source_array.to_owned());
600 }
601
602 let sliced = source_array.slice_each_axis(|ax| {
604 if ax.axis.index() < slice_elements.len() {
605 match &slice_elements[ax.axis.index()] {
606 SliceInfoElem::Slice { start, end, step } => {
607 let dim_size = ax.len as isize;
609 let safe_start = self.handle_negative_index(*start, dim_size);
610 let safe_end = if let Some(e) = end {
611 self.handle_negative_index(*e, dim_size)
612 } else {
613 dim_size
614 };
615
616 let clamped_start = safe_start.max(0).min(dim_size) as usize;
618 let clamped_end = safe_end.max(0).min(dim_size) as usize;
619
620 let safe_step = step.max(&1).unsigned_abs();
622
623 crate::ndarray::Slice::new(
624 clamped_start as isize,
625 Some(clamped_end as isize),
626 safe_step as isize,
627 )
628 }
629 SliceInfoElem::Index(idx) => {
630 let dim_size = ax.len as isize;
631 let safe_idx = self.handle_negative_index(*idx, dim_size);
632 let clamped_idx = safe_idx.max(0).min(dim_size - 1) as usize;
633 crate::ndarray::Slice::new(
634 clamped_idx as isize,
635 Some((clamped_idx + 1) as isize),
636 1,
637 )
638 }
639 _ => crate::ndarray::Slice::new(0, None, 1),
640 }
641 } else {
642 crate::ndarray::Slice::new(0, None, 1)
643 }
644 });
645
646 Ok(sliced.to_owned())
647 }
648
649 fn handle_negative_index(&self, index: isize, dimsize: isize) -> isize {
651 if index < 0 {
652 dimsize + index
653 } else {
654 index
655 }
656 }
657}
658
659pub trait MemoryMappedSlicing<A: Clone + Copy + 'static + Send + Sync> {
661 fn slice<I, E>(&self, sliceinfo: I) -> CoreResult<MemoryMappedSlice<A, E>>
663 where
664 I: crate::ndarray::SliceArg<E>,
665 E: Dimension;
666
667 fn slice_1d(
669 &self,
670 range: impl RangeBounds<usize>,
671 ) -> CoreResult<MemoryMappedSlice<A, crate::ndarray::Ix1>>;
672
673 fn slice_2d(
675 &self,
676 row_range: impl RangeBounds<usize>,
677 col_range: impl RangeBounds<usize>,
678 ) -> CoreResult<MemoryMappedSlice<A, crate::ndarray::Ix2>>;
679}
680
681impl<A: Clone + Copy + 'static + Send + Sync> MemoryMappedSlicing<A> for MemoryMappedArray<A> {
682 fn slice<I, E>(&self, sliceinfo: I) -> CoreResult<MemoryMappedSlice<A, E>>
683 where
684 I: crate::ndarray::SliceArg<E>,
685 E: Dimension,
686 {
687 let slicedshape = self.shape.clone();
694
695 let mut elems = Vec::new();
698 for &dim_size in &slicedshape {
699 elems.push(SliceInfoElem::Slice {
700 start: 0,
701 end: Some(dim_size as isize),
702 step: 1,
703 });
704 }
705
706 let slice_info = unsafe { SliceInfo::new(elems) }
707 .map_err(|_| CoreError::ShapeError(ErrorContext::new("Failed to create slice info")))?;
708
709 let source = MemoryMappedArray::new::<crate::ndarray::OwnedRepr<A>, E>(
712 None,
713 &self.file_path,
714 self.mode,
715 self.offset,
716 )?;
717
718 Ok(MemoryMappedSlice::new(source, slice_info))
719 }
720
721 fn slice_1d(
722 &self,
723 range: impl RangeBounds<usize>,
724 ) -> CoreResult<MemoryMappedSlice<A, crate::ndarray::Ix1>> {
725 let start = match range.start_bound() {
727 std::ops::Bound::Included(&n) => n,
728 std::ops::Bound::Excluded(&n) => n + 1,
729 std::ops::Bound::Unbounded => 0,
730 };
731
732 let end = match range.end_bound() {
733 std::ops::Bound::Included(&n) => n + 1,
734 std::ops::Bound::Excluded(&n) => n,
735 std::ops::Bound::Unbounded => self.shape[0],
736 };
737
738 if start >= end || end > self.shape[0] {
739 return Err(CoreError::ShapeError(ErrorContext::new(format!(
740 "Invalid slice range {}..{} for array of shape {:?}",
741 start, end, self.shape
742 ))));
743 }
744
745 let slice_info = unsafe {
747 SliceInfo::<Vec<SliceInfoElem>, crate::ndarray::Ix1, crate::ndarray::Ix1>::new(vec![
748 SliceInfoElem::Slice {
749 start: start as isize,
750 end: Some(end as isize),
751 step: 1,
752 },
753 ])
754 .map_err(|e| {
755 CoreError::ShapeError(ErrorContext::new(format!(
756 "Failed to create slice info: {e}"
757 )))
758 })?
759 };
760
761 let source = self.clone_ref()?;
763 Ok(MemoryMappedSlice::new(source, slice_info))
764 }
765
766 fn slice_2d(
767 &self,
768 row_range: impl RangeBounds<usize>,
769 col_range: impl RangeBounds<usize>,
770 ) -> CoreResult<MemoryMappedSlice<A, crate::ndarray::Ix2>> {
771 if self.shape.len() != 2 {
773 return Err(CoreError::ShapeError(ErrorContext::new(format!(
774 "Expected 2D array, got {}D",
775 self.shape.len()
776 ))));
777 }
778
779 let row_start = match row_range.start_bound() {
781 std::ops::Bound::Included(&n) => n,
782 std::ops::Bound::Excluded(&n) => n + 1,
783 std::ops::Bound::Unbounded => 0,
784 };
785
786 let row_end = match row_range.end_bound() {
787 std::ops::Bound::Included(&n) => n + 1,
788 std::ops::Bound::Excluded(&n) => n,
789 std::ops::Bound::Unbounded => self.shape[0],
790 };
791
792 let col_start = match col_range.start_bound() {
794 std::ops::Bound::Included(&n) => n,
795 std::ops::Bound::Excluded(&n) => n + 1,
796 std::ops::Bound::Unbounded => 0,
797 };
798
799 let col_end = match col_range.end_bound() {
800 std::ops::Bound::Included(&n) => n + 1,
801 std::ops::Bound::Excluded(&n) => n,
802 std::ops::Bound::Unbounded => self.shape[1],
803 };
804
805 if row_start >= row_end || row_end > self.shape[0] {
807 return Err(CoreError::ShapeError(ErrorContext::new(format!(
808 "Invalid row slice _range {}..{} for array of shape {:?}",
809 row_start, row_end, self.shape
810 ))));
811 }
812
813 if col_start >= col_end || col_end > self.shape[1] {
814 return Err(CoreError::ShapeError(ErrorContext::new(format!(
815 "Invalid column slice _range {}..{} for array of shape {:?}",
816 col_start, col_end, self.shape
817 ))));
818 }
819
820 let slice_info = unsafe {
822 SliceInfo::<Vec<SliceInfoElem>, crate::ndarray::Ix2, crate::ndarray::Ix2>::new(vec![
823 SliceInfoElem::Slice {
824 start: row_start as isize,
825 end: Some(row_end as isize),
826 step: 1,
827 },
828 SliceInfoElem::Slice {
829 start: col_start as isize,
830 end: Some(col_end as isize),
831 step: 1,
832 },
833 ])
834 .map_err(|e| {
835 CoreError::ShapeError(ErrorContext::new(format!(
836 "Failed to create slice info: {e}"
837 )))
838 })?
839 };
840
841 let source = self.clone_ref()?;
843 Ok(MemoryMappedSlice::new(source, slice_info))
844 }
845}
846
847