Skip to content

Commit b1bd336

Browse files
committed
Switch constructors for one-dimensional arrays to collect Rust-side data structures which then back the NumPy arrays as base objects.
1 parent e4c32d4 commit b1bd336

File tree

2 files changed

+18
-83
lines changed

2 files changed

+18
-83
lines changed

src/array.rs

Lines changed: 6 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -952,18 +952,8 @@ impl<T: Element> PyArray<T, Ix1> {
952952
/// });
953953
/// ```
954954
pub fn from_slice<'py>(py: Python<'py>, slice: &[T]) -> &'py Self {
955-
unsafe {
956-
let array = PyArray::new(py, [slice.len()], false);
957-
if T::IS_COPY {
958-
ptr::copy_nonoverlapping(slice.as_ptr(), array.data(), slice.len());
959-
} else {
960-
let data_ptr = array.data();
961-
for (i, item) in slice.iter().enumerate() {
962-
data_ptr.add(i).write(item.clone());
963-
}
964-
}
965-
array
966-
}
955+
let data = slice.to_vec();
956+
data.into_pyarray(py)
967957
}
968958

969959
/// Construct one-dimension PyArray
@@ -996,20 +986,8 @@ impl<T: Element> PyArray<T, Ix1> {
996986
/// });
997987
/// ```
998988
pub fn from_exact_iter(py: Python<'_>, iter: impl ExactSizeIterator<Item = T>) -> &Self {
999-
// NumPy will always zero-initialize object pointers,
1000-
// so the array can be dropped safely if the iterator panics.
1001-
unsafe {
1002-
let len = iter.len();
1003-
let array = Self::new(py, [len], false);
1004-
let mut idx = 0;
1005-
for item in iter {
1006-
assert!(idx < len);
1007-
array.uget_raw([idx]).write(item);
1008-
idx += 1;
1009-
}
1010-
assert!(idx == len);
1011-
array
1012-
}
989+
let data = iter.collect::<Box<[_]>>();
990+
data.into_pyarray(py)
1013991
}
1014992

1015993
/// Construct one-dimension PyArray from a type which implements
@@ -1028,29 +1006,8 @@ impl<T: Element> PyArray<T, Ix1> {
10281006
/// });
10291007
/// ```
10301008
pub fn from_iter(py: Python<'_>, iter: impl IntoIterator<Item = T>) -> &Self {
1031-
let iter = iter.into_iter();
1032-
let (min_len, max_len) = iter.size_hint();
1033-
let mut capacity = max_len.unwrap_or_else(|| min_len.max(512 / mem::size_of::<T>()));
1034-
unsafe {
1035-
// NumPy will always zero-initialize object pointers,
1036-
// so the array can be dropped safely if the iterator panics.
1037-
let array = Self::new(py, [capacity], false);
1038-
let mut length = 0;
1039-
for (i, item) in iter.enumerate() {
1040-
length += 1;
1041-
if length > capacity {
1042-
capacity *= 2;
1043-
array
1044-
.resize(capacity)
1045-
.expect("PyArray::from_iter: Failed to allocate memory");
1046-
}
1047-
array.uget_raw([i]).write(item);
1048-
}
1049-
if capacity > length {
1050-
array.resize(length).unwrap()
1051-
}
1052-
array
1053-
}
1009+
let data = iter.into_iter().collect::<Vec<_>>();
1010+
data.into_pyarray(py)
10541011
}
10551012

10561013
/// Extends or trancates the length of 1 dimension PyArray.
@@ -1335,8 +1292,6 @@ impl<T: Element + AsPrimitive<f64>> PyArray<T, Ix1> {
13351292
mod tests {
13361293
use super::*;
13371294

1338-
use std::ops::Range;
1339-
13401295
#[test]
13411296
fn test_get_unchecked() {
13421297
pyo3::Python::with_gil(|py| {
@@ -1366,36 +1321,4 @@ mod tests {
13661321
py_run!(py, arr, "assert arr.dtype.hasobject");
13671322
});
13681323
}
1369-
1370-
struct InsincereIterator(Range<usize>, usize);
1371-
1372-
impl Iterator for InsincereIterator {
1373-
type Item = usize;
1374-
1375-
fn next(&mut self) -> Option<Self::Item> {
1376-
self.0.next()
1377-
}
1378-
}
1379-
1380-
impl ExactSizeIterator for InsincereIterator {
1381-
fn len(&self) -> usize {
1382-
self.1
1383-
}
1384-
}
1385-
1386-
#[test]
1387-
#[should_panic]
1388-
fn from_exact_iter_too_short() {
1389-
Python::with_gil(|py| {
1390-
PyArray::from_exact_iter(py, InsincereIterator(0..3, 5));
1391-
});
1392-
}
1393-
1394-
#[test]
1395-
#[should_panic]
1396-
fn from_exact_iter_too_long() {
1397-
Python::with_gil(|py| {
1398-
PyArray::from_exact_iter(py, InsincereIterator(0..5, 3));
1399-
});
1400-
}
14011324
}

tests/to_py.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,18 @@ fn long_iter_to_pyarray() {
6262
});
6363
}
6464

65+
#[test]
66+
fn exact_iter_to_pyarray() {
67+
Python::with_gil(|py| {
68+
let arr = PyArray::from_exact_iter(py, 0_u32..512);
69+
70+
assert_eq!(
71+
arr.readonly().as_slice().unwrap(),
72+
(0_u32..512).collect::<Vec<_>>(),
73+
);
74+
});
75+
}
76+
6577
#[test]
6678
fn from_small_array() {
6779
macro_rules! small_array_test {

0 commit comments

Comments
 (0)