@@ -19,13 +19,11 @@ use pyo3::{
1919 Python , ToPyObject ,
2020} ;
2121
22+ use crate :: borrow:: { PyReadonlyArray , PyReadwriteArray } ;
2223use crate :: convert:: { ArrayExt , IntoPyArray , NpyIndex , ToNpyDims , ToPyArray } ;
2324use crate :: dtype:: { Element , PyArrayDescr } ;
2425use crate :: error:: { DimensionalityError , FromVecError , NotContiguousError , TypeError } ;
2526use crate :: npyffi:: { self , npy_intp, NPY_ORDER , PY_ARRAY_API } ;
26- #[ allow( deprecated) ]
27- use crate :: npyiter:: { NpySingleIter , NpySingleIterBuilder , ReadWrite } ;
28- use crate :: readonly:: PyReadonlyArray ;
2927use crate :: slice_container:: PySliceContainer ;
3028
3129/// A safe, static-typed interface for
@@ -194,18 +192,8 @@ impl<T, D> PyArray<T, D> {
194192 }
195193
196194 #[ inline( always) ]
197- fn check_flag ( & self , flag : c_int ) -> bool {
198- unsafe { * self . as_array_ptr ( ) } . flags & flag == flag
199- }
200-
201- #[ inline( always) ]
202- pub ( crate ) fn get_flag ( & self ) -> c_int {
203- unsafe { * self . as_array_ptr ( ) } . flags
204- }
205-
206- /// Returns a temporally unwriteable reference of the array.
207- pub fn readonly ( & self ) -> PyReadonlyArray < T , D > {
208- self . into ( )
195+ pub ( crate ) fn check_flags ( & self , flags : c_int ) -> bool {
196+ unsafe { * self . as_array_ptr ( ) } . flags & flags != 0
209197 }
210198
211199 /// Returns `true` if the internal data of the array is C-style contiguous
@@ -227,18 +215,17 @@ impl<T, D> PyArray<T, D> {
227215 /// });
228216 /// ```
229217 pub fn is_contiguous ( & self ) -> bool {
230- self . check_flag ( npyffi:: NPY_ARRAY_C_CONTIGUOUS )
231- | self . check_flag ( npyffi:: NPY_ARRAY_F_CONTIGUOUS )
218+ self . check_flags ( npyffi:: NPY_ARRAY_C_CONTIGUOUS | npyffi:: NPY_ARRAY_F_CONTIGUOUS )
232219 }
233220
234221 /// Returns `true` if the internal data of the array is Fortran-style contiguous.
235222 pub fn is_fortran_contiguous ( & self ) -> bool {
236- self . check_flag ( npyffi:: NPY_ARRAY_F_CONTIGUOUS )
223+ self . check_flags ( npyffi:: NPY_ARRAY_F_CONTIGUOUS )
237224 }
238225
239226 /// Returns `true` if the internal data of the array is C-style contiguous.
240227 pub fn is_c_contiguous ( & self ) -> bool {
241- self . check_flag ( npyffi:: NPY_ARRAY_C_CONTIGUOUS )
228+ self . check_flags ( npyffi:: NPY_ARRAY_C_CONTIGUOUS )
242229 }
243230
244231 /// Get `Py<PyArray>` from `&PyArray`, which is the owned wrapper of PyObject.
@@ -680,27 +667,61 @@ impl<T: Element, D: Dimension> PyArray<T, D> {
680667
681668 /// Get the immutable reference of the specified element, with checking the passed index is valid.
682669 ///
683- /// Please consider the use of safe alternatives
684- /// ([`PyReadonlyArray::get`](../struct.PyReadonlyArray.html#method.get)
685- /// or [`get_owned`](#method.get_owned)) instead of this.
670+ /// Consider using safe alternatives like [`PyReadonlyArray::get`].
671+ ///
686672 /// # Example
673+ ///
687674 /// ```
688675 /// use numpy::PyArray;
689- /// pyo3::Python::with_gil(|py| {
676+ /// use pyo3::Python;
677+ ///
678+ /// Python::with_gil(|py| {
690679 /// let arr = PyArray::arange(py, 0, 16, 1).reshape([2, 2, 4]).unwrap();
691- /// assert_eq!(* unsafe { arr.get([1, 0, 3]) } .unwrap(), 11);
680+ /// assert_eq!(unsafe { * arr.get([1, 0, 3]).unwrap() } , 11);
692681 /// });
693682 /// ```
694683 ///
695684 /// # Safety
696- /// If the internal array is not readonly and can be mutated from Python code,
697- /// holding the slice might cause undefined behavior.
685+ ///
686+ /// Calling this method is undefined behaviour if the underlying array
687+ /// is aliased mutably by other instances of `PyArray`
688+ /// or concurrently modified by Python or other native code.
698689 #[ inline( always) ]
699690 pub unsafe fn get ( & self , index : impl NpyIndex < Dim = D > ) -> Option < & T > {
700691 let offset = index. get_checked :: < T > ( self . shape ( ) , self . strides ( ) ) ?;
701692 Some ( & * self . data ( ) . offset ( offset) )
702693 }
703694
695+ /// Same as [`get`][Self::get], but returns `Option<&mut T>`.
696+ ///
697+ /// Consider using safe alternatives like [`PyReadwriteArray::get_mut`].
698+ ///
699+ /// # Example
700+ ///
701+ /// ```
702+ /// use numpy::PyArray;
703+ /// use pyo3::Python;
704+ ///
705+ /// Python::with_gil(|py| {
706+ /// let arr = PyArray::arange(py, 0, 16, 1).reshape([2, 2, 4]).unwrap();
707+ /// unsafe {
708+ /// *arr.get_mut([1, 0, 3]).unwrap() = 42;
709+ /// }
710+ /// assert_eq!(unsafe { *arr.get([1, 0, 3]).unwrap() }, 42);
711+ /// });
712+ /// ```
713+ ///
714+ /// # Safety
715+ ///
716+ /// Calling this method is undefined behaviour if the underlying array
717+ /// is aliased immutably by mutably by other instances of `PyArray`
718+ /// or concurrently modified by Python or other native code.
719+ #[ inline( always) ]
720+ pub unsafe fn get_mut ( & self , index : impl NpyIndex < Dim = D > ) -> Option < & mut T > {
721+ let offset = index. get_checked :: < T > ( self . shape ( ) , self . strides ( ) ) ?;
722+ Some ( & mut * self . data ( ) . offset ( offset) )
723+ }
724+
704725 /// Get the immutable reference of the specified element, without checking the
705726 /// passed index is valid.
706727 ///
@@ -823,28 +844,37 @@ impl<T: Element, D: Dimension> PyArray<T, D> {
823844 ToPyArray :: to_pyarray ( arr, py)
824845 }
825846
826- /// Get the immutable view of the internal data of `PyArray`, as
827- /// [`ndarray::ArrayView`](https://docs.rs/ndarray/latest/ndarray/type.ArrayView.html).
847+ /// Get an immutable borrow of the NumPy array
848+ pub fn readonly ( & self ) -> PyReadonlyArray < ' _ , T , D > {
849+ PyReadonlyArray :: try_new ( self ) . unwrap ( )
850+ }
851+
852+ /// Get a mutable borrow of the NumPy array
853+ pub fn readwrite ( & self ) -> PyReadwriteArray < ' _ , T , D > {
854+ PyReadwriteArray :: try_new ( self ) . unwrap ( )
855+ }
856+
857+ /// Returns the internal array as [`ArrayView`].
828858 ///
829- /// Please consider the use of safe alternatives
830- /// ([`PyReadonlyArray::as_array`](../struct.PyReadonlyArray.html#method.as_array)
831- /// or [`to_array`](#method.to_array)) instead of this.
859+ /// See also [`PyReadonlyArray::as_array`].
832860 ///
833861 /// # Safety
834- /// If the internal array is not readonly and can be mutated from Python code,
835- /// holding the `ArrayView` might cause undefined behavior.
862+ ///
863+ /// The existence of an exclusive reference to the internal data, e.g. `&mut [T]` or `ArrayViewMut`, implies undefined behavior.
836864 pub unsafe fn as_array ( & self ) -> ArrayView < ' _ , T , D > {
837865 let ( shape, ptr, inverted_axes) = self . ndarray_shape_ptr ( ) ;
838866 let mut res = ArrayView :: from_shape_ptr ( shape, ptr) ;
839867 inverted_axes. invert ( & mut res) ;
840868 res
841869 }
842870
843- /// Returns the internal array as [`ArrayViewMut`]. See also [`as_array`](#method.as_array).
871+ /// Returns the internal array as [`ArrayViewMut`].
872+ ///
873+ /// See also [`PyReadwriteArray::as_array_mut`].
844874 ///
845875 /// # Safety
846- /// If another reference to the internal data exists(e.g., `&[T]` or `ArrayView`),
847- /// it might cause undefined behavior.
876+ ///
877+ /// The existence of another reference to the internal data, e.g. `&[T]` or `ArrayView`, implies undefined behavior.
848878 pub unsafe fn as_array_mut ( & self ) -> ArrayViewMut < ' _ , T , D > {
849879 let ( shape, ptr, inverted_axes) = self . ndarray_shape_ptr ( ) ;
850880 let mut res = ArrayViewMut :: from_shape_ptr ( shape, ptr) ;
@@ -920,7 +950,7 @@ impl<D: Dimension> PyArray<PyObject, D> {
920950 ///
921951 /// let pyarray = PyArray::from_owned_object_array(py, array);
922952 ///
923- /// assert!(pyarray.readonly().get(0).unwrap().as_ref(py).is_instance_of::<CustomElement>().unwrap());
953+ /// assert!(pyarray.readonly().as_array(). get(0).unwrap().as_ref(py).is_instance_of::<CustomElement>().unwrap());
924954 /// });
925955 /// ```
926956 pub fn from_owned_object_array < ' py , T > ( py : Python < ' py > , arr : Array < Py < T > , D > ) -> & ' py Self {
@@ -1036,21 +1066,6 @@ impl<T: Element> PyArray<T, Ix1> {
10361066 self . resize_ ( self . py ( ) , [ new_elems] , 1 , NPY_ORDER :: NPY_ANYORDER )
10371067 }
10381068
1039- /// Iterates all elements of this array.
1040- /// See [NpySingleIter](../npyiter/struct.NpySingleIter.html) for more.
1041- ///
1042- /// # Safety
1043- ///
1044- /// The iterator will produce mutable references into the array which must not be
1045- /// aliased by other references for the life time of the iterator.
1046- #[ deprecated(
1047- note = "The wrappers of the array iterator API are deprecated, please use ndarray's `ArrayBase::iter_mut` instead."
1048- ) ]
1049- #[ allow( deprecated) ]
1050- pub unsafe fn iter < ' py > ( & ' py self ) -> PyResult < NpySingleIter < ' py , T , ReadWrite > > {
1051- NpySingleIterBuilder :: readwrite ( self ) . build ( )
1052- }
1053-
10541069 fn resize_ < D : IntoDimension > (
10551070 & self ,
10561071 py : Python ,
0 commit comments