Skip to content

Commit 64c43a7

Browse files
committed
Add Some examples to iterators
1 parent 445a484 commit 64c43a7

File tree

5 files changed

+94
-27
lines changed

5 files changed

+94
-27
lines changed

src/array.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ impl<T, D> PyArray<T, D> {
174174
/// use pyo3::types::IntoPyDict;
175175
/// let gil = pyo3::Python::acquire_gil();
176176
/// let py = gil.python();
177-
/// let array = numpy::PyArray::arange(py, 0, 1, 10);
177+
/// let array = numpy::PyArray::arange(py, 0, 10, 1);
178178
/// assert!(array.is_contiguous());
179179
/// let locals = [("np", numpy::get_array_module(py).unwrap())].into_py_dict(py);
180180
/// let not_contiguous: &numpy::PyArray1<f32> = py
@@ -772,6 +772,14 @@ impl<T: Element> PyArray<T, Ix1> {
772772
self.resize_([new_elems], 1, NPY_ORDER::NPY_ANYORDER)
773773
}
774774

775+
/// Iterates all elements of this array.
776+
/// See [NpySingleIter](../npyiter/struct.NpySingleIter.html) for more.
777+
pub fn iter<'py>(
778+
&'py self,
779+
) -> PyResult<crate::NpySingleIter<'py, T, crate::npyiter::ReadWrite>> {
780+
crate::NpySingleIterBuilder::readwrite(self).build()
781+
}
782+
775783
fn resize_<D: IntoDimension>(
776784
&self,
777785
dims: D,

src/error.rs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -115,15 +115,3 @@ impl fmt::Display for NotContiguousError {
115115
}
116116

117117
impl_pyerr!(NotContiguousError);
118-
119-
/// Represents issues in NpyIterator instantiation.
120-
#[derive(Debug)]
121-
pub struct NpyIterInstantiationError;
122-
123-
impl fmt::Display for NpyIterInstantiationError {
124-
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
125-
write!(f, "Unknown error while instantiating NpyIter",)
126-
}
127-
}
128-
129-
impl_pyerr!(NpyIterInstantiationError);

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ pub use crate::convert::{IntoPyArray, NpyIndex, ToNpyDims, ToPyArray};
5353
pub use crate::error::{FromVecError, NotContiguousError, ShapeError};
5454
pub use crate::npyffi::{PY_ARRAY_API, PY_UFUNC_API};
5555
pub use crate::npyiter::{
56-
NpyIterFlag, NpyMultiIter, NpyMultiIterBuilder, NpySingleIter, NpySingleIterBuilder,
56+
IterMode, NpyIterFlag, NpyMultiIter, NpyMultiIterBuilder, NpySingleIter, NpySingleIterBuilder,
5757
};
5858
pub use crate::readonly::{
5959
PyReadonlyArray, PyReadonlyArray1, PyReadonlyArray2, PyReadonlyArray3, PyReadonlyArray4,

src/npyiter.rs

Lines changed: 78 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
//! [NpySingleIter](./struct.NpySingleIter.html) and
55
//! [NpyMultiIter](./struct.NpyMultiIter.html).
66
use crate::array::{PyArray, PyArrayDyn};
7-
use crate::error::NpyIterInstantiationError;
87
use crate::npyffi::{
98
array::PY_ARRAY_API,
109
npy_intp, npy_uint32,
@@ -163,7 +162,7 @@ pub struct NpySingleIterBuilder<'py, T, I: IterMode> {
163162
}
164163

165164
impl<'py, T: Element> NpySingleIterBuilder<'py, T, Readonly> {
166-
/// Make a new builder for a readonly iterator.
165+
/// Makes a new builder for a readonly iterator.
167166
pub fn readonly<D: ndarray::Dimension>(array: PyReadonlyArray<'py, T, D>) -> Self {
168167
let (array, was_writable) = array.destruct();
169168
Self {
@@ -176,7 +175,7 @@ impl<'py, T: Element> NpySingleIterBuilder<'py, T, Readonly> {
176175
}
177176

178177
impl<'py, T: Element> NpySingleIterBuilder<'py, T, ReadWrite> {
179-
/// Make a new builder for a writable iterator.
178+
/// Makes a new builder for a writable iterator.
180179
pub fn readwrite<D: ndarray::Dimension>(array: &'py PyArray<T, D>) -> Self {
181180
Self {
182181
flags: NPY_ITER_READWRITE,
@@ -188,13 +187,13 @@ impl<'py, T: Element> NpySingleIterBuilder<'py, T, ReadWrite> {
188187
}
189188

190189
impl<'py, T: Element, I: IterMode> NpySingleIterBuilder<'py, T, I> {
191-
/// Set a flag to this builder, returning `self`.
190+
/// Sets a flag to this builder, returning `self`.
192191
pub fn set(mut self, flag: NpyIterFlag) -> Self {
193192
self.flags |= flag.to_c_enum();
194193
self
195194
}
196195

197-
/// Create an iterator from this builder.
196+
/// Creates an iterator from this builder.
198197
pub fn build(self) -> PyResult<NpySingleIter<'py, T, I>> {
199198
let array_ptr = self.array.as_array_ptr();
200199
let iter_ptr = unsafe {
@@ -216,11 +215,50 @@ impl<'py, T: Element, I: IterMode> NpySingleIterBuilder<'py, T, I> {
216215
}
217216
}
218217

219-
/// An iterator over a single array.
218+
/// An iterator over a single array, construced by
219+
/// [NpySingleIterBuilder](./struct.NpySingleIterBuilder.html).
220+
/// This iterator iterates all elements in the array as `&mut T` (in case `readwrite` is used)
221+
/// or `&T` (in case `readonly` is used).
220222
///
221223
/// # Example
222224
///
225+
/// You can use
226+
/// [`NpySingleIterBuilder::readwrite`](./struct.NpySingleIterBuilder.html#method.readwrite)
227+
/// to get a mutable iterator.
223228
///
229+
/// ```
230+
/// use numpy::NpySingleIterBuilder;
231+
/// let gil = pyo3::Python::acquire_gil();
232+
/// let py = gil.python();
233+
/// let array = numpy::PyArray::arange(py, 0, 10, 1);
234+
/// let iter = NpySingleIterBuilder::readwrite(array).build().unwrap();
235+
/// for (i, elem) in iter.enumerate() {
236+
/// assert_eq!(*elem, i as i64);
237+
/// *elem = *elem * 2; // elements are mutable
238+
/// }
239+
/// ```
240+
/// Or, as a shorthand, `PyArray::iter` can be also used.
241+
/// ```
242+
/// # use numpy::NpySingleIterBuilder;
243+
/// # let gil = pyo3::Python::acquire_gil();
244+
/// # let py = gil.python();
245+
/// # let array = numpy::PyArray::arange(py, 0, 10, 1);
246+
/// for (i, elem) in array.iter().unwrap().enumerate() {
247+
/// assert_eq!(*elem, i as i64);
248+
/// *elem = *elem * 2; // elements are mutable
249+
/// }
250+
/// ```
251+
/// On the other hand, immutable iterator requires [readonly array](../struct.PyReadonlyArray.html).
252+
/// ```
253+
/// use numpy::NpySingleIterBuilder;
254+
/// let gil = pyo3::Python::acquire_gil();
255+
/// let py = gil.python();
256+
/// let array = numpy::PyArray::arange(py, 0, 1, 10);
257+
/// let iter = NpySingleIterBuilder::readonly(array.readonly()).build().unwrap();
258+
/// for (i, elem) in iter.enumerate() {
259+
/// assert_eq!(*elem, i as i64);
260+
/// }
261+
/// ```
224262
pub struct NpySingleIter<'py, T, I> {
225263
iterator: ptr::NonNull<NpyIter>,
226264
iternext: unsafe extern "C" fn(*mut NpyIter) -> c_int,
@@ -242,7 +280,7 @@ impl<'py, T, I> NpySingleIter<'py, T, I> {
242280
let mut iterator = match ptr::NonNull::new(iterator) {
243281
Some(iter) => iter,
244282
None => {
245-
return Err(NpyIterInstantiationError.into());
283+
return Err(PyErr::fetch(py));
246284
}
247285
};
248286

@@ -257,7 +295,7 @@ impl<'py, T, I> NpySingleIter<'py, T, I> {
257295

258296
if dataptr.is_null() {
259297
unsafe { PY_ARRAY_API.NpyIter_Deallocate(iterator.as_mut()) };
260-
return Err(NpyIterInstantiationError.into());
298+
return Err(PyErr::fetch(py));
261299
}
262300

263301
let iter_size = unsafe { PY_ARRAY_API.NpyIter_GetIterSize(iterator.as_mut()) };
@@ -368,7 +406,7 @@ impl<'py, T: Element, S: MultiIterMode> NpyMultiIterBuilder<'py, T, S> {
368406
}
369407
}
370408

371-
/// Add a writable array to the resulting iterator.
409+
/// Adds a writable array to the resulting iterator.
372410
pub fn add_readwrite<D: ndarray::Dimension>(
373411
mut self,
374412
array: &'py PyArray<T, D>,
@@ -385,7 +423,7 @@ impl<'py, T: Element, S: MultiIterMode> NpyMultiIterBuilder<'py, T, S> {
385423
}
386424

387425
impl<'py, T: Element, S: MultiIterModeWithManyArrays> NpyMultiIterBuilder<'py, T, S> {
388-
/// Create an iterator from this builder.
426+
/// Creates an iterator from this builder.
389427
pub fn build(self) -> PyResult<NpyMultiIter<'py, T, S>> {
390428
let Self {
391429
flags,
@@ -419,7 +457,34 @@ impl<'py, T: Element, S: MultiIterModeWithManyArrays> NpyMultiIterBuilder<'py, T
419457
}
420458
}
421459

422-
/// Multi iterator
460+
/// An iterator over multiple arrays, construced by
461+
/// [NpyMultiIterBuilder](./struct.NpyMultiIterBuilder.html).
462+
/// You can add
463+
/// [`NpyMultiIterBuilder::add_readwrite`](./struct.NpyMultiIterBuilder.html#method.add_readwrite)
464+
/// for adding a mutable component to the iterator, and
465+
/// [`NpyMultiIterBuilder::add_readonly`](./struct.NpyMultiIterBuilder.html#method.add_readonly)
466+
/// for adding a immutable one.
467+
///
468+
/// # Example
469+
///
470+
/// ```
471+
/// use numpy::NpyMultiIterBuilder;
472+
/// let gil = pyo3::Python::acquire_gil();
473+
/// let py = gil.python();
474+
/// let array1 = numpy::PyArray::arange(py, 0, 10, 1);
475+
/// let array2 = numpy::PyArray::arange(py, 10, 20, 1);
476+
/// let array3 = numpy::PyArray::arange(py, 10, 30, 2);
477+
/// let iter = NpyMultiIterBuilder::new()
478+
/// .add_readonly(array1.readonly())
479+
/// .add_readwrite(array2)
480+
/// .add_readonly(array3.readonly())
481+
/// .build()
482+
/// .unwrap();
483+
/// for (i, j, k) in iter {
484+
/// assert_eq!(*i + *j, *k);
485+
/// *j += *i + *k; // The third element is only mutable.
486+
/// }
487+
/// ```
423488
pub struct NpyMultiIter<'py, T, S: MultiIterModeWithManyArrays> {
424489
iterator: ptr::NonNull<NpyIter>,
425490
iternext: unsafe extern "C" fn(*mut NpyIter) -> c_int,
@@ -442,7 +507,7 @@ impl<'py, T, S: MultiIterModeWithManyArrays> NpyMultiIter<'py, T, S> {
442507
let mut iterator = match ptr::NonNull::new(iterator) {
443508
Some(ptr) => ptr,
444509
None => {
445-
return Err(NpyIterInstantiationError.into());
510+
return Err(PyErr::fetch(py));
446511
}
447512
};
448513

@@ -457,7 +522,7 @@ impl<'py, T, S: MultiIterModeWithManyArrays> NpyMultiIter<'py, T, S> {
457522

458523
if dataptr.is_null() {
459524
unsafe { PY_ARRAY_API.NpyIter_Deallocate(iterator.as_mut()) };
460-
return Err(NpyIterInstantiationError.into());
525+
return Err(PyErr::fetch(py));
461526
}
462527

463528
let iter_size = unsafe { PY_ARRAY_API.NpyIter_GetIterSize(iterator.as_mut()) };

src/readonly.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,12 @@ impl<'py, T: Element, D: Dimension> PyReadonlyArray<'py, T, D> {
130130
unsafe { self.array.get(index) }
131131
}
132132

133+
/// Iterates all elements of this array.
134+
/// See [NpySingleIter](../npyiter/struct.NpySingleIter.html) for more.
135+
pub fn iter(self) -> PyResult<crate::NpySingleIter<'py, T, crate::npyiter::Readonly>> {
136+
crate::NpySingleIterBuilder::readonly(self).build()
137+
}
138+
133139
pub(crate) fn destruct(self) -> (&'py PyArray<T, D>, bool) {
134140
let PyReadonlyArray {
135141
array,

0 commit comments

Comments
 (0)