Skip to content
120 changes: 120 additions & 0 deletions src/iter_index.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
use core::ops::{ Range, RangeTo, RangeFrom, RangeFull, RangeInclusive, RangeToInclusive };
use core::iter::{Skip, Take};
use crate::Itertools;

mod private_iter_index {
use core::ops;

pub trait Sealed {}

impl Sealed for ops::Range<usize> {}
impl Sealed for ops::RangeInclusive<usize> {}
impl Sealed for ops::RangeTo<usize> {}
impl Sealed for ops::RangeToInclusive<usize> {}
impl Sealed for ops::RangeFrom<usize> {}
impl Sealed for ops::RangeFull {}
impl Sealed for usize {}
}

/// Used by the ``range`` function to know which iterator
/// to turn different ranges into.
pub trait IteratorIndex<I> : private_iter_index::Sealed
where I: Iterator
{
/// The type that [`get`] or [`Itertools::get`]
/// returns when called with this type of index.
type Output: Iterator<Item = I::Item>;

/// Returns an iterator(or value) in the specified range.
///
/// Prefer calling [`get`] or [`Itertools::get`] instead
/// of calling this directly.
fn index(self, from: I) -> Self::Output;
}

impl<I> IteratorIndex<I> for Range<usize>
where I: Iterator
{
type Output = Take<Skip<I>>;

fn index(self, iter: I) -> Self::Output {
iter.skip(self.start)
.take(self.end.saturating_sub(self.start))
}
}

impl<I> IteratorIndex<I> for RangeInclusive<usize>
where I: Iterator
{
type Output = Take<Skip<I>>;

fn index(self, iter: I) -> Self::Output {
iter.skip(*self.start())
.take(
(1 + *self.end())
.saturating_sub(*self.start())
)
}
}

impl<I> IteratorIndex<I> for RangeTo<usize>
where I: Iterator
{
type Output = Take<I>;

fn index(self, iter: I) -> Self::Output {
iter.take(self.end)
}
}

impl<I> IteratorIndex<I> for RangeToInclusive<usize>
where I: Iterator
{
type Output = Take<I>;

fn index(self, iter: I) -> Self::Output {
iter.take(self.end + 1)
}
}

impl<I> IteratorIndex<I> for RangeFrom<usize>
where I: Iterator
{
type Output = Skip<I>;

fn index(self, iter: I) -> Self::Output {
iter.skip(self.start)
}
}

impl<I> IteratorIndex<I> for RangeFull
where I: Iterator
{
type Output = I;

fn index(self, iter: I) -> Self::Output {
iter
}
}

impl<I> IteratorIndex<I> for usize
where I: Iterator
{
type Output = <Option<I::Item> as IntoIterator>::IntoIter;

fn index(self, mut iter: I) -> Self::Output {
iter.nth(self).into_iter()
}
}

/// Returns an element of the iterator or an iterator
/// over a subsection of the iterator.
///
/// See [`Itertools::get`] for more information.
pub fn get<I, R>(iter: I, index: R)
-> R::Output
where I: IntoIterator,
R: IteratorIndex<I::IntoIter>
{
index.index(iter.into_iter())
}
50 changes: 50 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ pub mod structs {
/// Traits helpful for using certain `Itertools` methods in generic contexts.
pub mod traits {
pub use crate::tuple_impl::HomogeneousTuple;
pub use crate::iter_index::IteratorIndex;
}

#[allow(deprecated)]
Expand All @@ -157,6 +158,7 @@ pub use crate::minmax::MinMaxResult;
pub use crate::peeking_take_while::PeekingNext;
pub use crate::process_results_impl::process_results;
pub use crate::repeatn::repeat_n;
pub use crate::iter_index::get;
#[allow(deprecated)]
pub use crate::sources::{repeat_call, unfold, iterate};
pub use crate::with_position::Position;
Expand All @@ -176,6 +178,7 @@ mod combinations;
mod combinations_with_replacement;
mod exactly_one_err;
mod diff;
mod iter_index;
mod format;
#[cfg(feature = "use_std")]
mod group_map;
Expand Down Expand Up @@ -396,6 +399,53 @@ pub trait Itertools : Iterator {
intersperse::intersperse(self, element)
}

/// Returns an element at a specific location, or returns an iterator
/// over a subsection of the iterator.
Comment on lines +491 to +492
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove "an element at a specific location, or returns".

///
/// Works similarly to [`slice::get`](https://doc.rust-lang.org/std/primitive.slice.html#method.get).
///
/// It's a generalisation of [`take`], [`skip`] and [`nth`], and uses these
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[`Iterator::take`], [`Iterator::skip`] should be enough.
Remove nth since it is not used anymore.

/// under the hood.
///
/// # Examples
///
/// ```
/// use itertools::Itertools;
///
/// let vec = vec![3, 1, 4, 1, 5];
///
/// let mut range: Vec<_> =
/// vec.iter().get(1..=3).copied().collect();
/// assert_eq!(&range, &[1, 4, 1]);
///
/// // It works with other types of ranges, too
/// range = vec.iter().get(..2).copied().collect();
/// assert_eq!(&range, &[3, 1]);
///
/// range = vec.iter().get(0..1).copied().collect();
/// assert_eq!(&range, &[3]);
///
/// range = vec.iter().get(2..).copied().collect();
/// assert_eq!(&range, &[4, 1, 5]);
///
/// range = vec.iter().get(..).copied().collect();
/// assert_eq!(range, vec);
///
/// range = vec.iter().get(3).copied().collect();
/// assert_eq!(&range, &[1]);
/// ```
///
/// [`take`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.take
/// [`skip`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.skip
/// [`nth`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.nth
Comment on lines +527 to +529
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove links.

fn get<R>(self, index: R)
-> R::Output
where R: iter_index::IteratorIndex<Self>,
Self: Sized
{
iter_index::get(self, index)
}

/// Create an iterator which iterates over both this and the specified
/// iterator simultaneously, yielding pairs of two optional elements.
///
Expand Down