Implement SortedStarts and SortedDisjoint for std::iter::* types#27
Implement SortedStarts and SortedDisjoint for std::iter::* types#27mineichen wants to merge 5 commits into
Conversation
9944ed1 to
7f91633
Compare
…ch cannot break the invariants of SortedStarts or SortedDisjoint
7f91633 to
d6bd680
Compare
Yes, Please add a TODO comment in the code that references https://internals.rust-lang.org/t/implement-fusediterator-for-core-stepby/24074 Is the PR ready to review? |
|
If you want this in your lib, I'd suggest the following workflow:
It is not ready for review yet, just to show you code to have a discussion about. |
…StartsMap, if the inner iter implements it
There was a problem hiding this comment.
Pull request overview
This PR extends the crate’s marker traits (SortedStarts/SortedDisjoint and map equivalents) to cover common core::iter adapter types, enabling users to compose standard iterator adapters while retaining access to the crate’s optimized set/map operations.
Changes:
- Implement
SortedStarts/SortedDisjointfor severalcore::iteradapters (Filter,TakeWhile,SkipWhile,Fuse,Skip,Take,Peekable) plusEmpty/Once. - Implement
SortedStartsMap/SortedDisjointMapfor the correspondingcore::iteradapter types. - Add compile-time coverage tests demonstrating
union()over chained standard iterator adapters.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
src/sorted_disjoint.rs |
Adds marker-trait impls for core::iter adapters over RangeInclusive<T> and adds a small test. |
src/sorted_disjoint_map.rs |
Adds marker-trait impls for core::iter adapters over (RangeInclusive<T>, VR) and adds a small test. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| impl<T: Integer, I, P> SortedDisjoint<T> for core::iter::SkipWhile<I, P> | ||
| where | ||
| I: SortedStarts<T>, | ||
| P: FnMut(&I::Item) -> bool, | ||
| { |
There was a problem hiding this comment.
Same issue as TakeWhile: this SortedDisjoint impl only requires I: SortedStarts<T>. skip_while preserves disjointness only if the input is already disjoint, so the bound should be I: SortedDisjoint<T> to avoid falsely marking overlapping iterators as disjoint.
| impl<T, VR, I, P> SortedDisjointMap<T, VR> for core::iter::TakeWhile<I, P> | ||
| where | ||
| T: Integer, | ||
| VR: ValueRef, | ||
| I: SortedStartsMap<T, VR>, |
There was a problem hiding this comment.
SortedDisjointMap promises the underlying (range, value) pairs are disjoint. This impl currently only requires I: SortedStartsMap<T, VR>, which would allow overlapping ranges to be treated as SortedDisjointMap after take_while. Tighten the bound to I: SortedDisjointMap<T, VR> to preserve the trait contract.
| impl<T, VR, I, P> SortedDisjointMap<T, VR> for core::iter::SkipWhile<I, P> | ||
| where | ||
| T: Integer, | ||
| VR: ValueRef, | ||
| I: SortedStartsMap<T, VR>, |
There was a problem hiding this comment.
This SortedDisjointMap impl for SkipWhile only requires I: SortedStartsMap<T, VR>, but skip_while preserves disjointness only when the input is already disjoint. Require I: SortedDisjointMap<T, VR> here to avoid violating SortedDisjointMap’s invariants.
| // Check if core::iter::StepBy implements FusedIterator if it's inner is. Seems like it could be upstreamed | ||
| // https://internals.rust-lang.org/t/implement-fusediterator-for-core-stepby/24074 | ||
| // impl<T: Integer, I> SortedStarts<T> for core::iter::Fuse<core::iter::StepBy<I>> where | ||
| // I: SortedStarts<T> | ||
| // { | ||
| // } | ||
| // impl<T: Integer, I> SortedDisjoint<T> for core::iter::Fuse<core::iter::StepBy<I>> where | ||
| // I: SortedDisjoint<T> | ||
| // { | ||
| // } | ||
|
|
There was a problem hiding this comment.
The commented-out StepBy impls and the inline link to an upstream internals thread are dead code that will likely rot over time. Consider removing this block from the library source, or converting it into a concise TODO that points to a tracked repository issue (so it’s discoverable and has an action item).
| // Check if core::iter::StepBy implements FusedIterator if it's inner is. Seems like it could be upstreamed | |
| // https://internals.rust-lang.org/t/implement-fusediterator-for-core-stepby/24074 | |
| // impl<T: Integer, I> SortedStarts<T> for core::iter::Fuse<core::iter::StepBy<I>> where | |
| // I: SortedStarts<T> | |
| // { | |
| // } | |
| // impl<T: Integer, I> SortedDisjoint<T> for core::iter::Fuse<core::iter::StepBy<I>> where | |
| // I: SortedDisjoint<T> | |
| // { | |
| // } |
|
|
||
| impl<T: Integer, I, P> SortedDisjoint<T> for core::iter::TakeWhile<I, P> | ||
| where | ||
| I: SortedStarts<T>, |
There was a problem hiding this comment.
SortedDisjoint is a stronger contract than SortedStarts (it promises disjointness). This impl currently only requires I: SortedStarts<T>, which would allow a non-disjoint iterator to be treated as SortedDisjoint after take_while, violating the trait’s guarantees. Change the bound to require I: SortedDisjoint<T> (and keep the predicate bound as-is).
| I: SortedStarts<T>, | |
| I: SortedDisjoint<T>, |
|
Please look at Copilot’s review (it did a good job, I think). For StepBy, let’s leave it out for now. Please add a TODO plus a tracking issue for revisiting StepBy/FusedIterator later. |
…> into a SortedDisjoint using FlatMap and Flatten
baea53b to
426a158
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 8 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| Self: FusedIterator + Iterator<Item = (RangeInclusive<T>, VR)>, | ||
| I: SortedStartsMap<T, VR>, | ||
| TMap: FnMut(I) -> IInner, | ||
| { | ||
| } | ||
|
|
||
| impl<T, VR, I> SortedStartsMap<T, VR> for core::iter::Flatten<core::option::IntoIter<I>> | ||
| where | ||
| T: Integer, | ||
| VR: ValueRef, | ||
| Self: FusedIterator + Iterator<Item = (RangeInclusive<T>, VR)>, | ||
| I: SortedStartsMap<T, VR>, | ||
| { | ||
| } | ||
|
|
||
| impl<T, VR, I> SortedDisjointMap<T, VR> for core::iter::Flatten<core::option::IntoIter<I>> | ||
| where | ||
| T: Integer, | ||
| VR: ValueRef, | ||
| Self: FusedIterator + Iterator<Item = (RangeInclusive<T>, VR)>, | ||
| I: SortedDisjointMap<T, VR>, | ||
| { |
| impl<T, I, IInner, TMap> SortedStarts<T> | ||
| for core::iter::FlatMap<core::option::IntoIter<I>, IInner, TMap> | ||
| where | ||
| T: Integer, | ||
| IInner: SortedStarts<T>, | ||
| Self: FusedIterator + Iterator<Item = RangeInclusive<T>>, | ||
| I: SortedStarts<T>, | ||
| TMap: FnMut(I) -> IInner, | ||
| { |
| T: Integer, | ||
| IInner: SortedDisjoint<T>, | ||
| Self: FusedIterator + Iterator<Item = RangeInclusive<T>>, | ||
| I: SortedStarts<T>, |
| impl<T, I> SortedStarts<T> for core::iter::Flatten<core::option::IntoIter<I>> | ||
| where | ||
| T: Integer, | ||
| Self: FusedIterator + Iterator<Item = RangeInclusive<T>>, | ||
| I: SortedStarts<T>, | ||
| { | ||
| } | ||
|
|
||
| impl<T, I> SortedDisjoint<T> for core::iter::Flatten<core::option::IntoIter<I>> | ||
| where | ||
| T: Integer, | ||
| Self: FusedIterator + Iterator<Item = RangeInclusive<T>>, | ||
| I: SortedDisjoint<T>, | ||
| { | ||
| } |
| // Check if core::iter::StepBy implements FusedIterator if it's inner is. Seems like it could be upstreamed | ||
| // https://internals.rust-lang.org/t/implement-fusediterator-for-core-stepby/24074 | ||
| // impl<T: Integer, I> SortedStarts<T> for core::iter::Fuse<core::iter::StepBy<I>> where | ||
| // I: SortedStarts<T> | ||
| // { | ||
| // } | ||
| // impl<T: Integer, I> SortedDisjoint<T> for core::iter::Fuse<core::iter::StepBy<I>> where | ||
| // I: SortedDisjoint<T> | ||
| // { | ||
| // } |
| { | ||
| } | ||
|
|
||
| // Check if core::iter::StepBy implements FusedIterator if it's inner is. Seems like it could be upstreamed |
| I: SortedStartsMap<T, VR>, | ||
| TMap: FnMut(I) -> IInner, | ||
| { | ||
| } | ||
|
|
| VR: ValueRef, | ||
| IInner: SortedDisjointMap<T, VR>, | ||
| Self: FusedIterator + Iterator<Item = (RangeInclusive<T>, VR)>, | ||
| I: SortedStartsMap<T, VR>, |
|
Please look at Copilot’s latest suggestions. They seem right to me. |
|
Sorry for the sloppy changes... I think i got things right now... Copilot suggested to Remove the code in one block, and in the other not... I kept it to allow implementing it in the future... Seems like StepBy could soon be added... :-) |
…ify iterator support
|
Look good. I've added documentation. I'll include this in the next release. |
Implement SortedStarts and SortedDisjoint for std::iter::* types, which cannot break the invariants of SortedStarts or SortedDisjoint... This enables users of the library to use these operators, as demonstrated in the test.
--Would you be willing to drop the FusedIterator requirement of
SortedStarts(breaking), if std::ops::Fused itself implements SortedStarts, if it's inner Iterator does?