Skip to content

Commit c4dff76

Browse files
committed
Change NotContiguousError to AsSliceError
This is a breaking API change causing `PyArrayMethods::as_slice` to become more accurate at reporting its failure reason.
1 parent 0a20571 commit c4dff76

File tree

5 files changed

+36
-21
lines changed

5 files changed

+36
-21
lines changed

src/array.rs

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use crate::cold;
2626
use crate::convert::{ArrayExt, IntoPyArray, NpyIndex, ToNpyDims, ToPyArray};
2727
use crate::dtype::{Element, PyArrayDescrMethods};
2828
use crate::error::{
29-
BorrowError, DimensionalityError, FromVecError, IgnoreError, NotContiguousError, TypeError,
29+
AsSliceError, BorrowError, DimensionalityError, FromVecError, IgnoreError, TypeError,
3030
DIMENSIONALITY_MISMATCH_ERR, MAX_DIMENSIONALITY_ERR,
3131
};
3232
use crate::npyffi::{self, npy_intp, NPY_ORDER, PY_ARRAY_API};
@@ -739,7 +739,7 @@ pub trait PyArrayMethods<'py, T, D>: PyUntypedArrayMethods<'py> {
739739
/// or concurrently modified by Python or other native code.
740740
///
741741
/// Please consider the safe alternative [`PyReadonlyArray::as_slice`].
742-
unsafe fn as_slice(&self) -> Result<&[T], NotContiguousError>
742+
unsafe fn as_slice(&self) -> Result<&[T], AsSliceError>
743743
where
744744
T: Element,
745745
D: Dimension,
@@ -749,10 +749,12 @@ pub trait PyArrayMethods<'py, T, D>: PyUntypedArrayMethods<'py> {
749749
// We can still produce a slice over zero objects regardless of whether
750750
// the underlying pointer is aligned or not.
751751
Ok(&[])
752-
} else if self.is_aligned() && self.is_contiguous() {
753-
Ok(slice::from_raw_parts(self.data(), len))
752+
} else if !self.is_aligned() {
753+
Err(AsSliceError::NotAligned)
754+
} else if !self.is_contiguous() {
755+
Err(AsSliceError::NotContiguous)
754756
} else {
755-
Err(NotContiguousError)
757+
Ok(slice::from_raw_parts(self.data(), len))
756758
}
757759
}
758760

@@ -766,7 +768,7 @@ pub trait PyArrayMethods<'py, T, D>: PyUntypedArrayMethods<'py> {
766768
///
767769
/// Please consider the safe alternative [`PyReadwriteArray::as_slice_mut`].
768770
#[allow(clippy::mut_from_ref)]
769-
unsafe fn as_slice_mut(&self) -> Result<&mut [T], NotContiguousError>
771+
unsafe fn as_slice_mut(&self) -> Result<&mut [T], AsSliceError>
770772
where
771773
T: Element,
772774
D: Dimension,
@@ -776,10 +778,12 @@ pub trait PyArrayMethods<'py, T, D>: PyUntypedArrayMethods<'py> {
776778
// We can still produce a slice over zero objects regardless of whether
777779
// the underlying pointer is aligned or not.
778780
Ok(&mut [])
779-
} else if self.is_aligned() && self.is_contiguous() {
780-
Ok(slice::from_raw_parts_mut(self.data(), len))
781+
} else if !self.is_aligned() {
782+
Err(AsSliceError::NotAligned)
783+
} else if !self.is_contiguous() {
784+
Err(AsSliceError::NotContiguous)
781785
} else {
782-
Err(NotContiguousError)
786+
Ok(slice::from_raw_parts_mut(self.data(), len))
783787
}
784788
}
785789

@@ -961,7 +965,7 @@ pub trait PyArrayMethods<'py, T, D>: PyUntypedArrayMethods<'py> {
961965
/// })
962966
/// # }
963967
/// ```
964-
fn to_vec(&self) -> Result<Vec<T>, NotContiguousError>
968+
fn to_vec(&self) -> Result<Vec<T>, AsSliceError>
965969
where
966970
T: Element,
967971
D: Dimension;
@@ -1468,7 +1472,7 @@ impl<'py, T, D> PyArrayMethods<'py, T, D> for Bound<'py, PyArray<T, D>> {
14681472
unsafe { self.cast_unchecked() }
14691473
}
14701474

