rust-lang / libs-team

The home of the library team
Apache License 2.0
123 stars 19 forks source link

Implement ExactSizeIterator for Flatten<option::IntoIter<I>> #332

Open SOF3 opened 8 months ago

SOF3 commented 8 months ago

Proposal

Motivating examples or use cases

fn iter_if<T>(cond: bool, inner: impl ExactSizeIterator<Item = T>) -> impl ExactSizeIterator<Item = T> {
    cond.then(|| inner).into_iter().flatten()
}

cannot compile because

error[E0277]: the trait bound Flatten<std::option::IntoIter<impl ExactSizeIterator<Item = T>>>: ExactSizeIterator is not satisfied

Solution sketch

In reality, the exact size can be inferred from the underlying iterator directly, something like this:

match self.inner.as_ref() {
    None => (0, Some(0)),
    Some(iter) => iter.size_hint(),
}

However this requires specialization on the size_hint impl of FlattenCompat.

Alternatives

Or we could just add an into_iter_flatten() method on Option, which returns IntoIterFlatten<I> that basically reimplements Flatten<option::IntoIter<I>>.

Links and related work

the8472 commented 8 months ago

This doesn't work because they can be Option::None which flatten into zero items.

SOF3 commented 8 months ago

@the8472 Isn't that what the None => (0, Some(0)) line is supposed to handle?

the8472 commented 8 months ago

Oh, sorry, I was thinking about flattening an iterator that yields option::IntoIter, not directly flattening an option iterator.

So iter_if could also be implemented using itertools::Either


fn iter_if<T>(cond: bool, inner: impl ExactSizeIterator<Item = T>) -> impl ExactSizeIterator<Item = T> {
    if cond {
       return Either::Left(inner)
    }
    return Either::Right(iter::empty())
}