Skip to content

Commit

Permalink
Implement size_hint for iter_non_repeating
Browse files Browse the repository at this point in the history
  • Loading branch information
allenap committed Sep 11, 2023
1 parent 4a5c5d1 commit f51f076
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 1 deletion.
13 changes: 12 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,7 @@ where
iters: Vec<(ITERATOR, Option<&'a str>)>,
separator: String,
capacity: usize,
size: Option<usize>,
}

impl<'a> NamesProduct<'a, core::iter::Cycle<alloc::vec::IntoIter<Option<&'a str>>>> {
Expand All @@ -427,6 +428,10 @@ impl<'a> NamesProduct<'a, core::iter::Cycle<alloc::vec::IntoIter<Option<&'a str>
.collect(),
separator: separator.to_string(),
capacity: Self::capacity(lists, separator),
size: match lists {
[] => Some(0),
ls => ls.iter().try_fold(1usize, |acc, list| acc.checked_mul(list.len())),
},
}
}

Expand Down Expand Up @@ -456,6 +461,10 @@ where
{
type Item = String;

fn size_hint(&self) -> (usize, Option<usize>) {
(self.size.unwrap_or(0), self.size)
}

fn next(&mut self) -> Option<Self::Item> {
let mut bump = true; // Request advance of next iterator.
for (iter, word) in self.iters.iter_mut() {
Expand Down Expand Up @@ -490,7 +499,9 @@ where
// We reached the end of the last iterator, hence we're done.
None
} else {
// We may be able to construct a word!
// Keep track of the number of names remaining.
self.size = self.size.map(|s| s.saturating_sub(1));
// We may be able to construct a name!
self.iters.iter().try_fold(String::with_capacity(self.capacity), |acc, (_, w)| match (acc, *w) {
(s, Some(w)) if s.is_empty() => Some(s + w),
(s, Some(w)) => Some(s + &self.separator + w),
Expand Down
33 changes: 33 additions & 0 deletions tests/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,39 @@ fn petnames_iter_non_repeating_yields_unique_names() {
)
}

#[test]
fn petnames_iter_non_repeating_provides_size_hint() {
let mut rng = StepRng::new(0, 1);
let petnames = Petnames::new("a1 a2", "b1 b2 b3", "c1 c2");
let iter = petnames.iter_non_repeating(&mut rng, 3, ".");
assert_eq!((12, Some(12)), iter.size_hint());
assert_eq!((9, Some(9)), iter.skip(3).size_hint());
}

#[test]
fn petnames_iter_non_repeating_provides_size_hint_that_saturates() {
let mut rng = StepRng::new(0, 1);
let petnames = Petnames::new("a1 a2", "b1 b2", "c1 c2");
let iter = petnames.iter_non_repeating(&mut rng, 3, ".");
assert_eq!((0, Some(0)), iter.skip(10).size_hint());
}

#[test]
fn petnames_iter_non_repeating_provides_size_hint_that_is_zero_when_any_list_is_empty() {
let mut rng = StepRng::new(0, 1);
let petnames = Petnames::new("", "b1 b2", "c1 c2");
let iter = petnames.iter_non_repeating(&mut rng, 3, ".");
assert_eq!((0, Some(0)), iter.size_hint());
}

#[test]
fn petnames_iter_non_repeating_provides_size_hint_that_is_zero_when_no_word_lists_are_given() {
let mut rng = StepRng::new(0, 1);
let petnames = Petnames::new("a1 a2", "b1 b2", "c1 c2");
let iter = petnames.iter_non_repeating(&mut rng, 0, ".");
assert_eq!((0, Some(0)), iter.size_hint());
}

#[test]
fn petnames_iter_non_repeating_yields_nothing_when_any_word_list_is_empty() {
let mut rng = StepRng::new(0, 1);
Expand Down

0 comments on commit f51f076

Please sign in to comment.