@@ -77,19 +77,19 @@ use crate::types::Element;
77
77
/// ```
78
78
pub struct PyArray < T , D > ( PyAny , PhantomData < T > , PhantomData < D > ) ;
79
79
80
- /// one -dimensional array
80
+ /// One -dimensional array.
81
81
pub type PyArray1 < T > = PyArray < T , Ix1 > ;
82
- /// two -dimensional array
82
+ /// Two -dimensional array.
83
83
pub type PyArray2 < T > = PyArray < T , Ix2 > ;
84
- /// three -dimensional array
84
+ /// Three -dimensional array.
85
85
pub type PyArray3 < T > = PyArray < T , Ix3 > ;
86
- /// four -dimensional array
86
+ /// Four -dimensional array.
87
87
pub type PyArray4 < T > = PyArray < T , Ix4 > ;
88
- /// five -dimensional array
88
+ /// Five -dimensional array.
89
89
pub type PyArray5 < T > = PyArray < T , Ix5 > ;
90
- /// six -dimensional array
90
+ /// Six -dimensional array.
91
91
pub type PyArray6 < T > = PyArray < T , Ix6 > ;
92
- /// dynamic -dimensional array
92
+ /// Dynamic -dimensional array.
93
93
pub type PyArrayDyn < T > = PyArray < T , IxDyn > ;
94
94
95
95
/// Returns a array module.
@@ -117,6 +117,12 @@ impl<'a, T, D> std::convert::From<&'a PyArray<T, D>> for &'a PyAny {
117
117
}
118
118
}
119
119
120
+ impl < T , D > IntoPy < PyObject > for PyArray < T , D > {
121
+ fn into_py ( self , py : Python < ' _ > ) -> PyObject {
122
+ unsafe { PyObject :: from_borrowed_ptr ( py, self . as_ptr ( ) ) }
123
+ }
124
+ }
125
+
120
126
impl < ' a , T : Element , D : Dimension > FromPyObject < ' a > for & ' a PyArray < T , D > {
121
127
// here we do type-check three times
122
128
// 1. Checks if the object is PyArray
@@ -129,14 +135,13 @@ impl<'a, T: Element, D: Dimension> FromPyObject<'a> for &'a PyArray<T, D> {
129
135
}
130
136
& * ( ob as * const PyAny as * const PyArray < T , D > )
131
137
} ;
132
- array. type_check ( ) ?;
133
- Ok ( array)
134
- }
135
- }
136
-
137
- impl < T , D > IntoPy < PyObject > for PyArray < T , D > {
138
- fn into_py ( self , py : Python < ' _ > ) -> PyObject {
139
- unsafe { PyObject :: from_borrowed_ptr ( py, self . as_ptr ( ) ) }
138
+ let type_ = unsafe { ( * ( * array. as_array_ptr ( ) ) . descr ) . type_num } ;
139
+ let dim = array. shape ( ) . len ( ) ;
140
+ if T :: is_same_type ( type_) && D :: NDIM . map ( |n| n == dim) . unwrap_or ( true ) {
141
+ Ok ( array)
142
+ } else {
143
+ Err ( ShapeError :: new ( type_, dim, T :: DATA_TYPE , D :: NDIM ) . into ( ) )
144
+ }
140
145
}
141
146
}
142
147
@@ -435,8 +440,10 @@ impl<T: Element, D: Dimension> PyArray<T, D> {
435
440
}
436
441
437
442
/// Returns the immutable view of the internal data of `PyArray` as slice.
438
- /// Please consider the use of [`PyReadonlyArray::as_slice`](../struct.PyReadonlyArray.html)
439
- /// instead of this.
443
+ ///
444
+ /// Please consider the use of safe alternatives
445
+ /// ([`PyReadonlyArray::as_slice`](../struct.PyReadonlyArray.html#method.as_slice)
446
+ /// , [`as_cell_slice`](#method.as_cell_slice) or [`to_vec`](#method.to_vec)) instead of this.
440
447
///
441
448
/// # Safety
442
449
/// If the internal array is not readonly and can be mutated from Python code,
@@ -491,47 +498,22 @@ impl<T: Element, D: Dimension> PyArray<T, D> {
491
498
IntoPyArray :: into_pyarray ( arr, py)
492
499
}
493
500
494
- /// Get an immutable reference of a specified element, with checking the passed index is valid.
501
+ /// Get the immutable reference of the specified element, with checking the passed index is valid.
495
502
///
496
- /// See [NpyIndex](../convert/trait.NpyIndex.html) for what types you can use as index.
497
- ///
498
- /// If you pass an invalid index to this function, it returns `None` .
503
+ /// Please consider the use of safe alternatives
504
+ /// ([`PyReadonlyArray::get`](../struct.PyReadonlyArray.html#method.get)
505
+ /// or [`get_owned`](#method.get_owned)) instead of this.
499
506
///
500
- /// # Example
501
- /// ```
502
- /// use numpy::PyArray;
503
- /// let gil = pyo3::Python::acquire_gil();
504
- /// let arr = PyArray::arange(gil.python(), 0, 16, 1).reshape([2, 2, 4]).unwrap();
505
- /// assert_eq!(*arr.get([1, 0, 3]).unwrap(), 11);
506
- /// assert!(arr.get([2, 0, 3]).is_none());
507
- /// ```
508
- ///
509
- /// For fixed dimension arrays, passing an index with invalid dimension causes compile error.
510
- /// ```compile_fail
511
- /// use numpy::PyArray;
512
- /// let gil = pyo3::Python::acquire_gil();
513
- /// let arr = PyArray::arange(gil.python(), 0, 16, 1).reshape([2, 2, 4]).unwrap();
514
- /// let a = arr.get([1, 2]); // Compile Error!
515
- /// ```
516
- ///
517
- /// However, for dinamic arrays, we cannot raise a compile error and just returns `None`.
518
- /// ```
519
- /// use numpy::PyArray;
520
- /// let gil = pyo3::Python::acquire_gil();
521
- /// let arr = PyArray::arange(gil.python(), 0, 16, 1).reshape([2, 2, 4]).unwrap();
522
- /// let arr = arr.to_dyn();
523
- /// assert!(arr.get([1, 2].as_ref()).is_none());
524
- /// ```
507
+ /// # Safety
508
+ /// If the internal array is not readonly and can be mutated from Python code,
509
+ /// holding the slice might cause undefined behavior.
525
510
#[ inline( always) ]
526
- pub fn get < Idx > ( & self , index : Idx ) -> Option < & T >
527
- where
528
- Idx : NpyIndex < Dim = D > ,
529
- {
511
+ pub unsafe fn get ( & self , index : impl NpyIndex < Dim = D > ) -> Option < & T > {
530
512
let offset = index. get_checked :: < T > ( self . shape ( ) , self . strides ( ) ) ?;
531
- unsafe { Some ( & * self . data ( ) . offset ( offset) ) }
513
+ Some ( & * self . data ( ) . offset ( offset) )
532
514
}
533
515
534
- /// Get an immutable reference of a specified element, without checking the
516
+ /// Get the immutable reference of the specified element, without checking the
535
517
/// passed index is valid.
536
518
///
537
519
/// See [NpyIndex](../convert/trait.NpyIndex.html) for what types you can use as index.
@@ -573,14 +555,26 @@ impl<T: Element, D: Dimension> PyArray<T, D> {
573
555
unsafe { PyArray :: from_borrowed_ptr ( python, self . as_ptr ( ) ) }
574
556
}
575
557
576
- fn type_check ( & self ) -> Result < ( ) , ShapeError > {
577
- let truth = unsafe { ( * ( * self . as_array_ptr ( ) ) . descr ) . type_num } ;
578
- let dim = self . shape ( ) . len ( ) ;
579
- if T :: is_same_type ( truth) && D :: NDIM . map ( |n| n == dim) . unwrap_or ( true ) {
580
- Ok ( ( ) )
581
- } else {
582
- Err ( ShapeError :: new ( truth, dim, T :: DATA_TYPE , D :: NDIM ) )
583
- }
558
+ /// Get the copy of the specified element in the array.
559
+ ///
560
+ /// See [NpyIndex](../convert/trait.NpyIndex.html) for what types you can use as index.
561
+ ///
562
+ /// # Example
563
+ /// ```
564
+ /// use numpy::PyArray2;
565
+ /// use pyo3::types::IntoPyDict;
566
+ /// let gil = pyo3::Python::acquire_gil();
567
+ /// let py = gil.python();
568
+ /// let locals = [("np", numpy::get_array_module(py).unwrap())].into_py_dict(py);
569
+ /// let array: &PyArray2<i64> = py
570
+ /// .eval("np.array([[0, 1], [2, 3]], dtype='int64')", Some(locals), None)
571
+ /// .unwrap()
572
+ /// .downcast()
573
+ /// .unwrap();
574
+ /// assert_eq!(array.to_vec().unwrap(), vec![0, 1, 2, 3]);
575
+ /// ```
576
+ pub fn get_owned ( & self , index : impl NpyIndex < Dim = D > ) -> Option < T > {
577
+ unsafe { self . get ( index) } . cloned ( )
584
578
}
585
579
586
580
/// Returns the copy of the internal data of `PyArray` to `Vec`.
@@ -629,6 +623,10 @@ impl<T: Element, D: Dimension> PyArray<T, D> {
629
623
/// Get the immutable view of the internal data of `PyArray`, as
630
624
/// [`ndarray::ArrayView`](https://docs.rs/ndarray/latest/ndarray/type.ArrayView.html).
631
625
///
626
+ /// Please consider the use of safe alternatives
627
+ /// ([`PyReadonlyArray::as_array`](../struct.PyReadonlyArray.html#method.as_array)
628
+ /// or [`to_array`](#method.to_array)) instead of this.
629
+ ///
632
630
/// # Safety
633
631
/// If the internal array is not readonly and can be mutated from Python code,
634
632
/// holding the `ArrayView` might cause undefined behavior.
0 commit comments