Skip to content

Commit

Permalink
add enumerate
Browse files Browse the repository at this point in the history
  • Loading branch information
ratmice committed Dec 5, 2023
1 parent 1210d6c commit 4327b1e
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 2 deletions.
82 changes: 82 additions & 0 deletions src/adapters/enumerate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
use crate::LendingIterator;

/// A lending iterator that yields the current count and the element during iteration.
pub struct Enumerate<I> {
count: usize,
iter: I,
}

impl<I> Enumerate<I> {
pub(crate) fn new(iter: I) -> Self {
Enumerate { iter, count: 0 }
}
}

impl<I: LendingIterator> LendingIterator for Enumerate<I> {
type Item<'a> = (usize, I::Item<'a>) where Self: 'a;
fn next(&mut self) -> Option<Self::Item<'_>> {
let item = self.iter.next()?;
let count = self.count;
self.count += 1;
Some((count, item))
}
}

#[cfg(test)]
mod test {
use super::*;
use crate::ToLendingIterator;

// A non-fused iterator for testing that we match std's behavior
struct Delay<I> {
countdown: usize,
iter: I,
}

impl<I> Delay<I> {
fn new(countdown: usize, iter: I) -> Self {
Delay { countdown, iter }
}
}

// Generally we avoid implementing both Iterator and LendingIterator
// for the same type. Here in testing the bounds of the arguments
// are known not to collide.
impl<I: LendingIterator> LendingIterator for Delay<I> {
type Item<'a> = I::Item<'a> where Self: 'a;
fn next(&mut self) -> Option<Self::Item<'_>> {
if self.countdown == 0 {
self.iter.next()
} else {
self.countdown -= 1;
None
}
}
}

impl<I: Iterator> Iterator for Delay<I> {
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
if self.countdown == 0 {
self.iter.next()
} else {
self.countdown -= 1;
None
}
}
}

#[test]
fn test() {
let first = Some((0, ()));
let second = Some((1, ()));
let mut delay_iter = Delay::new(1, std::iter::repeat(()).take(2)).enumerate();
let mut delay_lending =
Delay::new(1, std::iter::repeat(()).into_lending().take(2)).enumerate();

assert_eq!((None, None), (delay_iter.next(), delay_lending.next()));
assert_eq!((first, first), (delay_iter.next(), delay_lending.next()));
assert_eq!((second, second), (delay_iter.next(), delay_lending.next()));
assert_eq!((None, None), (delay_iter.next(), delay_lending.next()));
}
}
2 changes: 2 additions & 0 deletions src/adapters/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod chain;
mod cloned;
mod enumerate;
mod filter;
mod filter_map;
mod map;
Expand All @@ -8,6 +9,7 @@ mod take;
mod zip;
pub use self::chain::Chain;
pub use self::cloned::Cloned;
pub use self::enumerate::Enumerate;
pub use self::filter::Filter;
pub use self::filter_map::FilterMap;
pub use self::map::{IntoIter, Map};
Expand Down
12 changes: 10 additions & 2 deletions src/traits/lending_iterator.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::{num::NonZeroUsize, ops::Deref};

use crate::{
Chain, Cloned, Filter, FilterMap, Map, OptionTrait, SingleArgFnMut, SingleArgFnOnce, StepBy,
Take, Zip,
Chain, Cloned, Enumerate, Filter, FilterMap, Map, OptionTrait, SingleArgFnMut, SingleArgFnOnce,
StepBy, Take, Zip,
};

/// Like [`Iterator`], but items may borrow from `&mut self`.
Expand Down Expand Up @@ -191,4 +191,12 @@ pub trait LendingIterator {
{
Cloned::new(self)
}

/// Creates a lending iterator which gives the current iteration count as well as the next value.
fn enumerate(self) -> Enumerate<Self>
where
Self: Sized,
{
Enumerate::new(self)
}
}

0 comments on commit 4327b1e

Please sign in to comment.