-
Notifications
You must be signed in to change notification settings - Fork 788
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Optimize nth and nth_back for BoundListIterator #4810
base: main
Are you sure you want to change the base?
Changes from 14 commits
cc9cabd
3a0c196
40d38f3
1b19616
f6e95a8
b0c749b
b2bf973
4e86709
e4269c2
6e18229
5bab05b
0b23173
e88f8be
3a7a171
ed8dba6
51104a1
cae0981
00e4802
b7373aa
7751a1c
a735850
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Optimizes `nth` and `nth_back` for `BoundListIterator` | ||
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,16 +1,16 @@ | ||||||||||||||||||||||||||||||||||||||
use std::iter::FusedIterator; | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
use crate::err::{self, PyResult}; | ||||||||||||||||||||||||||||||||||||||
use crate::ffi::{self, Py_ssize_t}; | ||||||||||||||||||||||||||||||||||||||
use crate::ffi_ptr_ext::FfiPtrExt; | ||||||||||||||||||||||||||||||||||||||
use crate::internal_tricks::get_ssize_index; | ||||||||||||||||||||||||||||||||||||||
use crate::types::any::PyAnyMethods; | ||||||||||||||||||||||||||||||||||||||
use crate::types::sequence::PySequenceMethods; | ||||||||||||||||||||||||||||||||||||||
use crate::types::{PySequence, PyTuple}; | ||||||||||||||||||||||||||||||||||||||
use crate::{ | ||||||||||||||||||||||||||||||||||||||
Borrowed, Bound, BoundObject, IntoPyObject, IntoPyObjectExt, PyAny, PyErr, PyObject, Python, | ||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
use crate::types::any::PyAnyMethods; | ||||||||||||||||||||||||||||||||||||||
use crate::types::sequence::PySequenceMethods; | ||||||||||||||||||||||||||||||||||||||
use std::iter::FusedIterator; | ||||||||||||||||||||||||||||||||||||||
#[cfg(all(not(Py_LIMITED_API), feature = "nightly"))] | ||||||||||||||||||||||||||||||||||||||
use std::num::NonZero; | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
/// Represents a Python `list`. | ||||||||||||||||||||||||||||||||||||||
/// | ||||||||||||||||||||||||||||||||||||||
|
@@ -547,6 +547,46 @@ impl<'py> BoundListIterator<'py> { | |||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
#[inline] | ||||||||||||||||||||||||||||||||||||||
#[cfg(all(not(Py_LIMITED_API), feature = "nightly"))] | ||||||||||||||||||||||||||||||||||||||
#[deny(unsafe_op_in_unsafe_fn)] | ||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm confused - shouldn't this only be defined on Ditto for all the other There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indeed - I spent hours reading the stdlib again to figure out that on stable toolchain, we should override |
||||||||||||||||||||||||||||||||||||||
unsafe fn nth_unchecked( | ||||||||||||||||||||||||||||||||||||||
index: &mut Index, | ||||||||||||||||||||||||||||||||||||||
length: &mut Length, | ||||||||||||||||||||||||||||||||||||||
list: &Bound<'py, PyList>, | ||||||||||||||||||||||||||||||||||||||
n: usize, | ||||||||||||||||||||||||||||||||||||||
) -> Option<Bound<'py, PyAny>> { | ||||||||||||||||||||||||||||||||||||||
let length = length.0.min(list.len()); | ||||||||||||||||||||||||||||||||||||||
let target_index = index.0 + n; | ||||||||||||||||||||||||||||||||||||||
if index.0 + n < length { | ||||||||||||||||||||||||||||||||||||||
let item = unsafe { list.get_item_unchecked(target_index) }; | ||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks & revised |
||||||||||||||||||||||||||||||||||||||
index.0 = target_index + 1; | ||||||||||||||||||||||||||||||||||||||
Some(item) | ||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||
None | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
#[inline] | ||||||||||||||||||||||||||||||||||||||
#[cfg(all(Py_LIMITED_API, feature = "nightly"))] | ||||||||||||||||||||||||||||||||||||||
#[deny(unsafe_op_in_unsafe_fn)] | ||||||||||||||||||||||||||||||||||||||
fn nth( | ||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
there's no unsafe code in this function so this is unnecessary |
||||||||||||||||||||||||||||||||||||||
index: &mut Index, | ||||||||||||||||||||||||||||||||||||||
length: &mut Length, | ||||||||||||||||||||||||||||||||||||||
list: &Bound<'py, PyList>, | ||||||||||||||||||||||||||||||||||||||
n: usize, | ||||||||||||||||||||||||||||||||||||||
) -> Option<Bound<'py, PyAny>> { | ||||||||||||||||||||||||||||||||||||||
let length = length.0.min(list.len()); | ||||||||||||||||||||||||||||||||||||||
let target_index = index.0 + n; | ||||||||||||||||||||||||||||||||||||||
if index.0 + n < length { | ||||||||||||||||||||||||||||||||||||||
let item = list.get_item(target_index).expect("get-item failed"); | ||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks & revised |
||||||||||||||||||||||||||||||||||||||
index.0 = target_index + 1; | ||||||||||||||||||||||||||||||||||||||
Some(item) | ||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||
None | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
/// # Safety | ||||||||||||||||||||||||||||||||||||||
/// | ||||||||||||||||||||||||||||||||||||||
/// On the free-threaded build, caller must verify they have exclusive | ||||||||||||||||||||||||||||||||||||||
|
@@ -589,6 +629,45 @@ impl<'py> BoundListIterator<'py> { | |||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
#[inline] | ||||||||||||||||||||||||||||||||||||||
#[cfg(all(not(Py_LIMITED_API), feature = "nightly"))] | ||||||||||||||||||||||||||||||||||||||
#[deny(unsafe_op_in_unsafe_fn)] | ||||||||||||||||||||||||||||||||||||||
unsafe fn nth_back_unchecked( | ||||||||||||||||||||||||||||||||||||||
index: &mut Index, | ||||||||||||||||||||||||||||||||||||||
length: &mut Length, | ||||||||||||||||||||||||||||||||||||||
list: &Bound<'py, PyList>, | ||||||||||||||||||||||||||||||||||||||
n: usize, | ||||||||||||||||||||||||||||||||||||||
) -> Option<Bound<'py, PyAny>> { | ||||||||||||||||||||||||||||||||||||||
let length_size = length.0.min(list.len()); | ||||||||||||||||||||||||||||||||||||||
if index.0 + n < length_size { | ||||||||||||||||||||||||||||||||||||||
let target_index = length_size - n - 1; | ||||||||||||||||||||||||||||||||||||||
let item = unsafe { list.get_item_unchecked(target_index) }; | ||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Personally this logic feels a little backwards to me, and I would probably prefer to do this using signed integers and testing if the index is less than zero. That said, this is totally equivalent and if it makes sense to you as-is then no need to change it. |
||||||||||||||||||||||||||||||||||||||
*length = Length(target_index); | ||||||||||||||||||||||||||||||||||||||
Some(item) | ||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||
None | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
#[inline] | ||||||||||||||||||||||||||||||||||||||
#[cfg(all(Py_LIMITED_API, feature = "nightly"))] | ||||||||||||||||||||||||||||||||||||||
fn nth_back( | ||||||||||||||||||||||||||||||||||||||
index: &mut Index, | ||||||||||||||||||||||||||||||||||||||
length: &mut Length, | ||||||||||||||||||||||||||||||||||||||
list: &Bound<'py, PyList>, | ||||||||||||||||||||||||||||||||||||||
n: usize, | ||||||||||||||||||||||||||||||||||||||
) -> Option<Bound<'py, PyAny>> { | ||||||||||||||||||||||||||||||||||||||
let length_size = length.0.min(list.len()); | ||||||||||||||||||||||||||||||||||||||
if index.0 + n < length_size { | ||||||||||||||||||||||||||||||||||||||
let target_index = length_size - n - 1; | ||||||||||||||||||||||||||||||||||||||
let item = list.get_item(target_index).expect("get-item failed"); | ||||||||||||||||||||||||||||||||||||||
*length = Length(target_index); | ||||||||||||||||||||||||||||||||||||||
Some(item) | ||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||
None | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
ngoldbaum marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||
#[cfg(not(Py_LIMITED_API))] | ||||||||||||||||||||||||||||||||||||||
fn with_critical_section<R>( | ||||||||||||||||||||||||||||||||||||||
&mut self, | ||||||||||||||||||||||||||||||||||||||
|
@@ -625,6 +704,26 @@ impl<'py> Iterator for BoundListIterator<'py> { | |||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
#[inline] | ||||||||||||||||||||||||||||||||||||||
#[cfg(feature = "nightly")] | ||||||||||||||||||||||||||||||||||||||
fn nth(&mut self, n: usize) -> Option<Self::Item> { | ||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks & revised |
||||||||||||||||||||||||||||||||||||||
#[cfg(not(Py_LIMITED_API))] | ||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||
self.with_critical_section(|index, length, list| unsafe { | ||||||||||||||||||||||||||||||||||||||
Self::nth_unchecked(index, length, list, n) | ||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
#[cfg(Py_LIMITED_API)] | ||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||
let Self { | ||||||||||||||||||||||||||||||||||||||
index, | ||||||||||||||||||||||||||||||||||||||
length, | ||||||||||||||||||||||||||||||||||||||
list, | ||||||||||||||||||||||||||||||||||||||
} = self; | ||||||||||||||||||||||||||||||||||||||
Self::nth(index, length, list, n) | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
If you implement my suggestion to only have There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. and you can do a similar refactor for the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks. I've adopted this idea for |
||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
#[inline] | ||||||||||||||||||||||||||||||||||||||
fn size_hint(&self) -> (usize, Option<usize>) { | ||||||||||||||||||||||||||||||||||||||
let len = self.len(); | ||||||||||||||||||||||||||||||||||||||
|
@@ -750,6 +849,32 @@ impl<'py> Iterator for BoundListIterator<'py> { | |||||||||||||||||||||||||||||||||||||
None | ||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
#[inline] | ||||||||||||||||||||||||||||||||||||||
#[cfg(all(not(Py_LIMITED_API), feature = "nightly"))] | ||||||||||||||||||||||||||||||||||||||
fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> { | ||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Unless I'm missing something... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I feel we need the flag https://github.com/PyO3/pyo3/actions/runs/12769998628/job/35593851381?pr=4810 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you can delete the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks. I deleted I also pushed a few commits and implemented |
||||||||||||||||||||||||||||||||||||||
self.with_critical_section(|index, length, list| { | ||||||||||||||||||||||||||||||||||||||
let max_len = length.0.min(list.len()); | ||||||||||||||||||||||||||||||||||||||
let currently_at = index.0; | ||||||||||||||||||||||||||||||||||||||
if currently_at >= max_len { | ||||||||||||||||||||||||||||||||||||||
if n == 0 { | ||||||||||||||||||||||||||||||||||||||
return Ok(()); | ||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||
return Err(unsafe { NonZero::new_unchecked(n) }); | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
let items_left = max_len - currently_at; | ||||||||||||||||||||||||||||||||||||||
if n <= items_left { | ||||||||||||||||||||||||||||||||||||||
index.0 += n; | ||||||||||||||||||||||||||||||||||||||
Ok(()) | ||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||
index.0 = max_len; | ||||||||||||||||||||||||||||||||||||||
let remainder = n - items_left; | ||||||||||||||||||||||||||||||||||||||
Err(unsafe { NonZero::new_unchecked(remainder) }) | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
impl DoubleEndedIterator for BoundListIterator<'_> { | ||||||||||||||||||||||||||||||||||||||
|
@@ -772,6 +897,26 @@ impl DoubleEndedIterator for BoundListIterator<'_> { | |||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
#[inline] | ||||||||||||||||||||||||||||||||||||||
#[cfg(feature = "nightly")] | ||||||||||||||||||||||||||||||||||||||
fn nth_back(&mut self, n: usize) -> Option<Self::Item> { | ||||||||||||||||||||||||||||||||||||||
#[cfg(not(Py_LIMITED_API))] | ||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||
self.with_critical_section(|index, length, list| unsafe { | ||||||||||||||||||||||||||||||||||||||
Self::nth_back_unchecked(index, length, list, n) | ||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
#[cfg(Py_LIMITED_API)] | ||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||
let Self { | ||||||||||||||||||||||||||||||||||||||
index, | ||||||||||||||||||||||||||||||||||||||
length, | ||||||||||||||||||||||||||||||||||||||
list, | ||||||||||||||||||||||||||||||||||||||
} = self; | ||||||||||||||||||||||||||||||||||||||
Self::nth_back(index, length, list, n) | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
#[inline] | ||||||||||||||||||||||||||||||||||||||
#[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))] | ||||||||||||||||||||||||||||||||||||||
fn rfold<B, F>(mut self, init: B, mut f: F) -> B | ||||||||||||||||||||||||||||||||||||||
|
@@ -839,6 +984,8 @@ mod tests { | |||||||||||||||||||||||||||||||||||||
use crate::types::sequence::PySequenceMethods; | ||||||||||||||||||||||||||||||||||||||
use crate::types::{PyList, PyTuple}; | ||||||||||||||||||||||||||||||||||||||
use crate::{ffi, IntoPyObject, PyResult, Python}; | ||||||||||||||||||||||||||||||||||||||
#[cfg(feature = "nightly")] | ||||||||||||||||||||||||||||||||||||||
use std::num::NonZero; | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
#[test] | ||||||||||||||||||||||||||||||||||||||
fn test_new() { | ||||||||||||||||||||||||||||||||||||||
|
@@ -1502,4 +1649,130 @@ mod tests { | |||||||||||||||||||||||||||||||||||||
assert!(tuple.eq(tuple_expected).unwrap()); | ||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
#[test] | ||||||||||||||||||||||||||||||||||||||
fn test_iter_nth() { | ||||||||||||||||||||||||||||||||||||||
Python::with_gil(|py| { | ||||||||||||||||||||||||||||||||||||||
let v = vec![6, 7, 8, 9, 10]; | ||||||||||||||||||||||||||||||||||||||
let ob = (&v).into_pyobject(py).unwrap(); | ||||||||||||||||||||||||||||||||||||||
let list = ob.downcast::<PyList>().unwrap(); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
let mut iter = list.iter(); | ||||||||||||||||||||||||||||||||||||||
iter.next(); | ||||||||||||||||||||||||||||||||||||||
assert_eq!(iter.nth(1).unwrap().extract::<i32>().unwrap(), 8); | ||||||||||||||||||||||||||||||||||||||
assert_eq!(iter.nth(1).unwrap().extract::<i32>().unwrap(), 10); | ||||||||||||||||||||||||||||||||||||||
assert!(iter.nth(1).is_none()); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
let v: Vec<i32> = vec![]; | ||||||||||||||||||||||||||||||||||||||
let ob = (&v).into_pyobject(py).unwrap(); | ||||||||||||||||||||||||||||||||||||||
let list = ob.downcast::<PyList>().unwrap(); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
let mut iter = list.iter(); | ||||||||||||||||||||||||||||||||||||||
iter.next(); | ||||||||||||||||||||||||||||||||||||||
assert!(iter.nth(1).is_none()); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
let v = vec![1, 2, 3]; | ||||||||||||||||||||||||||||||||||||||
let ob = (&v).into_pyobject(py).unwrap(); | ||||||||||||||||||||||||||||||||||||||
let list = ob.downcast::<PyList>().unwrap(); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
let mut iter = list.iter(); | ||||||||||||||||||||||||||||||||||||||
assert!(iter.nth(10).is_none()); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
let v = vec![6, 7, 8, 9, 10]; | ||||||||||||||||||||||||||||||||||||||
let ob = (&v).into_pyobject(py).unwrap(); | ||||||||||||||||||||||||||||||||||||||
let list = ob.downcast::<PyList>().unwrap(); | ||||||||||||||||||||||||||||||||||||||
let mut iter = list.iter(); | ||||||||||||||||||||||||||||||||||||||
assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 6); | ||||||||||||||||||||||||||||||||||||||
assert_eq!(iter.nth(2).unwrap().extract::<i32>().unwrap(), 9); | ||||||||||||||||||||||||||||||||||||||
assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 10); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
let mut iter = list.iter(); | ||||||||||||||||||||||||||||||||||||||
iter.nth_back(1); | ||||||||||||||||||||||||||||||||||||||
assert_eq!(iter.nth(2).unwrap().extract::<i32>().unwrap(), 8); | ||||||||||||||||||||||||||||||||||||||
assert!(iter.next().is_none()); | ||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
#[test] | ||||||||||||||||||||||||||||||||||||||
fn test_iter_nth_back() { | ||||||||||||||||||||||||||||||||||||||
Python::with_gil(|py| { | ||||||||||||||||||||||||||||||||||||||
let v = vec![1, 2, 3, 4, 5]; | ||||||||||||||||||||||||||||||||||||||
let ob = (&v).into_pyobject(py).unwrap(); | ||||||||||||||||||||||||||||||||||||||
let list = ob.downcast::<PyList>().unwrap(); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
let mut iter = list.iter(); | ||||||||||||||||||||||||||||||||||||||
assert_eq!(iter.nth_back(0).unwrap().extract::<i32>().unwrap(), 5); | ||||||||||||||||||||||||||||||||||||||
assert_eq!(iter.nth_back(1).unwrap().extract::<i32>().unwrap(), 3); | ||||||||||||||||||||||||||||||||||||||
assert!(iter.nth_back(2).is_none()); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
let v: Vec<i32> = vec![]; | ||||||||||||||||||||||||||||||||||||||
let ob = (&v).into_pyobject(py).unwrap(); | ||||||||||||||||||||||||||||||||||||||
let list = ob.downcast::<PyList>().unwrap(); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
let mut iter = list.iter(); | ||||||||||||||||||||||||||||||||||||||
assert!(iter.nth_back(0).is_none()); | ||||||||||||||||||||||||||||||||||||||
assert!(iter.nth_back(1).is_none()); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
let v = vec![1, 2, 3]; | ||||||||||||||||||||||||||||||||||||||
let ob = (&v).into_pyobject(py).unwrap(); | ||||||||||||||||||||||||||||||||||||||
let list = ob.downcast::<PyList>().unwrap(); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
let mut iter = list.iter(); | ||||||||||||||||||||||||||||||||||||||
assert!(iter.nth_back(5).is_none()); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
let v = vec![1, 2, 3, 4, 5]; | ||||||||||||||||||||||||||||||||||||||
let ob = (&v).into_pyobject(py).unwrap(); | ||||||||||||||||||||||||||||||||||||||
let list = ob.downcast::<PyList>().unwrap(); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
let mut iter = list.iter(); | ||||||||||||||||||||||||||||||||||||||
iter.next_back(); // Consume the last element | ||||||||||||||||||||||||||||||||||||||
assert_eq!(iter.nth_back(1).unwrap().extract::<i32>().unwrap(), 3); | ||||||||||||||||||||||||||||||||||||||
assert_eq!(iter.next_back().unwrap().extract::<i32>().unwrap(), 2); | ||||||||||||||||||||||||||||||||||||||
assert_eq!(iter.nth_back(0).unwrap().extract::<i32>().unwrap(), 1); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
let v = vec![1, 2, 3, 4, 5]; | ||||||||||||||||||||||||||||||||||||||
let ob = (&v).into_pyobject(py).unwrap(); | ||||||||||||||||||||||||||||||||||||||
let list = ob.downcast::<PyList>().unwrap(); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
let mut iter = list.iter(); | ||||||||||||||||||||||||||||||||||||||
assert_eq!(iter.nth_back(1).unwrap().extract::<i32>().unwrap(), 4); | ||||||||||||||||||||||||||||||||||||||
assert_eq!(iter.nth_back(2).unwrap().extract::<i32>().unwrap(), 1); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
let mut iter2 = list.iter(); | ||||||||||||||||||||||||||||||||||||||
iter2.next_back(); | ||||||||||||||||||||||||||||||||||||||
assert_eq!(iter2.nth_back(1).unwrap().extract::<i32>().unwrap(), 3); | ||||||||||||||||||||||||||||||||||||||
assert_eq!(iter2.next_back().unwrap().extract::<i32>().unwrap(), 2); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
let mut iter3 = list.iter(); | ||||||||||||||||||||||||||||||||||||||
iter3.nth(1); | ||||||||||||||||||||||||||||||||||||||
assert_eq!(iter3.nth_back(2).unwrap().extract::<i32>().unwrap(), 3); | ||||||||||||||||||||||||||||||||||||||
assert!(iter3.nth_back(0).is_none()); | ||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
#[cfg(feature = "nightly")] | ||||||||||||||||||||||||||||||||||||||
#[test] | ||||||||||||||||||||||||||||||||||||||
fn test_iter_advance_by() { | ||||||||||||||||||||||||||||||||||||||
Python::with_gil(|py| { | ||||||||||||||||||||||||||||||||||||||
let v = vec![1, 2, 3, 4, 5]; | ||||||||||||||||||||||||||||||||||||||
let ob = (&v).into_pyobject(py).unwrap(); | ||||||||||||||||||||||||||||||||||||||
let list = ob.downcast::<PyList>().unwrap(); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
let mut iter = list.iter(); | ||||||||||||||||||||||||||||||||||||||
assert_eq!(iter.advance_by(2), Ok(())); | ||||||||||||||||||||||||||||||||||||||
assert_eq!(iter.next().unwrap().extract::<i32>().unwrap(), 3); | ||||||||||||||||||||||||||||||||||||||
assert_eq!(iter.advance_by(0), Ok(())); | ||||||||||||||||||||||||||||||||||||||
assert_eq!(iter.advance_by(100), Err(NonZero::new(98).unwrap())); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
let mut iter2 = list.iter(); | ||||||||||||||||||||||||||||||||||||||
assert_eq!(iter2.advance_by(6), Err(NonZero::new(1).unwrap())); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
let mut iter3 = list.iter(); | ||||||||||||||||||||||||||||||||||||||
assert_eq!(iter3.advance_by(5), Ok(())); | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
let mut iter4 = list.iter(); | ||||||||||||||||||||||||||||||||||||||
assert_eq!(iter4.advance_by(0), Ok(())); | ||||||||||||||||||||||||||||||||||||||
assert_eq!(iter4.next().unwrap().extract::<i32>().unwrap(), 1); | ||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe also mention that
advance_by
andadvance_by_back
are implemented on nightly