use core::iter::{Skip, Take}; use core::ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive}; #[cfg(doc)] use crate::Itertools; mod private_iter_index { use core::ops; pub trait Sealed {} impl Sealed for ops::Range {} impl Sealed for ops::RangeInclusive {} impl Sealed for ops::RangeTo {} impl Sealed for ops::RangeToInclusive {} impl Sealed for ops::RangeFrom {} impl Sealed for ops::RangeFull {} } /// Used by [`Itertools::get`] to know which iterator /// to turn different ranges into. pub trait IteratorIndex: private_iter_index::Sealed where I: Iterator, { /// The type returned for this type of index. type Output: Iterator; /// Returns an adapted iterator for the current index. /// /// Prefer calling [`Itertools::get`] instead /// of calling this directly. fn index(self, from: I) -> Self::Output; } impl IteratorIndex for Range where I: Iterator, { type Output = Skip>; fn index(self, iter: I) -> Self::Output { iter.take(self.end).skip(self.start) } } impl IteratorIndex for RangeInclusive where I: Iterator, { type Output = Take>; fn index(self, iter: I) -> Self::Output { // end - start + 1 without overflowing if possible let length = if *self.end() == usize::MAX { assert_ne!(*self.start(), 0); self.end() - self.start() + 1 } else { (self.end() + 1).saturating_sub(*self.start()) }; iter.skip(*self.start()).take(length) } } impl IteratorIndex for RangeTo where I: Iterator, { type Output = Take; fn index(self, iter: I) -> Self::Output { iter.take(self.end) } } impl IteratorIndex for RangeToInclusive where I: Iterator, { type Output = Take; fn index(self, iter: I) -> Self::Output { assert_ne!(self.end, usize::MAX); iter.take(self.end + 1) } } impl IteratorIndex for RangeFrom where I: Iterator, { type Output = Skip; fn index(self, iter: I) -> Self::Output { iter.skip(self.start) } } impl IteratorIndex for RangeFull where I: Iterator, { type Output = I; fn index(self, iter: I) -> Self::Output { iter } } pub fn get(iter: I, index: R) -> R::Output where I: IntoIterator, R: IteratorIndex, { index.index(iter.into_iter()) }