55use std:: {
66 marker:: PhantomData ,
77 mem,
8+ ops:: Deref ,
89 os:: raw:: { c_int, c_void} ,
910 ptr, slice,
1011} ;
@@ -16,21 +17,22 @@ use ndarray::{
1617} ;
1718use num_traits:: AsPrimitive ;
1819use pyo3:: {
19- ffi, pyobject_native_type_named , types:: PyModule , AsPyPointer , FromPyObject , IntoPy , Py , PyAny ,
20+ ffi, pyobject_native_type_base , types:: PyModule , AsPyPointer , FromPyObject , IntoPy , Py , PyAny ,
2021 PyClassInitializer , PyDowncastError , PyErr , PyNativeType , PyObject , PyResult , PyTypeInfo ,
2122 Python , ToPyObject ,
2223} ;
2324
2425use crate :: borrow:: { PyReadonlyArray , PyReadwriteArray } ;
2526use crate :: cold;
2627use crate :: convert:: { ArrayExt , IntoPyArray , NpyIndex , ToNpyDims , ToPyArray } ;
27- use crate :: dtype:: { Element , PyArrayDescr } ;
28+ use crate :: dtype:: Element ;
2829use crate :: error:: {
2930 BorrowError , DimensionalityError , FromVecError , IgnoreError , NotContiguousError , TypeError ,
3031 DIMENSIONALITY_MISMATCH_ERR , MAX_DIMENSIONALITY_ERR ,
3132} ;
3233use crate :: npyffi:: { self , npy_intp, NPY_ORDER , PY_ARRAY_API } ;
3334use crate :: slice_container:: PySliceContainer ;
35+ use crate :: untyped_array:: PyUntypedArray ;
3436
3537/// A safe, statically-typed wrapper for NumPy's [`ndarray`][ndarray] class.
3638///
@@ -135,93 +137,64 @@ unsafe impl<T: Element, D: Dimension> PyTypeInfo for PyArray<T, D> {
135137 }
136138}
137139
138- pyobject_native_type_named ! ( PyArray <T , D >; T ; D ) ;
140+ pyobject_native_type_base ! ( PyArray <T , D >; T ; D ) ;
139141
140- impl < T , D > IntoPy < PyObject > for PyArray < T , D > {
141- fn into_py ( self , py : Python < ' _ > ) -> PyObject {
142- unsafe { PyObject :: from_borrowed_ptr ( py, self . as_ptr ( ) ) }
142+ impl < T , D > AsRef < PyAny > for PyArray < T , D > {
143+ #[ inline]
144+ fn as_ref ( & self ) -> & PyAny {
145+ & self . 0
143146 }
144147}
145148
146- impl < ' py , T : Element , D : Dimension > FromPyObject < ' py > for & ' py PyArray < T , D > {
147- fn extract ( ob : & ' py PyAny ) -> PyResult < Self > {
148- PyArray :: extract ( ob)
149+ impl < T , D > Deref for PyArray < T , D > {
150+ type Target = PyUntypedArray ;
151+
152+ #[ inline]
153+ fn deref ( & self ) -> & Self :: Target {
154+ unsafe { & * ( self as * const Self as * const PyUntypedArray ) }
149155 }
150156}
151157
152- impl < T , D > PyArray < T , D > {
153- /// Returns a raw pointer to the underlying [`PyArrayObject`][npyffi::PyArrayObject].
158+ impl < T , D > AsPyPointer for PyArray < T , D > {
154159 #[ inline]
155- pub fn as_array_ptr ( & self ) -> * mut npyffi :: PyArrayObject {
156- self . as_ptr ( ) as _
160+ fn as_ptr ( & self ) -> * mut ffi :: PyObject {
161+ self . 0 . as_ptr ( )
157162 }
163+ }
158164
159- /// Returns the `dtype` of the array.
160- ///
161- /// See also [`ndarray.dtype`][ndarray-dtype] and [`PyArray_DTYPE`][PyArray_DTYPE].
162- ///
163- /// # Example
164- ///
165- /// ```
166- /// use numpy::{dtype, PyArray};
167- /// use pyo3::Python;
168- ///
169- /// Python::with_gil(|py| {
170- /// let array = PyArray::from_vec(py, vec![1_i32, 2, 3]);
171- ///
172- /// assert!(array.dtype().is_equiv_to(dtype::<i32>(py)));
173- /// });
174- /// ```
175- ///
176- /// [ndarray-dtype]: https://numpy.org/doc/stable/reference/generated/numpy.ndarray.dtype.html
177- /// [PyArray_DTYPE]: https://numpy.org/doc/stable/reference/c-api/array.html#c.PyArray_DTYPE
178- pub fn dtype ( & self ) -> & PyArrayDescr {
179- unsafe {
180- let descr_ptr = ( * self . as_array_ptr ( ) ) . descr ;
181- self . py ( ) . from_borrowed_ptr ( descr_ptr as _ )
182- }
165+ impl < T , D > IntoPy < Py < PyArray < T , D > > > for & ' _ PyArray < T , D > {
166+ #[ inline]
167+ fn into_py ( self , py : Python < ' _ > ) -> Py < PyArray < T , D > > {
168+ unsafe { Py :: from_borrowed_ptr ( py, self . as_ptr ( ) ) }
183169 }
170+ }
184171
185- #[ inline( always) ]
186- pub ( crate ) fn check_flags ( & self , flags : c_int ) -> bool {
187- unsafe { ( * self . as_array_ptr ( ) ) . flags & flags != 0 }
172+ impl < T , D > From < & ' _ PyArray < T , D > > for Py < PyArray < T , D > > {
173+ #[ inline]
174+ fn from ( other : & PyArray < T , D > ) -> Self {
175+ unsafe { Py :: from_borrowed_ptr ( other. py ( ) , other. as_ptr ( ) ) }
188176 }
177+ }
189178
190- /// Returns `true` if the internal data of the array is contiguous,
191- /// indepedently of whether C-style/row-major or Fortran-style/column-major.
192- ///
193- /// # Example
194- ///
195- /// ```
196- /// use numpy::PyArray1;
197- /// use pyo3::{types::IntoPyDict, Python};
198- ///
199- /// Python::with_gil(|py| {
200- /// let array = PyArray1::arange(py, 0, 10, 1);
201- /// assert!(array.is_contiguous());
202- ///
203- /// let view = py
204- /// .eval("array[::2]", None, Some([("array", array)].into_py_dict(py)))
205- /// .unwrap()
206- /// .downcast::<PyArray1<i32>>()
207- /// .unwrap();
208- /// assert!(!view.is_contiguous());
209- /// });
210- /// ```
211- pub fn is_contiguous ( & self ) -> bool {
212- self . check_flags ( npyffi:: NPY_ARRAY_C_CONTIGUOUS | npyffi:: NPY_ARRAY_F_CONTIGUOUS )
179+ impl < ' a , T , D > From < & ' a PyArray < T , D > > for & ' a PyAny {
180+ fn from ( ob : & ' a PyArray < T , D > ) -> Self {
181+ unsafe { & * ( ob as * const PyArray < T , D > as * const PyAny ) }
213182 }
183+ }
214184
215- /// Returns `true` if the internal data of the array is Fortran-style/column-major contiguous.
216- pub fn is_fortran_contiguous ( & self ) -> bool {
217- self . check_flags ( npyffi :: NPY_ARRAY_F_CONTIGUOUS )
185+ impl < T , D > IntoPy < PyObject > for PyArray < T , D > {
186+ fn into_py ( self , py : Python < ' _ > ) -> PyObject {
187+ unsafe { PyObject :: from_borrowed_ptr ( py , self . as_ptr ( ) ) }
218188 }
189+ }
219190
220- /// Returns `true` if the internal data of the array is C-style/row-major contiguous.
221- pub fn is_c_contiguous ( & self ) -> bool {
222- self . check_flags ( npyffi :: NPY_ARRAY_C_CONTIGUOUS )
191+ impl < ' py , T : Element , D : Dimension > FromPyObject < ' py > for & ' py PyArray < T , D > {
192+ fn extract ( ob : & ' py PyAny ) -> PyResult < Self > {
193+ PyArray :: extract ( ob )
223194 }
195+ }
224196
197+ impl < T , D > PyArray < T , D > {
225198 /// Turn `&PyArray<T,D>` into `Py<PyArray<T,D>>`,
226199 /// i.e. a pointer into Python's heap which is independent of the GIL lifetime.
227200 ///
@@ -264,105 +237,6 @@ impl<T, D> PyArray<T, D> {
264237 py. from_borrowed_ptr ( ptr)
265238 }
266239
267- /// Returns the number of dimensions of the array.
268- ///
269- /// See also [`ndarray.ndim`][ndarray-ndim] and [`PyArray_NDIM`][PyArray_NDIM].
270- ///
271- /// # Example
272- ///
273- /// ```
274- /// use numpy::PyArray3;
275- /// use pyo3::Python;
276- ///
277- /// Python::with_gil(|py| {
278- /// let arr = PyArray3::<f64>::zeros(py, [4, 5, 6], false);
279- ///
280- /// assert_eq!(arr.ndim(), 3);
281- /// });
282- /// ```
283- ///
284- /// [ndarray-ndim]: https://numpy.org/doc/stable/reference/generated/numpy.ndarray.ndim.html
285- /// [PyArray_NDIM]: https://numpy.org/doc/stable/reference/c-api/array.html#c.PyArray_NDIM
286- #[ inline]
287- pub fn ndim ( & self ) -> usize {
288- unsafe { ( * self . as_array_ptr ( ) ) . nd as usize }
289- }
290-
291- /// Returns a slice indicating how many bytes to advance when iterating along each axis.
292- ///
293- /// See also [`ndarray.strides`][ndarray-strides] and [`PyArray_STRIDES`][PyArray_STRIDES].
294- ///
295- /// # Example
296- ///
297- /// ```
298- /// use numpy::PyArray3;
299- /// use pyo3::Python;
300- ///
301- /// Python::with_gil(|py| {
302- /// let arr = PyArray3::<f64>::zeros(py, [4, 5, 6], false);
303- ///
304- /// assert_eq!(arr.strides(), &[240, 48, 8]);
305- /// });
306- /// ```
307- /// [ndarray-strides]: https://numpy.org/doc/stable/reference/generated/numpy.ndarray.strides.html
308- /// [PyArray_STRIDES]: https://numpy.org/doc/stable/reference/c-api/array.html#c.PyArray_STRIDES
309- #[ inline]
310- pub fn strides ( & self ) -> & [ isize ] {
311- let n = self . ndim ( ) ;
312- if n == 0 {
313- cold ( ) ;
314- return & [ ] ;
315- }
316- let ptr = self . as_array_ptr ( ) ;
317- unsafe {
318- let p = ( * ptr) . strides ;
319- slice:: from_raw_parts ( p, n)
320- }
321- }
322-
323- /// Returns a slice which contains dimmensions of the array.
324- ///
325- /// See also [`ndarray.shape`][ndaray-shape] and [`PyArray_DIMS`][PyArray_DIMS].
326- ///
327- /// # Example
328- ///
329- /// ```
330- /// use numpy::PyArray3;
331- /// use pyo3::Python;
332- ///
333- /// Python::with_gil(|py| {
334- /// let arr = PyArray3::<f64>::zeros(py, [4, 5, 6], false);
335- ///
336- /// assert_eq!(arr.shape(), &[4, 5, 6]);
337- /// });
338- /// ```
339- ///
340- /// [ndarray-shape]: https://numpy.org/doc/stable/reference/generated/numpy.ndarray.shape.html
341- /// [PyArray_DIMS]: https://numpy.org/doc/stable/reference/c-api/array.html#c.PyArray_DIMS
342- #[ inline]
343- pub fn shape ( & self ) -> & [ usize ] {
344- let n = self . ndim ( ) ;
345- if n == 0 {
346- cold ( ) ;
347- return & [ ] ;
348- }
349- let ptr = self . as_array_ptr ( ) ;
350- unsafe {
351- let p = ( * ptr) . dimensions as * mut usize ;
352- slice:: from_raw_parts ( p, n)
353- }
354- }
355-
356- /// Calculates the total number of elements in the array.
357- pub fn len ( & self ) -> usize {
358- self . shape ( ) . iter ( ) . product ( )
359- }
360-
361- /// Returns `true` if the there are no elements in the array.
362- pub fn is_empty ( & self ) -> bool {
363- self . shape ( ) . iter ( ) . any ( |dim| * dim == 0 )
364- }
365-
366240 /// Returns a pointer to the first element of the array.
367241 #[ inline( always) ]
368242 pub fn data ( & self ) -> * mut T {
@@ -401,7 +275,7 @@ impl<T: Element, D: Dimension> PyArray<T, D> {
401275 Ok ( array)
402276 }
403277
404- /// Same as [`shape`][Self ::shape], but returns `D` insead of `&[usize]`.
278+ /// Same as [`shape`][PyUntypedArray ::shape], but returns `D` insead of `&[usize]`.
405279 #[ inline( always) ]
406280 pub fn dims ( & self ) -> D {
407281 D :: from_dimension ( & Dim ( self . shape ( ) ) ) . expect ( DIMENSIONALITY_MISMATCH_ERR )
@@ -1499,7 +1373,7 @@ impl<T: Element, D> PyArray<T, D> {
14991373
15001374 /// Extends or truncates the dimensions of an array.
15011375 ///
1502- /// This method works only on [contiguous][`Self ::is_contiguous` ] arrays.
1376+ /// This method works only on [contiguous][PyUntypedArray ::is_contiguous] arrays.
15031377 /// Missing elements will be initialized as if calling [`zeros`][Self::zeros].
15041378 ///
15051379 /// See also [`ndarray.resize`][ndarray-resize] and [`PyArray_Resize`][PyArray_Resize].
0 commit comments