-
Notifications
You must be signed in to change notification settings - Fork 319
Added Range iterator #447
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added Range iterator #447
Changes from 5 commits
b58c106
50e6b49
061acfb
6d624b7
14e34cf
f469a68
aa0ea02
8ccd1c0
eb326f0
52affb3
2ebe2bd
7364cd4
d4339b8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
use core::ops::{ Range, RangeTo, RangeFrom, RangeFull, RangeInclusive, RangeToInclusive }; | ||
use core::iter::{Skip, Take}; | ||
use crate::Itertools; | ||
|
||
/// Used by the ``range`` function to know which iterator | ||
/// to turn different ranges into. | ||
pub trait IntoRangeIter<IterFrom> { | ||
type IterTo; | ||
|
||
fn into_range_iter(self, from: IterFrom) -> Self::IterTo; | ||
} | ||
|
||
impl<I> IntoRangeIter<I> for Range<usize> | ||
where I: Iterator | ||
{ | ||
type IterTo = Take<Skip<I>>; | ||
|
||
fn into_range_iter(self, iter: I) -> Self::IterTo { | ||
iter.skip(self.start) | ||
.take(self.end.saturating_sub(self.start)) | ||
} | ||
} | ||
|
||
impl<I> IntoRangeIter<I> for RangeInclusive<usize> | ||
where I: Iterator | ||
{ | ||
type IterTo = Take<Skip<I>>; | ||
|
||
fn into_range_iter(self, iter: I) -> Self::IterTo { | ||
iter.skip(*self.start()) | ||
.take( | ||
(1 + *self.end()) | ||
.saturating_sub(*self.start()) | ||
) | ||
} | ||
} | ||
|
||
impl<I> IntoRangeIter<I> for RangeTo<usize> | ||
where I: Iterator | ||
{ | ||
type IterTo = Take<I>; | ||
|
||
fn into_range_iter(self, iter: I) -> Self::IterTo { | ||
iter.take(self.end) | ||
} | ||
} | ||
|
||
impl<I> IntoRangeIter<I> for RangeToInclusive<usize> | ||
where I: Iterator | ||
{ | ||
type IterTo = Take<I>; | ||
|
||
fn into_range_iter(self, iter: I) -> Self::IterTo { | ||
iter.take(self.end + 1) | ||
} | ||
} | ||
|
||
impl<I> IntoRangeIter<I> for RangeFrom<usize> | ||
where I: Iterator | ||
{ | ||
type IterTo = Skip<I>; | ||
|
||
fn into_range_iter(self, iter: I) -> Self::IterTo { | ||
iter.skip(self.start) | ||
} | ||
} | ||
|
||
impl<I> IntoRangeIter<I> for RangeFull | ||
where I: Iterator | ||
{ | ||
type IterTo = I; | ||
|
||
fn into_range_iter(self, iter: I) -> Self::IterTo { | ||
iter | ||
} | ||
} | ||
|
||
/// Limits an iterator to a range. See [`Itertools::range`] | ||
/// for more information. | ||
pub fn range<I, R>(iter: I, range: R) | ||
-> R::IterTo | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like the idea of exploiting existing iterator implementations. Three questions:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure that the TraitBounds -> IntoRangeIter conversion can work, because IntoRangeIter type is implement specifically for each TraitBounds type, so implementing it for all TraitBounds types would be a conflict. I'm not sure if rust team is working on prioritized implementations, but if it's possible to somehow say "use these implementations, or this other even more generic one if the specific ones are not possible". IntoIterRange implementing RangeBounds is definitely something we should add. And for some reason I had the idea that trait methods couldn't have generics, but that doesn't seem to be the case, so we shouldn't need to pass around the iterator information in the trait. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And I'll see if I can figure out that type alias thing. I am not too used to working with some of these things, I have stuck in my little rust box and not gone into other places too much, but it's great that I am now! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was thinking that maybe we should rename "IntoRangeIter" to "IterRangeBounds", because I feel like that makes more sense. The bounds aren't the thing that turn into an iterator after all, they just are a RangeBounds that work on an iterator |
||
where I: IntoIterator, | ||
R: IntoRangeIter<I::IntoIter> | ||
{ | ||
range.into_range_iter(iter.into_iter()) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No test about
RangeToInclusive
(such as..=2
) yet, add one or codecov will rightfully complain.