Skip to content

Commit

Permalink
feat(corelib): Iterator::advance_by (#7059)
Browse files Browse the repository at this point in the history
  • Loading branch information
MagisterDallis authored Jan 15, 2025
1 parent 9a3f075 commit 3e611b5
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 3 deletions.
41 changes: 41 additions & 0 deletions corelib/src/iter/traits/iterator.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,47 @@ pub trait Iterator<T> {
/// ```
fn next(ref self: T) -> Option<Self::Item>;

/// Advances the iterator by `n` elements.
///
/// This method will eagerly skip `n` elements by calling [`next`] up to `n`
/// times until [`None`] is encountered.
///
/// `advance_by(n)` will return `Ok(())` if the iterator successfully advances by
/// `n` elements, or a `Err(NonZero<usize>)` with value `k` if [`None`] is encountered,
/// where `k` is remaining number of steps that could not be advanced because the iterator ran
/// out.
/// If `self` is empty and `n` is non-zero, then this returns `Err(n)`.
/// Otherwise, `k` is always less than `n`.
///
/// [`None`]: Option::None
/// [`next`]: Iterator::next
///
/// # Examples
///
/// ```
/// let mut iter = array![1_u8, 2, 3, 4].into_iter();
///
/// assert_eq!(iter.advance_by(2), Result::Ok(()));
/// assert_eq!(iter.next(), Option::Some(3));
/// assert_eq!(iter.advance_by(0), Result::Ok(()));
/// assert_eq!(iter.advance_by(100), Result::Err(99));
/// ```
fn advance_by<+Destruct<T>, +Destruct<Self::Item>>(
ref self: T, n: usize,
) -> Result<
(), NonZero<usize>,
> {
if let Option::Some(nz_n) = n.try_into() {
if let Option::Some(_) = Self::next(ref self) {
return Self::advance_by(ref self, n - 1);
} else {
Result::Err(nz_n)
}
} else {
Result::Ok(())
}
}

/// Takes a closure and creates an iterator which calls that closure on each
/// element.
///
Expand Down
10 changes: 10 additions & 0 deletions corelib/src/test/iter_test.cairo
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
#[test]
fn test_advance_by() {
let mut iter = array![1_u8, 2, 3, 4].into_iter();

assert_eq!(iter.advance_by(2), Result::Ok(()));
assert_eq!(iter.next(), Option::Some(3));
assert_eq!(iter.advance_by(0), Result::Ok(()));
assert_eq!(iter.advance_by(100), Result::Err(99));
}

#[test]
fn test_iter_adapter_map() {
let mut iter = array![1, 2, 3].into_iter().map(|x| 2 * x);
Expand Down
6 changes: 3 additions & 3 deletions tests/bug_samples/issue7031.cairo
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
pub trait IteratorEx<T, impl I: Iterator<T>, +Destruct<T>, +Drop<I::Item>> {
fn advance_by(
fn advance_by_(
ref self: T, n: usize,
) -> Result<
(), NonZero<usize>,
Expand All @@ -19,7 +19,7 @@ impl ItratorExImpl<T, impl I: Iterator<T>, +Destruct<T>, +Drop<I::Item>> of Iter
#[test]
fn test_advance_by() {
let mut iter = array![1_u8, 2, 3, 4].into_iter();
assert_eq!(iter.advance_by(2), Result::Ok(()));
assert_eq!(iter.advance_by_(2), Result::Ok(()));
assert_eq!(iter.next(), Option::Some(3));
assert_eq!(iter.advance_by(0), Result::Ok(()));
assert_eq!(iter.advance_by_(0), Result::Ok(()));
}

0 comments on commit 3e611b5

Please sign in to comment.