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 if resultdims.len() == 1 => {
145 let dim1 = crate::ndarray::Ix1(resultdims[0]);
146 let converted_dim = unsafe { std::mem::transmute_copy(&dim1) };
147 return Ok(converted_dim);
148 }
149 2 if resultdims.len() == 2 => {
150 let dim2 = crate::ndarray::Ix2(resultdims[0], resultdims[1]);
151 let converted_dim = unsafe { std::mem::transmute_copy(&dim2) };
152 return Ok(converted_dim);
153 }
154 3 if resultdims.len() == 3 => {
155 let dim3 = crate::ndarray::Ix3(resultdims[0], resultdims[1], resultdims[2]);
156 let converted_dim = unsafe { std::mem::transmute_copy(&dim3) };
157 return Ok(converted_dim);
158 }
159 4 if resultdims.len() == 4 => {
160 let dim4 = crate::ndarray::Ix4(
161 resultdims[0],
162 resultdims[1],
163 resultdims[2],
164 resultdims[3],
165 );
166 let converted_dim = unsafe { std::mem::transmute_copy(&dim4) };
167 return Ok(converted_dim);
168 }
169 _ => {}
170 }
171
172 return Err(CoreError::DimensionError(ErrorContext::new(format!(
173 "Cannot convert {source_ndim} dimensions to target dimension type"
174 ))));
175 }
176
177 if source_ndim < target_ndim {
179 let mut expanded_dims = resultdims.to_vec();
181 expanded_dims.resize(target_ndim, 1);
182
183 match target_ndim {
184 1 => {
185 if expanded_dims.len() == 1 {
186 let dim1 = crate::ndarray::Ix1(expanded_dims[0]);
187 let converted_dim = unsafe { std::mem::transmute_copy(&dim1) };
188 Ok(converted_dim)
189 } else {
190 Err(CoreError::DimensionError(ErrorContext::new(format!(
191 "Cannot expand to 1D from dimensions: {expanded_dims:?}"
192 ))))
193 }
194 }
195 2 => {
196 if expanded_dims.len() == 2 {
197 let dim2 = crate::ndarray::Ix2(expanded_dims[0], expanded_dims[1]);
198 let converted_dim = unsafe { std::mem::transmute_copy(&dim2) };
199 Ok(converted_dim)
200 } else {
201 Err(CoreError::DimensionError(ErrorContext::new(format!(
202 "Cannot expand to 2D from dimensions: {expanded_dims:?}"
203 ))))
204 }
205 }
206 3 => {
207 if expanded_dims.len() == 3 {
208 let dim3 = crate::ndarray::Ix3(
209 expanded_dims[0],
210 expanded_dims[1],
211 expanded_dims[2],
212 );
213 let converted_dim = unsafe { std::mem::transmute_copy(&dim3) };
214 Ok(converted_dim)
215 } else {
216 Err(CoreError::DimensionError(ErrorContext::new(format!(
217 "Cannot expand to 3D from dimensions: {expanded_dims:?}"
218 ))))
219 }
220 }
221 4 => {
222 if expanded_dims.len() == 4 {
223 let dim4 = crate::ndarray::Ix4(
224 expanded_dims[0],
225 expanded_dims[1],
226 expanded_dims[2],
227 expanded_dims[3],
228 );
229 let converted_dim = unsafe { std::mem::transmute_copy(&dim4) };
230 Ok(converted_dim)
231 } else {
232 Err(CoreError::DimensionError(ErrorContext::new(format!(
233 "Cannot expand to 4D from dimensions: {expanded_dims:?}"
234 ))))
235 }
236 }
237 _ => Err(CoreError::DimensionError(ErrorContext::new(format!(
238 "Unsupported target dimension: {target_ndim}"
239 )))),
240 }
241 } else {
242 let mut squeezed_dims = Vec::new();
244 let mut removed_count = 0;
245 let dims_to_remove = source_ndim - target_ndim;
246
247 for &dim_size in resultdims {
248 if dim_size == 1 && removed_count < dims_to_remove {
249 removed_count += 1;
250 } else {
251 squeezed_dims.push(dim_size);
252 }
253 }
254
255 if squeezed_dims.len() != target_ndim {
256 return Err(CoreError::DimensionError(ErrorContext::new(format!(
257 "Sliced shape has {} dimensions but target type expects {} dimensions. \
258 Sliced shape: {:?}, source shape: {:?}, available singleton dimensions: {}",
259 source_ndim,
260 target_ndim,
261 resultdims,
262 resultdims,
263 resultdims.iter().filter(|&&x| x == 1).count()
264 ))));
265 }
266
267 match target_ndim {
268 1 => {
269 if squeezed_dims.len() == 1 {
270 let dim1 = crate::ndarray::Ix1(squeezed_dims[0]);
271 let converted_dim = unsafe { std::mem::transmute_copy(&dim1) };
272 Ok(converted_dim)
273 } else {
274 Err(CoreError::DimensionError(ErrorContext::new(format!(
275 "Cannot squeeze to 1D from dimensions: {squeezed_dims:?}"
276 ))))
277 }
278 }
279 2 => {
280 if squeezed_dims.len() == 2 {
281 let dim2 = crate::ndarray::Ix2(squeezed_dims[0], squeezed_dims[1]);
282 let converted_dim = unsafe { std::mem::transmute_copy(&dim2) };
283 Ok(converted_dim)
284 } else {
285 Err(CoreError::DimensionError(ErrorContext::new(format!(
286 "Cannot squeeze to 2D from dimensions: {squeezed_dims:?}"
287 ))))
288 }
289 }
290 3 => {
291 if squeezed_dims.len() == 3 {
292 let dim3 = crate::ndarray::Ix3(
293 squeezed_dims[0],
294 squeezed_dims[1],
295 squeezed_dims[2],
296 );
297 let converted_dim = unsafe { std::mem::transmute_copy(&dim3) };
298 Ok(converted_dim)
299 } else {
300 Err(CoreError::DimensionError(ErrorContext::new(format!(
301 "Cannot squeeze to 3D from dimensions: {squeezed_dims:?}"
302 ))))
303 }
304 }
305 4 => {
306 if squeezed_dims.len() == 4 {
307 let dim4 = crate::ndarray::Ix4(
308 squeezed_dims[0],
309 squeezed_dims[1],
310 squeezed_dims[2],
311 squeezed_dims[3],
312 );
313 let converted_dim = unsafe { std::mem::transmute_copy(&dim4) };
314 Ok(converted_dim)
315 } else {
316 Err(CoreError::DimensionError(ErrorContext::new(format!(
317 "Cannot squeeze to 4D from dimensions: {squeezed_dims:?}"
318 ))))
319 }
320 }
321 _ => Err(CoreError::DimensionError(ErrorContext::new(format!(
322 "Unsupported target dimension: {target_ndim}"
323 )))),
324 }
325 }
326 }
327
328 pub const fn source(&self) -> &MemoryMappedArray<A> {
330 &self.source
331 }
332
333 pub const fn slice_info(&self) -> &SliceInfo<Vec<SliceInfoElem>, D, D> {
335 &self.slice_info
336 }
337
338 fn safe_dimensionality_conversion(
340 array: crate::ndarray::ArrayBase<crate::ndarray::OwnedRepr<A>, crate::ndarray::IxDyn>,
341 context: &str,
342 ) -> CoreResult<ArrayBase<crate::ndarray::OwnedRepr<A>, D>> {
343 let sourceshape = array.shape().to_vec();
344 let source_ndim = sourceshape.len();
345 let target_ndim = D::NDIM;
346
347 if target_ndim.is_none() {
349 return array.into_dimensionality::<D>().map_err(|_| {
350 CoreError::DimensionError(ErrorContext::new(format!(
351 "Failed to convert {context} array to dynamic dimension type. Source shape: {sourceshape:?}"
352 )))
353 });
354 }
355
356 let target_ndim = target_ndim.expect("Operation failed");
357
358 if source_ndim == target_ndim {
360 return array.into_dimensionality::<D>().map_err(|_| {
361 CoreError::DimensionError(ErrorContext::new(format!(
362 "Dimension conversion failed for {} array despite matching dimensions ({} -> {}). Source shape: {:?}, target dimension type: {}",
363 context, source_ndim, target_ndim, sourceshape, std::any::type_name::<D>()
364 )))
365 });
366 }
367
368 match source_ndim.cmp(&target_ndim) {
370 std::cmp::Ordering::Less => {
371 Self::try_expand_dimensions(array, context, source_ndim, target_ndim)
373 }
374 std::cmp::Ordering::Greater => {
375 Self::try_squeeze_dimensions(array, context, source_ndim, target_ndim)
377 }
378 std::cmp::Ordering::Equal => {
379 array.into_dimensionality::<D>().map_err(|_| {
381 CoreError::DimensionError(ErrorContext::new(format!(
382 "Unexpected dimension conversion failure for {context} array with matching dimensions. Source shape: {sourceshape:?}"
383 )))
384 })
385 }
386 }
387 }
388
389 fn try_expand_dimensions(
391 array: crate::ndarray::ArrayBase<crate::ndarray::OwnedRepr<A>, crate::ndarray::IxDyn>,
392 context: &str,
393 source_dims: usize,
394 target_dims: usize,
395 ) -> CoreResult<ArrayBase<crate::ndarray::OwnedRepr<A>, D>> {
396 let sourceshape = array.shape().to_vec();
397 let dims_to_add = target_dims - source_dims;
398
399 if dims_to_add == 0 {
400 return array.into_dimensionality::<D>().map_err(|_| {
401 CoreError::DimensionError(ErrorContext::new(format!(
402 "Failed to convert {context} array despite equal dimensions"
403 )))
404 });
405 }
406
407 let mut expandedshape = sourceshape.clone();
409 expandedshape.resize(source_dims + dims_to_add, 1);
410
411 match array
413 .clone()
414 .into_shape_with_order(crate::ndarray::IxDyn(&expandedshape))
415 {
416 Ok(reshaped) => reshaped.into_dimensionality::<D>().map_err(|_| {
417 CoreError::DimensionError(ErrorContext::new(format!(
418 "Failed to convert expanded {context} array to target dimension type"
419 )))
420 }),
421 Err(_) => {
422 let mut altshape = vec![1; dims_to_add];
424 altshape.extend_from_slice(&sourceshape);
425
426 array
427 .into_shape_with_order(crate::ndarray::IxDyn(&altshape))
428 .map_err(|_| {
429 CoreError::DimensionError(ErrorContext::new(format!(
430 "Cannot reshape {context} array from shape {sourceshape:?} to any expanded shape"
431 )))
432 })?
433 .into_dimensionality::<D>()
434 .map_err(|_| {
435 CoreError::DimensionError(ErrorContext::new(format!(
436 "Cannot expand {context} array from {source_dims} to {target_dims} dimensions"
437 )))
438 })
439 }
440 }
441 }
442
443 fn try_squeeze_dimensions(
445 array: crate::ndarray::ArrayBase<crate::ndarray::OwnedRepr<A>, crate::ndarray::IxDyn>,
446 context: &str,
447 source_dims: usize,
448 target_dims: usize,
449 ) -> CoreResult<ArrayBase<crate::ndarray::OwnedRepr<A>, D>> {
450 let sourceshape = array.shape().to_vec();
451
452 let mut squeezedshape = Vec::new();
454 let mut removed_dims = 0;
455 let dims_to_remove = source_dims - target_dims;
456
457 for &dim_size in &sourceshape {
458 if dim_size == 1 && removed_dims < dims_to_remove {
459 removed_dims += 1;
461 } else {
462 squeezedshape.push(dim_size);
463 }
464 }
465
466 if squeezedshape.len() != target_dims {
467 return Err(CoreError::DimensionError(ErrorContext::new(format!(
468 "Cannot squeeze {} array from {} to {} dimensions. Source shape: {:?}, only {} singleton dimensions available",
469 context, source_dims, target_dims, sourceshape,
470 sourceshape.iter().filter(|&&x| x == 1).count()
471 ))));
472 }
473
474 array
476 .into_shape_with_order(crate::ndarray::IxDyn(&squeezedshape))
477 .map_err(|_| {
478 CoreError::DimensionError(ErrorContext::new(format!(
479 "Cannot reshape {context} array from shape {sourceshape:?} to squeezed shape {squeezedshape:?}"
480 )))
481 })?
482 .into_dimensionality::<D>()
483 .map_err(|_| {
484 CoreError::DimensionError(ErrorContext::new(format!(
485 "Cannot convert squeezed {context} array from {source_dims} to {target_dims} dimensions"
486 )))
487 })
488 }
489
490 pub fn load(&self) -> CoreResult<ArrayBase<crate::ndarray::OwnedRepr<A>, D>> {
495 let data_slice = self.source.as_slice();
497
498 self.load_slice_generic(data_slice)
500 }
501
502 fn load_slice_generic(
504 &self,
505 data_slice: &[A],
506 ) -> CoreResult<ArrayBase<crate::ndarray::OwnedRepr<A>, D>> {
507 use ::ndarray::IxDyn;
508
509 self.validate_dimension_compatibility()?;
511
512 let sourceshape = IxDyn(&self.source.shape);
514 let source_array =
515 crate::ndarray::ArrayView::from_shape(sourceshape, data_slice).map_err(|e| {
516 CoreError::ShapeError(ErrorContext::new(format!(
517 "Failed to create array view from source shape {:?}: {}",
518 self.source.shape, e
519 )))
520 })?;
521
522 let slice_elements = self.slice_info.as_ref();
524 let sliced = self.apply_slice_safely_owned(source_array, slice_elements)?;
525
526 Self::safe_dimensionality_conversion(sliced, "sliced array")
528 }
529
530 fn validate_dimension_compatibility(&self) -> CoreResult<()> {
532 let source_ndim = self.source.shape.len();
533 let slice_elements = self.slice_info.as_ref();
534
535 let mut resulting_dims = 0;
537 let mut index_operations = 0;
538
539 for (i, elem) in slice_elements.iter().enumerate() {
541 if i >= source_ndim {
542 resulting_dims += 1;
545 } else {
546 match elem {
547 SliceInfoElem::Index(_) => {
548 index_operations += 1;
550 }
551 SliceInfoElem::Slice { .. } => {
552 resulting_dims += 1;
554 }
555 _ => {
558 resulting_dims += 1;
560 }
561 }
562 }
563 }
564
565 if slice_elements.len() < source_ndim {
567 resulting_dims += source_ndim - slice_elements.len();
568 }
569
570 if let Some(target_ndim) = D::NDIM {
572 if resulting_dims != target_ndim {
573 return Err(CoreError::DimensionError(ErrorContext::new(format!(
574 "Dimension mismatch: slice operation will result in {}D array, but target type expects {}D. Source shape: {:?} ({}D), slice elements: {}, index operations: {}",
575 resulting_dims, target_ndim, self.source.shape, source_ndim,
576 slice_elements.len(), index_operations
577 ))));
578 }
579 }
580
581 Ok(())
582 }
583
584 fn apply_slice_safely_owned(
586 &self,
587 source_array: crate::ndarray::ArrayView<A, IxDyn>,
588 slice_elements: &[SliceInfoElem],
589 ) -> CoreResult<crate::ndarray::Array<A, IxDyn>> {
590 if slice_elements.is_empty() {
591 return Ok(source_array.to_owned());
592 }
593
594 let sliced = source_array.slice_each_axis(|ax| {
596 if ax.axis.index() < slice_elements.len() {
597 match &slice_elements[ax.axis.index()] {
598 SliceInfoElem::Slice { start, end, step } => {
599 let dim_size = ax.len as isize;
601 let safe_start = self.handle_negative_index(*start, dim_size);
602 let safe_end = if let Some(e) = end {
603 self.handle_negative_index(*e, dim_size)
604 } else {
605 dim_size
606 };
607
608 let clamped_start = safe_start.max(0).min(dim_size) as usize;
610 let clamped_end = safe_end.max(0).min(dim_size) as usize;
611
612 let safe_step = step.max(&1).unsigned_abs();
614
615 crate::ndarray::Slice::new(
616 clamped_start as isize,
617 Some(clamped_end as isize),
618 safe_step as isize,
619 )
620 }
621 SliceInfoElem::Index(idx) => {
622 let dim_size = ax.len as isize;
623 let safe_idx = self.handle_negative_index(*idx, dim_size);
624 let clamped_idx = safe_idx.max(0).min(dim_size - 1) as usize;
625 crate::ndarray::Slice::new(
626 clamped_idx as isize,
627 Some((clamped_idx + 1) as isize),
628 1,
629 )
630 }
631 _ => crate::ndarray::Slice::new(0, None, 1),
632 }
633 } else {
634 crate::ndarray::Slice::new(0, None, 1)
635 }
636 });
637
638 Ok(sliced.to_owned())
639 }
640
641 fn handle_negative_index(&self, index: isize, dimsize: isize) -> isize {
643 if index < 0 {
644 dimsize + index
645 } else {
646 index
647 }
648 }
649}
650
651pub trait MemoryMappedSlicing<A: Clone + Copy + 'static + Send + Sync> {
653 fn slice<I, E>(&self, sliceinfo: I) -> CoreResult<MemoryMappedSlice<A, E>>
655 where
656 I: crate::ndarray::SliceArg<E>,
657 E: Dimension;
658
659 fn slice_1d(
661 &self,
662 range: impl RangeBounds<usize>,
663 ) -> CoreResult<MemoryMappedSlice<A, crate::ndarray::Ix1>>;
664
665 fn slice_2d(
667 &self,
668 row_range: impl RangeBounds<usize>,
669 col_range: impl RangeBounds<usize>,
670 ) -> CoreResult<MemoryMappedSlice<A, crate::ndarray::Ix2>>;
671}
672
673impl<A: Clone + Copy + 'static + Send + Sync> MemoryMappedSlicing<A> for MemoryMappedArray<A> {
674 fn slice<I, E>(&self, sliceinfo: I) -> CoreResult<MemoryMappedSlice<A, E>>
675 where
676 I: crate::ndarray::SliceArg<E>,
677 E: Dimension,
678 {
679 let slicedshape = self.shape.clone();
686
687 let mut elems = Vec::new();
690 for &dim_size in &slicedshape {
691 elems.push(SliceInfoElem::Slice {
692 start: 0,
693 end: Some(dim_size as isize),
694 step: 1,
695 });
696 }
697
698 let slice_info = unsafe { SliceInfo::new(elems) }
699 .map_err(|_| CoreError::ShapeError(ErrorContext::new("Failed to create slice info")))?;
700
701 let source = MemoryMappedArray::new::<crate::ndarray::OwnedRepr<A>, E>(
704 None,
705 &self.file_path,
706 self.mode,
707 self.offset,
708 )?;
709
710 Ok(MemoryMappedSlice::new(source, slice_info))
711 }
712
713 fn slice_1d(
714 &self,
715 range: impl RangeBounds<usize>,
716 ) -> CoreResult<MemoryMappedSlice<A, crate::ndarray::Ix1>> {
717 let start = match range.start_bound() {
719 std::ops::Bound::Included(&n) => n,
720 std::ops::Bound::Excluded(&n) => n + 1,
721 std::ops::Bound::Unbounded => 0,
722 };
723
724 let end = match range.end_bound() {
725 std::ops::Bound::Included(&n) => n + 1,
726 std::ops::Bound::Excluded(&n) => n,
727 std::ops::Bound::Unbounded => self.shape[0],
728 };
729
730 if start >= end || end > self.shape[0] {
731 return Err(CoreError::ShapeError(ErrorContext::new(format!(
732 "Invalid slice range {}..{} for array of shape {:?}",
733 start, end, self.shape
734 ))));
735 }
736
737 let slice_info = unsafe {
739 SliceInfo::<Vec<SliceInfoElem>, crate::ndarray::Ix1, crate::ndarray::Ix1>::new(vec![
740 SliceInfoElem::Slice {
741 start: start as isize,
742 end: Some(end as isize),
743 step: 1,
744 },
745 ])
746 .map_err(|e| {
747 CoreError::ShapeError(ErrorContext::new(format!(
748 "Failed to create slice info: {e}"
749 )))
750 })?
751 };
752
753 let source = self.clone_ref()?;
755 Ok(MemoryMappedSlice::new(source, slice_info))
756 }
757
758 fn slice_2d(
759 &self,
760 row_range: impl RangeBounds<usize>,
761 col_range: impl RangeBounds<usize>,
762 ) -> CoreResult<MemoryMappedSlice<A, crate::ndarray::Ix2>> {
763 if self.shape.len() != 2 {
765 return Err(CoreError::ShapeError(ErrorContext::new(format!(
766 "Expected 2D array, got {}D",
767 self.shape.len()
768 ))));
769 }
770
771 let row_start = match row_range.start_bound() {
773 std::ops::Bound::Included(&n) => n,
774 std::ops::Bound::Excluded(&n) => n + 1,
775 std::ops::Bound::Unbounded => 0,
776 };
777
778 let row_end = match row_range.end_bound() {
779 std::ops::Bound::Included(&n) => n + 1,
780 std::ops::Bound::Excluded(&n) => n,
781 std::ops::Bound::Unbounded => self.shape[0],
782 };
783
784 let col_start = match col_range.start_bound() {
786 std::ops::Bound::Included(&n) => n,
787 std::ops::Bound::Excluded(&n) => n + 1,
788 std::ops::Bound::Unbounded => 0,
789 };
790
791 let col_end = match col_range.end_bound() {
792 std::ops::Bound::Included(&n) => n + 1,
793 std::ops::Bound::Excluded(&n) => n,
794 std::ops::Bound::Unbounded => self.shape[1],
795 };
796
797 if row_start >= row_end || row_end > self.shape[0] {
799 return Err(CoreError::ShapeError(ErrorContext::new(format!(
800 "Invalid row slice _range {}..{} for array of shape {:?}",
801 row_start, row_end, self.shape
802 ))));
803 }
804
805 if col_start >= col_end || col_end > self.shape[1] {
806 return Err(CoreError::ShapeError(ErrorContext::new(format!(
807 "Invalid column slice _range {}..{} for array of shape {:?}",
808 col_start, col_end, self.shape
809 ))));
810 }
811
812 let slice_info = unsafe {
814 SliceInfo::<Vec<SliceInfoElem>, crate::ndarray::Ix2, crate::ndarray::Ix2>::new(vec![
815 SliceInfoElem::Slice {
816 start: row_start as isize,
817 end: Some(row_end as isize),
818 step: 1,
819 },
820 SliceInfoElem::Slice {
821 start: col_start as isize,
822 end: Some(col_end as isize),
823 step: 1,
824 },
825 ])
826 .map_err(|e| {
827 CoreError::ShapeError(ErrorContext::new(format!(
828 "Failed to create slice info: {e}"
829 )))
830 })?
831 };
832
833 let source = self.clone_ref()?;
835 Ok(MemoryMappedSlice::new(source, slice_info))
836 }
837}
838
839