Implement ExactSizeIterator for Zip<A, Repeat<B>> by 414owen · Pull Request #146642 · rust-lang/rust (original) (raw)
Where:
A: ExactSizeIterator,
B: Clone,
And the symmetrical instance.
The only other instance for ExactSizeIterator<Zip<_, _>> requires each zipped iterator to be ExactSizeIterator, and since Repeat does not implement ExactSizeIterator, these instances don't overlap with anything.
I posted on the internals forum, and was told these instances would be insta-stable.
The stable attribute seems to require feature and since attributes, which I'm not entirely sure I've done correctly. Pointers are welcome.
rustbot added S-waiting-on-review
Status: Awaiting review from the assignee but also interested parties.
Relevant to the library team, which will review and decide on the PR/issue.
labels
r? @ibraheemdev
rustbot has assigned @ibraheemdev.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.
Use r? to explicitly pick a reviewer
414owen changed the title
Implement ExactSizeIterator for Implement ExactSizeIterator for Zip<A, Repeat>Zip<A, Repeat<B>>
Cool idea!
I think they could/should also be TrustedLen, which is even more useful than ESI in cases where you're extending or collecting into, i.e.:
| fn extend_trusted(&mut self, iterator: impl iter::TrustedLen<Item = T>) { |
|---|
| let (low, high) = iterator.size_hint(); |
| if let Some(additional) = high { |
| debug_assert_eq!( |
| low, |
| additional, |
| "TrustedLen iterator's size hint is not exact: {:?}", |
| (low, high) |
| ); |
| self.reserve(additional); |
| unsafe { |
| let ptr = self.as_mut_ptr(); |
| let mut local_len = SetLenOnDrop::new(&mut self.len); |
| iterator.for_each(move |element |
| ptr::write(ptr.add(local_len.current_len()), element); |
| // Since the loop executes user code which can panic we have to update |
| // the length every step to correctly drop what we've written. |
| // NB can't overflow since we would have had to alloc the address space |
| local_len.increment_len(1); |
| }); |
| } |
| } else { |
| // Per TrustedLen contract a `None` upper bound means that the iterator length |
| // truly exceeds usize::MAX, which would eventually lead to a capacity overflow anyway. |
| // Since the other branch already panics eagerly (via `reserve()`) we do the same here. |
| // This avoids additional codegen for a fallback code path which would eventually |
| // panic anyway. |
| panic!("capacity overflow"); |
| } |
| } |
Thanks @yotamofek :)
There's already a:
unsafe impl<A, B> TrustedLen for Zip<A, B> where A: TrustedLen, B: TrustedLen, { }
And since Repeat implements TrustedLen itself, I think this case is already covered?
Ah right, sorry, missed that!
scottmcm added T-libs-api
Relevant to the library API team, which will review and decide on the PR/issue.
This change is insta-stable, or significant enough to need a team FCP to proceed.
and removed T-libs
Relevant to the library team, which will review and decide on the PR/issue.
labels
I think what this really wants it an InfiniteIterator trait for Repeat and RangeFrom and such to implement. Because why Zip<A, Repeat<B>> but not Zip<A, RangeFrom<B>> or Zip<A, RepeatWith<B>> or ...
@scottmcm I had the same thought, but I figured this would be easier to get through, first.
RepeatWith could also be added to the list @scottmcm mentioned. Such a trait would also scale better outside std in case other iterators outside std can both implement said trait and make use of said trait for their own optimisations.
Where: A: ExactSizeIterator, B: Clone,
And the symmetrical instance.
The only other instance for ExactSizeIterator<Zip<_, _>> requires each
zipped iterator to be ExactSizeIterator, and since Repeat does not
implement ExactSizeIterator, these instances don't overlap with
anything.
Although for InfiniteIterator my motivation was more for iter.chain(repeat(n)), etc.
The instance for Zip would overlap with the existing ExactSizeIterator trait, and I'm not sure what the best way to tell the compiler they're mutually exclusive traits would be... (edit, looks like I can use negative bounds, nowadays?)
414owen added a commit to 414owen/rust that referenced this pull request
This enables more ExactSizeIterator instances.
Previously, in rust-lang#146642,
I sought to add specific instances for Zip<Repeat<A>, I> and its
symmatrical mirror.
Introducing InfiniteIterator provides much broader support for
ExactSizeIterator.
For example,
[1, 2, 3].chain(repeat(1)).take(5)Will now happily resolve to an instance of ExactSizeIterator.
The downside of this approach is that, to avoid the overlapping instance
with Zip, I had to introduce a negative trait bound, which, IIUC,
isn't available outside of the compiler.
If anyone knows od a better way to handle the overlapping instances, or a way I can expose something which triggers the negative instance, that would be very helpful.
414owen added a commit to 414owen/rust that referenced this pull request
This enables more ExactSizeIterator instances.
Previously, in rust-lang#146642,
I sought to add specific instances for Zip<Repeat<A>, I> and its
symmatrical mirror.
Introducing InfiniteIterator provides much broader support for
ExactSizeIterator.
For example,
[1, 2, 3].chain(repeat(1)).take(5)Will now happily resolve to an instance of ExactSizeIterator.
The downside of this approach is that, to avoid the overlapping instance
with Zip, I had to introduce a negative trait bound, which, IIUC,
isn't available outside of the compiler.
If anyone knows of a better way to handle the overlapping instances, or a way I can expose something which triggers the negative instance, that would be very helpful.
There's also a missing symmetrical instance for Chain. Solutions
are welcome.
414owen added a commit to 414owen/rust that referenced this pull request
This enables more ExactSizeIterator instances, specifically, those
for Take, where the sub-iterator is infinite, and Zip where the
one sub-iterator is infinite, and the other is exact sized.
Previously, in rust-lang#146642,
I sought to add specific instances for Zip<Repeat<A>, I> and its
symmatrical mirror.
Introducing InfiniteIterator provides much broader support for
ExactSizeIterator.
For example,
[1, 2, 3].chain(repeat(1)).take(5)Will now happily resolve to an instance of ExactSizeIterator.
The downside of this approach is that, to avoid the overlapping instance
with Zip, I had to introduce a negative trait bound, which, IIUC,
isn't available outside of the compiler.
If anyone knows of a better way to handle the overlapping instances, or a way I can expose something which triggers the negative instance, that would be very helpful.
There's also a missing symmetrical instance for Chain. Solutions
are welcome.
414owen added a commit to 414owen/rust that referenced this pull request
This enables more ExactSizeIterator instances, specifically, those
for Take, where the sub-iterator is infinite, and Zip where the
one sub-iterator is infinite, and the other is exact sized.
Previously, in rust-lang#146642,
I sought to add specific instances for Zip<Repeat<A>, I> and its
symmatrical mirror.
Introducing InfiniteIterator provides much broader support for
ExactSizeIterator.
For example,
[1, 2, 3].into_iter().chain(repeat(1)).take(5)Will now happily resolve to an instance of ExactSizeIterator.
The downside of this approach is that, to avoid the overlapping instance
with Zip, I had to introduce a negative trait bound, which, IIUC,
isn't available outside of the compiler.
If anyone knows of a better way to handle the overlapping instances, or a way I can expose something which triggers the negative instance, that would be very helpful.
There's also a missing symmetrical instance for Chain. Solutions
are welcome.
414owen added a commit to 414owen/rust that referenced this pull request
This enables more ExactSizeIterator instances, specifically, those
for Take, where the sub-iterator is infinite, and Zip where the
one sub-iterator is infinite, and the other is exact sized.
Previously, in rust-lang#146642,
I sought to add specific instances for Zip<Repeat<A>, I> and its
symmatrical mirror.
Introducing InfiniteIterator provides much broader support for
ExactSizeIterator.
For example,
[1, 2, 3].into_iter().chain(repeat(1)).take(5)Will now happily resolve to an instance of ExactSizeIterator.
The downside of this approach is that, to avoid the overlapping instance
with Zip, I had to introduce a negative trait bound, which, IIUC,
isn't available outside of the compiler.
If anyone knows of a better way to handle the overlapping instances, or a way I can expose something which triggers the negative instance, that would be very helpful.
There's also a missing symmetrical instance for Chain. Solutions
are welcome.