5
5
use std:: {
6
6
marker:: PhantomData ,
7
7
mem,
8
+ ops:: Deref ,
8
9
os:: raw:: { c_int, c_void} ,
9
10
ptr, slice,
10
11
} ;
@@ -16,21 +17,22 @@ use ndarray::{
16
17
} ;
17
18
use num_traits:: AsPrimitive ;
18
19
use 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 ,
20
21
PyClassInitializer , PyDowncastError , PyErr , PyNativeType , PyObject , PyResult , PyTypeInfo ,
21
22
Python , ToPyObject ,
22
23
} ;
23
24
24
25
use crate :: borrow:: { PyReadonlyArray , PyReadwriteArray } ;
25
26
use crate :: cold;
26
27
use crate :: convert:: { ArrayExt , IntoPyArray , NpyIndex , ToNpyDims , ToPyArray } ;
27
- use crate :: dtype:: { Element , PyArrayDescr } ;
28
+ use crate :: dtype:: Element ;
28
29
use crate :: error:: {
29
30
BorrowError , DimensionalityError , FromVecError , IgnoreError , NotContiguousError , TypeError ,
30
31
DIMENSIONALITY_MISMATCH_ERR , MAX_DIMENSIONALITY_ERR ,
31
32
} ;
32
33
use crate :: npyffi:: { self , npy_intp, NPY_ORDER , PY_ARRAY_API } ;
33
34
use crate :: slice_container:: PySliceContainer ;
35
+ use crate :: untyped_array:: PyUntypedArray ;
34
36
35
37
/// A safe, statically-typed wrapper for NumPy's [`ndarray`][ndarray] class.
36
38
///
@@ -135,93 +137,64 @@ unsafe impl<T: Element, D: Dimension> PyTypeInfo for PyArray<T, D> {
135
137
}
136
138
}
137
139
138
- pyobject_native_type_named ! ( PyArray <T , D >; T ; D ) ;
140
+ pyobject_native_type_base ! ( PyArray <T , D >; T ; D ) ;
139
141
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
143
146
}
144
147
}
145
148
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 ) }
149
155
}
150
156
}
151
157
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 > {
154
159
#[ 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 ( )
157
162
}
163
+ }
158
164
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 ( ) ) }
183
169
}
170
+ }
184
171
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 ( ) ) }
188
176
}
177
+ }
189
178
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 ) }
213
182
}
183
+ }
214
184
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 ( ) ) }
218
188
}
189
+ }
219
190
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 )
223
194
}
195
+ }
224
196
197
+ impl < T , D > PyArray < T , D > {
225
198
/// Turn `&PyArray<T,D>` into `Py<PyArray<T,D>>`,
226
199
/// i.e. a pointer into Python's heap which is independent of the GIL lifetime.
227
200
///
@@ -264,105 +237,6 @@ impl<T, D> PyArray<T, D> {
264
237
py. from_borrowed_ptr ( ptr)
265
238
}
266
239
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
-
366
240
/// Returns a pointer to the first element of the array.
367
241
#[ inline( always) ]
368
242
pub fn data ( & self ) -> * mut T {
@@ -401,7 +275,7 @@ impl<T: Element, D: Dimension> PyArray<T, D> {
401
275
Ok ( array)
402
276
}
403
277
404
- /// Same as [`shape`][Self ::shape], but returns `D` insead of `&[usize]`.
278
+ /// Same as [`shape`][PyUntypedArray ::shape], but returns `D` insead of `&[usize]`.
405
279
#[ inline( always) ]
406
280
pub fn dims ( & self ) -> D {
407
281
D :: from_dimension ( & Dim ( self . shape ( ) ) ) . expect ( DIMENSIONALITY_MISMATCH_ERR )
@@ -1499,7 +1373,7 @@ impl<T: Element, D> PyArray<T, D> {
1499
1373
1500
1374
/// Extends or truncates the dimensions of an array.
1501
1375
///
1502
- /// This method works only on [contiguous][`Self ::is_contiguous` ] arrays.
1376
+ /// This method works only on [contiguous][PyUntypedArray ::is_contiguous] arrays.
1503
1377
/// Missing elements will be initialized as if calling [`zeros`][Self::zeros].
1504
1378
///
1505
1379
/// See also [`ndarray.resize`][ndarray-resize] and [`PyArray_Resize`][PyArray_Resize].
0 commit comments