@@ -9,21 +9,30 @@ use std::mem;
99use std:: os:: raw:: c_int;
1010use std:: ptr;
1111
12- use convert:: { NpyIndex , ToNpyDims } ;
12+ use convert:: { IntoPyArray , NpyIndex , ToNpyDims , ToPyArray } ;
1313use error:: { ErrorKind , IntoPyResult } ;
14+ use slice_box:: SliceBox ;
1415use types:: { NpyDataType , TypeNum } ;
1516
1617/// A safe, static-typed interface for
1718/// [NumPy ndarray](https://docs.scipy.org/doc/numpy/reference/arrays.ndarray.html).
1819///
1920/// # Memory location
20- /// Numpy api allows to use a memory area allocated outside Pyhton.
2121///
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`
2424///
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.
2736///
2837/// # Reference
2938///
@@ -32,11 +41,6 @@ use types::{NpyDataType, TypeNum};
3241/// See [pyo3's document](https://pyo3.rs/master/doc/pyo3/index.html#ownership-and-lifetimes)
3342/// for the reason.
3443///
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.
4044///
4145/// # Dimension
4246/// `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> {
264268 let ptr = self . as_array_ptr ( ) ;
265269 ( * ptr) . data as * mut T
266270 }
271+
272+ pub ( crate ) unsafe fn copy_ptr ( & self , other : * const T , len : usize ) {
273+ ptr:: copy_nonoverlapping ( other, self . data ( ) , len)
274+ }
267275}
268276
269277impl < T : TypeNum , D : Dimension > PyArray < T , D > {
@@ -305,7 +313,7 @@ impl<T: TypeNum, D: Dimension> PyArray<T, D> {
305313 unsafe { PyArray :: new_ ( py, dims, ptr:: null_mut ( ) , flags) }
306314 }
307315
308- unsafe fn new_ < ' py , ID > (
316+ pub ( crate ) unsafe fn new_ < ' py , ID > (
309317 py : Python < ' py > ,
310318 dims : ID ,
311319 strides : * mut npy_intp ,
@@ -329,6 +337,32 @@ impl<T: TypeNum, D: Dimension> PyArray<T, D> {
329337 Self :: from_owned_ptr ( py, ptr)
330338 }
331339
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+
332366 /// Construct a new nd-dimensional array filled with 0.
333367 ///
334368 /// If `is_fortran` is true, then
@@ -362,7 +396,7 @@ impl<T: TypeNum, D: Dimension> PyArray<T, D> {
362396 }
363397 }
364398
365- /// Construct PyArray from ndarray::Array .
399+ /// Construct PyArray from ` ndarray::ArrayBase` .
366400 ///
367401 /// This method allocates memory in Python's heap via numpy api, and then copies all elements
368402 /// of the array there.
@@ -372,25 +406,32 @@ impl<T: TypeNum, D: Dimension> PyArray<T, D> {
372406 /// # extern crate pyo3; extern crate numpy; #[macro_use] extern crate ndarray; fn main() {
373407 /// use numpy::PyArray;
374408 /// 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]]);
376410 /// assert_eq!(pyarray.as_array().unwrap(), array![[1, 2], [3, 4]]);
377411 /// # }
378412 /// ```
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
380414 where
381415 S : Data < Elem = T > ,
382416 {
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)
394435 }
395436
396437 /// Get the immutable view of the internal data of `PyArray`, as `ndarray::ArrayView`.
@@ -539,12 +580,27 @@ impl<T: TypeNum> PyArray<T, Ix1> {
539580 pub fn from_slice < ' py > ( py : Python < ' py > , slice : & [ T ] ) -> & ' py Self {
540581 let array = PyArray :: new ( py, [ slice. len ( ) ] , false ) ;
541582 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 ( ) ) ;
544584 }
545585 array
546586 }
547587
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+
548604 /// Construct one-dimension PyArray from `impl ExactSizeIterator`.
549605 ///
550606 /// # Example
@@ -584,8 +640,7 @@ impl<T: TypeNum> PyArray<T, Ix1> {
584640 /// # }
585641 /// ```
586642 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 > ( ) ;
589644 let array = Self :: new ( py, [ capacity] , false ) ;
590645 let mut length = 0 ;
591646 unsafe {
@@ -882,35 +937,6 @@ impl<T: TypeNum, D> PyArray<T, D> {
882937 }
883938}
884939
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-
914940impl < T : TypeNum + AsPrimitive < f64 > > PyArray < T , Ix1 > {
915941 /// Return evenly spaced values within a given interval.
916942 /// Same as [numpy.arange](https://docs.scipy.org/doc/numpy/reference/generated/numpy.arange.html).
0 commit comments