1471-
fn to_vec(&self) -> Result<Vec<T>, NotContiguousError>
1475+
fn to_vec(&self) -> Result<Vec<T>, AsSliceError>
14721476
where
14731477
T: Element,
14741478
D: Dimension,

src/borrow/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ use pyo3::{Borrowed, Bound, CastError, FromPyObject, PyAny, PyResult};
180180
use crate::array::{PyArray, PyArrayMethods};
181181
use crate::convert::NpyIndex;
182182
use crate::dtype::Element;
183-
use crate::error::{BorrowError, NotContiguousError};
183+
use crate::error::{BorrowError, AsSliceError};
184184
use crate::npyffi::flags;
185185
use crate::untyped_array::PyUntypedArrayMethods;
186186

@@ -268,7 +268,7 @@ where
268268

269269
/// Provide an immutable slice view of the interior of the NumPy array if it is contiguous.
270270
#[inline(always)]
271-
pub fn as_slice(&self) -> Result<&[T], NotContiguousError> {
271+
pub fn as_slice(&self) -> Result<&[T], AsSliceError> {
272272
// SAFETY: Global borrow flags ensure aliasing discipline.
273273
unsafe { self.array.as_slice() }
274274
}
@@ -511,7 +511,7 @@ where
511511

512512
/// Provide a mutable slice view of the interior of the NumPy array if it is contiguous.
513513
#[inline(always)]
514-
pub fn as_slice_mut(&mut self) -> Result<&mut [T], NotContiguousError> {
514+
pub fn as_slice_mut(&mut self) -> Result<&mut [T], AsSliceError> {
515515
// SAFETY: Global borrow flags ensure aliasing discipline.
516516
unsafe { self.array.as_slice_mut() }
517517
}

src/error.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -141,17 +141,27 @@ impl fmt::Display for FromVecError {
141141

142142
impl_pyerr!(FromVecError);
143143

144-
/// Represents that the given array is not contiguous.
144+
/// Represents that the given array is not compatible with viewing as a Rust slice.
145+
///
146+
/// If an array fails for more than one reason, it is not guaranteed which variant is returned.
145147
#[derive(Debug)]
146-
pub struct NotContiguousError;
148+
pub enum AsSliceError {
149+
/// The array is not backed by an aligned pointer.
150+
NotAligned,
151+
/// The array is not contiguous in memory.
152+
NotContiguous,
153+
}
147154

148-
impl fmt::Display for NotContiguousError {
155+
impl fmt::Display for AsSliceError {
149156
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150-
write!(f, "The given array is not contiguous")
157+
match self {
158+
Self::NotAligned => write!(f, "The given array is not aligned"),
159+
Self::NotContiguous => write!(f, "The given array is not contiguous"),
160+
}
151161
}
152162
}
153163

154-
impl_pyerr!(NotContiguousError);
164+
impl_pyerr!(AsSliceError);
155165

156166
/// Inidcates why borrowing an array failed.
157167
#[derive(Debug)]

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ pub use crate::borrow::{
106106
};
107107
pub use crate::convert::{IntoPyArray, NpyIndex, ToNpyDims, ToPyArray};
108108
pub use crate::dtype::{dtype, Complex32, Complex64, Element, PyArrayDescr, PyArrayDescrMethods};
109-
pub use crate::error::{BorrowError, FromVecError, NotContiguousError};
109+
pub use crate::error::{BorrowError, FromVecError, AsSliceError};
110110
pub use crate::npyffi::{PY_ARRAY_API, PY_UFUNC_API};
111111
pub use crate::strings::{PyFixedString, PyFixedUnicode};
112112
pub use crate::sum_products::{dot, einsum, inner};

tests/array.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,8 @@ fn as_slice() {
196196

197197
let not_aligned = not_aligned_array(py);
198198
assert!(!not_aligned.is_aligned());
199-
assert!(not_aligned.readonly().as_slice().is_err());
199+
let err = not_aligned.readonly().as_slice().unwrap_err();
200+
assert_eq!(err.to_string(), "The given array is not aligned");
200201

201202
let misaligned_empty: Bound<'_, PyArray1<u16>> = {
202203
let arr = not_aligned_array(py);

0 commit comments

Comments
 (0)