@@ -9,21 +9,30 @@ use std::mem;
9
9
use std:: os:: raw:: c_int;
10
10
use std:: ptr;
11
11
12
- use convert:: { NpyIndex , ToNpyDims } ;
12
+ use convert:: { IntoPyArray , NpyIndex , ToNpyDims , ToPyArray } ;
13
13
use error:: { ErrorKind , IntoPyResult } ;
14
+ use slice_box:: SliceBox ;
14
15
use types:: { NpyDataType , TypeNum } ;
15
16
16
17
/// A safe, static-typed interface for
17
18
/// [NumPy ndarray](https://docs.scipy.org/doc/numpy/reference/arrays.ndarray.html).
18
19
///
19
20
/// # Memory location
20
- /// Numpy api allows to use a memory area allocated outside Pyhton.
21
21
///
22
- /// However, we designed `PyArray` to always **owns a memory area allocated in Python's private
23
- /// heap**, where all memories are managed by GC.
22
+ /// 1. `PyArray` constructed via `IntoPyArray::into_pyarray` or `PyArray::from_vec`
23
+ /// or `PyArray::from_owned_array`
24
24
///
25
- /// This means you always need to pay allocation cost when you create a `PyArray`, but don't need
26
- /// to fear memory leak.
25
+ /// These methods don't allocate and use `Box<[T]>` as container.
26
+ ///
27
+ /// Please take care that **you cannot use some destructive methods like `resize`,
28
+ /// for this kind of array**.
29
+ ///
30
+ /// 2.`PyArray` constructed via other methods, like `ToPyArray::to_pyarray` or `PyArray::from_slice`
31
+ /// or `PyArray::from_array`.
32
+ ///
33
+ /// These methods allocate a memory area in Python's private heap.
34
+ ///
35
+ /// In this case, you have no restriction.
27
36
///
28
37
/// # Reference
29
38
///
@@ -32,11 +41,6 @@ use types::{NpyDataType, TypeNum};
32
41
/// See [pyo3's document](https://pyo3.rs/master/doc/pyo3/index.html#ownership-and-lifetimes)
33
42
/// for the reason.
34
43
///
35
- /// # Mutation
36
- /// You can do destructive changes to `PyArray` via &self methods like [`move_to`](#method.move_to).
37
- ///
38
- /// About this design, see
39
- /// [pyo3's document](https://pyo3.rs/master/doc/pyo3/index.html#ownership-and-lifetimes), too.
40
44
///
41
45
/// # Dimension
42
46
/// `PyArray` has 2 type parametes `T` and `D`. `T` represents its data type like `f32`, and `D`
@@ -264,6 +268,10 @@ impl<T, D> PyArray<T, D> {
264
268
let ptr = self . as_array_ptr ( ) ;
265
269
( * ptr) . data as * mut T
266
270
}
271
+
272
+ pub ( crate ) unsafe fn copy_ptr ( & self , other : * const T , len : usize ) {
273
+ ptr:: copy_nonoverlapping ( other, self . data ( ) , len)
274
+ }
267
275
}
268
276
269
277
impl < T : TypeNum , D : Dimension > PyArray < T , D > {
@@ -305,7 +313,7 @@ impl<T: TypeNum, D: Dimension> PyArray<T, D> {
305
313
unsafe { PyArray :: new_ ( py, dims, ptr:: null_mut ( ) , flags) }
306
314
}
307
315
308
- unsafe fn new_ < ' py , ID > (
316
+ pub ( crate ) unsafe fn new_ < ' py , ID > (
309
317
py : Python < ' py > ,
310
318
dims : ID ,
311
319
strides : * mut npy_intp ,
@@ -329,6 +337,32 @@ impl<T: TypeNum, D: Dimension> PyArray<T, D> {
329
337
Self :: from_owned_ptr ( py, ptr)
330
338
}
331
339
340
+ pub ( crate ) unsafe fn from_boxed_slice < ' py , ID > (
341
+ py : Python < ' py > ,
342
+ dims : ID ,
343
+ strides : * mut npy_intp ,
344
+ slice : Box < [ T ] > ,
345
+ ) -> & ' py Self
346
+ where
347
+ ID : IntoDimension < Dim = D > ,
348
+ {
349
+ let dims = dims. into_dimension ( ) ;
350
+ let slice = SliceBox :: new ( slice) ;
351
+ let ptr = PY_ARRAY_API . PyArray_New (
352
+ PY_ARRAY_API . get_type_object ( npyffi:: ArrayType :: PyArray_Type ) ,
353
+ dims. ndim_cint ( ) ,
354
+ dims. as_dims_ptr ( ) ,
355
+ T :: typenum_default ( ) ,
356
+ strides, // strides
357
+ slice. data ( ) , // data
358
+ 0 , // itemsize
359
+ 0 , // flag
360
+ :: std:: ptr:: null_mut ( ) , //obj
361
+ ) ;
362
+ PY_ARRAY_API . PyArray_SetBaseObject ( ptr as * mut npyffi:: PyArrayObject , slice. as_ptr ( ) ) ;
363
+ Self :: from_owned_ptr ( py, ptr)
364
+ }
365
+
332
366
/// Construct a new nd-dimensional array filled with 0.
333
367
///
334
368
/// If `is_fortran` is true, then
@@ -362,7 +396,7 @@ impl<T: TypeNum, D: Dimension> PyArray<T, D> {
362
396
}
363
397
}
364
398
365
- /// Construct PyArray from ndarray::Array .
399
+ /// Construct PyArray from ` ndarray::ArrayBase` .
366
400
///
367
401
/// This method allocates memory in Python's heap via numpy api, and then copies all elements
368
402
/// of the array there.
@@ -372,25 +406,32 @@ impl<T: TypeNum, D: Dimension> PyArray<T, D> {
372
406
/// # extern crate pyo3; extern crate numpy; #[macro_use] extern crate ndarray; fn main() {
373
407
/// use numpy::PyArray;
374
408
/// let gil = pyo3::Python::acquire_gil();
375
- /// let pyarray = PyArray::from_ndarray (gil.python(), &array![[1, 2], [3, 4]]);
409
+ /// let pyarray = PyArray::from_array (gil.python(), &array![[1, 2], [3, 4]]);
376
410
/// assert_eq!(pyarray.as_array().unwrap(), array![[1, 2], [3, 4]]);
377
411
/// # }
378
412
/// ```
379
- pub fn from_ndarray < ' py , S > ( py : Python < ' py > , arr : & ArrayBase < S , D > ) -> & ' py Self
413
+ pub fn from_array < ' py , S > ( py : Python < ' py > , arr : & ArrayBase < S , D > ) -> & ' py Self
380
414
where
381
415
S : Data < Elem = T > ,
382
416
{
383
- let len = arr. len ( ) ;
384
- let mut strides: Vec < _ > = arr
385
- . strides ( )
386
- . into_iter ( )
387
- . map ( |n| n * mem:: size_of :: < T > ( ) as npy_intp )
388
- . collect ( ) ;
389
- unsafe {
390
- let array = PyArray :: new_ ( py, arr. raw_dim ( ) , strides. as_mut_ptr ( ) as * mut npy_intp , 0 ) ;
391
- ptr:: copy_nonoverlapping ( arr. as_ptr ( ) , array. data ( ) , len) ;
392
- array
393
- }
417
+ ToPyArray :: to_pyarray ( arr, py)
418
+ }
419
+
420
+ /// Construct PyArray from `ndarray::Array`.
421
+ ///
422
+ /// This method uses internal `Vec` of `ndarray::Array` as numpy array.
423
+ ///
424
+ /// # Example
425
+ /// ```
426
+ /// # extern crate pyo3; extern crate numpy; #[macro_use] extern crate ndarray; fn main() {
427
+ /// use numpy::PyArray;
428
+ /// let gil = pyo3::Python::acquire_gil();
429
+ /// let pyarray = PyArray::from_owned_array(gil.python(), array![[1, 2], [3, 4]]);
430
+ /// assert_eq!(pyarray.as_array().unwrap(), array![[1, 2], [3, 4]]);
431
+ /// # }
432
+ /// ```
433
+ pub fn from_owned_array < ' py > ( py : Python < ' py > , arr : Array < T , D > ) -> & ' py Self {
434
+ IntoPyArray :: into_pyarray ( arr, py)
394
435
}
395
436
396
437
/// Get the immutable view of the internal data of `PyArray`, as `ndarray::ArrayView`.
@@ -539,12 +580,27 @@ impl<T: TypeNum> PyArray<T, Ix1> {
539
580
pub fn from_slice < ' py > ( py : Python < ' py > , slice : & [ T ] ) -> & ' py Self {
540
581
let array = PyArray :: new ( py, [ slice. len ( ) ] , false ) ;
541
582
unsafe {
542
- let src = slice. as_ptr ( ) as * mut T ;
543
- ptr:: copy_nonoverlapping ( src, array. data ( ) , slice. len ( ) ) ;
583
+ array. copy_ptr ( slice. as_ptr ( ) , slice. len ( ) ) ;
544
584
}
545
585
array
546
586
}
547
587
588
+ /// Construct one-dimension PyArray from `Vec`.
589
+ ///
590
+ /// # Example
591
+ /// ```
592
+ /// # extern crate pyo3; extern crate numpy; fn main() {
593
+ /// use numpy::PyArray;
594
+ /// let gil = pyo3::Python::acquire_gil();
595
+ /// let vec = vec![1, 2, 3, 4, 5];
596
+ /// let pyarray = PyArray::from_vec(gil.python(), vec);
597
+ /// assert_eq!(pyarray.as_slice().unwrap(), &[1, 2, 3, 4, 5]);
598
+ /// # }
599
+ /// ```
600
+ pub fn from_vec < ' py > ( py : Python < ' py > , vec : Vec < T > ) -> & ' py Self {
601
+ IntoPyArray :: into_pyarray ( vec, py)
602
+ }
603
+
548
604
/// Construct one-dimension PyArray from `impl ExactSizeIterator`.
549
605
///
550
606
/// # Example
@@ -584,8 +640,7 @@ impl<T: TypeNum> PyArray<T, Ix1> {
584
640
/// # }
585
641
/// ```
586
642
pub fn from_iter ( py : Python , iter : impl IntoIterator < Item = T > ) -> & Self {
587
- // ↓ max cached size of ndarray
588
- let mut capacity = 1024 / mem:: size_of :: < T > ( ) ;
643
+ let mut capacity = 512 / mem:: size_of :: < T > ( ) ;
589
644
let array = Self :: new ( py, [ capacity] , false ) ;
590
645
let mut length = 0 ;
591
646
unsafe {
@@ -882,35 +937,6 @@ impl<T: TypeNum, D> PyArray<T, D> {
882
937
}
883
938
}
884
939
885
- impl < T : TypeNum > PyArray < T , IxDyn > {
886
- /// Move the data of self into `other`, performing a data-type conversion if necessary.
887
- ///
888
- /// For type safety, you have to convert `PyArray` to `PyArrayDyn` before using this method.
889
- /// # Example
890
- /// ```
891
- /// # extern crate pyo3; extern crate numpy; fn main() {
892
- /// use numpy::PyArray;
893
- /// let gil = pyo3::Python::acquire_gil();
894
- /// let pyarray_f = PyArray::arange(gil.python(), 2.0, 5.0, 1.0).into_dyn();
895
- /// let pyarray_i = PyArray::<i64, _>::new(gil.python(), [3], false);
896
- /// assert!(pyarray_f.move_to(pyarray_i).is_ok());
897
- /// assert_eq!(pyarray_i.as_slice().unwrap(), &[2, 3, 4]);
898
- /// # }
899
- pub fn move_to < U : TypeNum , D2 : Dimension > (
900
- & self ,
901
- other : & PyArray < U , D2 > ,
902
- ) -> Result < ( ) , ErrorKind > {
903
- let self_ptr = self . as_array_ptr ( ) ;
904
- let other_ptr = other. as_array_ptr ( ) ;
905
- let result = unsafe { PY_ARRAY_API . PyArray_MoveInto ( other_ptr, self_ptr) } ;
906
- if result == -1 {
907
- Err ( ErrorKind :: dtype_cast ( self , U :: npy_data_type ( ) ) )
908
- } else {
909
- Ok ( ( ) )
910
- }
911
- }
912
- }
913
-
914
940
impl < T : TypeNum + AsPrimitive < f64 > > PyArray < T , Ix1 > {
915
941
/// Return evenly spaced values within a given interval.
916
942
/// Same as [numpy.arange](https://docs.scipy.org/doc/numpy/reference/generated/numpy.arange.html).
0 commit comments