Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Changelog
- v0.28.0
- Fix mismatched behavior between `PyArrayLike1` and `PyArrayLike2` when used with floats ([#520](https://github.com/PyO3/rust-numpy/pull/520))
- Add ownership-moving conversions into `PyReadonlyArray` and `PyReadwriteArray` ([#524](https://github.com/PyO3/rust-numpy/pull/524))

- v0.27.1
- Bump ndarray dependency to v0.17. ([#516](https://github.com/PyO3/rust-numpy/pull/516))
Expand Down
67 changes: 64 additions & 3 deletions src/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,7 @@ unsafe fn clone_elements<T: Element>(py: Python<'_>, elems: &[T], data_ptr: &mut

/// Implementation of functionality for [`PyArray<T, D>`].
#[doc(alias = "PyArray")]
pub trait PyArrayMethods<'py, T, D>: PyUntypedArrayMethods<'py> {
pub trait PyArrayMethods<'py, T, D>: PyUntypedArrayMethods<'py> + Sized {
/// Access an untyped representation of this array.
fn as_untyped(&self) -> &Bound<'py, PyUntypedArray>;

Expand Down Expand Up @@ -956,12 +956,33 @@ pub trait PyArrayMethods<'py, T, D>: PyUntypedArrayMethods<'py> {
T: Element,
D: Dimension;

/// Consume `self` into an immutable borrow of the NumPy array
fn try_into_readonly(self) -> Result<PyReadonlyArray<'py, T, D>, BorrowError>
where
T: Element,
D: Dimension;

/// Get an immutable borrow of the NumPy array
fn try_readonly(&self) -> Result<PyReadonlyArray<'py, T, D>, BorrowError>
where
T: Element,
D: Dimension;

/// Consume `self` into an immutable borrow of the NumPy array
///
/// # Panics
///
/// Panics if the allocation backing the array is currently mutably borrowed.
///
/// For a non-panicking variant, use [`try_into_readonly`][Self::try_into_readonly].
fn into_readonly(self) -> PyReadonlyArray<'py, T, D>
where
T: Element,
D: Dimension,
{
self.try_into_readonly().unwrap()
}

/// Get an immutable borrow of the NumPy array
///
/// # Panics
Expand All @@ -977,12 +998,36 @@ pub trait PyArrayMethods<'py, T, D>: PyUntypedArrayMethods<'py> {
self.try_readonly().unwrap()
}

/// Consume `self` into an mutable borrow of the NumPy array
fn try_into_readwrite(self) -> Result<PyReadwriteArray<'py, T, D>, BorrowError>
where
T: Element,
D: Dimension;

/// Get a mutable borrow of the NumPy array
fn try_readwrite(&self) -> Result<PyReadwriteArray<'py, T, D>, BorrowError>
where
T: Element,
D: Dimension;

/// Consume `self` into an mutable borrow of the NumPy array
///
/// # Panics
///
/// Panics if the allocation backing the array is currently borrowed or
/// if the array is [flagged as][flags] not writeable.
///
/// For a non-panicking variant, use [`try_into_readwrite`][Self::try_into_readwrite].
///
/// [flags]: https://numpy.org/doc/stable/reference/generated/numpy.ndarray.flags.html
fn into_readwrite(self) -> PyReadwriteArray<'py, T, D>
where
T: Element,
D: Dimension,
{
self.try_into_readwrite().unwrap()
}

/// Get a mutable borrow of the NumPy array
///
/// # Panics
Expand Down Expand Up @@ -1467,20 +1512,36 @@ impl<'py, T, D> PyArrayMethods<'py, T, D> for Bound<'py, PyArray<T, D>> {
slice.map(|slc| T::vec_from_slice(self.py(), slc))
}

fn try_into_readonly(self) -> Result<PyReadonlyArray<'py, T, D>, BorrowError>
where
T: Element,
D: Dimension,
{
PyReadonlyArray::try_new(self)
}

fn try_readonly(&self) -> Result<PyReadonlyArray<'py, T, D>, BorrowError>
where
T: Element,
D: Dimension,
{
PyReadonlyArray::try_new(self.clone())
self.clone().try_into_readonly()
}

fn try_into_readwrite(self) -> Result<PyReadwriteArray<'py, T, D>, BorrowError>
where
T: Element,
D: Dimension,
{
PyReadwriteArray::try_new(self)
}

fn try_readwrite(&self) -> Result<PyReadwriteArray<'py, T, D>, BorrowError>
where
T: Element,
D: Dimension,
{
PyReadwriteArray::try_new(self.clone())
self.clone().try_into_readwrite()
}

unsafe fn as_array(&self) -> ArrayView<'_, T, D>
Expand Down
13 changes: 10 additions & 3 deletions src/borrow/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,13 @@ where
///
/// Safe wrapper for [`PyArray::resize`].
///
/// Note that as this mutates a pointed-to object, the [`PyReadwriteArray`] must be the only
/// Python reference to the object. There cannot be `PyArray` pointers or even `Bound<PyAny>`
/// pointing to the same object; this means for example that an object received from a PyO3
/// `pyfunction` cannot call this method, since the PyO3 wrapper maintains a reference itself.
/// Attempting to call this method when there are other Python references is still safe; NumPy
/// will raise a Python-space exception.
///
/// # Example
///
/// ```
Expand All @@ -616,7 +623,7 @@ where
/// let pyarray = PyArray::arange(py, 0, 10, 1);
/// assert_eq!(pyarray.len(), 10);
///
/// let pyarray = pyarray.readwrite();
/// let pyarray = pyarray.into_readwrite();
/// let pyarray = pyarray.resize(100).unwrap();
/// assert_eq!(pyarray.len(), 100);
/// });
Expand Down Expand Up @@ -722,7 +729,7 @@ mod tests {
.cast_into::<PyArray1<f64>>()
.unwrap();

let exclusive = array.readwrite();
let exclusive = array.into_readwrite();
assert!(exclusive.resize(100).is_err());
});
}
Expand All @@ -732,7 +739,7 @@ mod tests {
Python::attach(|py| {
let array = PyArray::<f64, _>::zeros(py, 10, false);

let exclusive = array.readwrite();
let exclusive = array.into_readwrite();
assert!(exclusive.resize(10).is_ok());
});
}
Expand Down
4 changes: 2 additions & 2 deletions tests/borrow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ fn multiple_shared_borrows() {
let array = PyArray::<f64, _>::zeros(py, (1, 2, 3), false);

let shared1 = array.readonly();
let shared2 = array.readonly();
let shared2 = array.into_readonly();

assert_eq!(shared2.shape(), [1, 2, 3]);
assert_eq!(shared1.shape(), [1, 2, 3]);
Expand Down Expand Up @@ -341,7 +341,7 @@ fn resize_using_exclusive_borrow() {
let array = PyArray::<f64, _>::zeros(py, 3, false);
assert_eq!(array.shape(), [3]);

let mut array = array.readwrite();
let mut array = array.into_readwrite();
assert_eq!(array.as_slice_mut().unwrap(), &[0.0; 3]);

let mut array = array.resize(5).unwrap();
Expand Down
Loading