use crate::cmp; use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen}; use crate::ops::{ControlFlow, Try}; /// An iterator that only iterates over the first `n` iterations of `iter`. /// /// This `struct` is created by the [`take`] method on [`Iterator`]. See its /// documentation for more. /// /// [`take`]: Iterator::take /// [`Iterator`]: trait.Iterator.html #[derive(Clone, Debug)] #[must_use = "iterators are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] pub struct Take { iter: I, n: usize, } impl Take { pub(in crate::iter) fn new(iter: I, n: usize) -> Take { Take { iter, n } } } #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for Take where I: Iterator, { type Item = ::Item; #[inline] fn next(&mut self) -> Option<::Item> { if self.n != 0 { self.n -= 1; self.iter.next() } else { None } } #[inline] fn nth(&mut self, n: usize) -> Option { if self.n > n { self.n -= n + 1; self.iter.nth(n) } else { if self.n > 0 { self.iter.nth(self.n - 1); self.n = 0; } None } } #[inline] fn size_hint(&self) -> (usize, Option) { if self.n == 0 { return (0, Some(0)); } let (lower, upper) = self.iter.size_hint(); let lower = cmp::min(lower, self.n); let upper = match upper { Some(x) if x < self.n => Some(x), _ => Some(self.n), }; (lower, upper) } #[inline] fn try_fold(&mut self, init: Acc, fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try, { fn check<'a, T, Acc, R: Try>( n: &'a mut usize, mut fold: impl FnMut(Acc, T) -> R + 'a, ) -> impl FnMut(Acc, T) -> ControlFlow + 'a { move |acc, x| { *n -= 1; let r = fold(acc, x); if *n == 0 { ControlFlow::Break(r) } else { ControlFlow::from_try(r) } } } if self.n == 0 { try { init } } else { let n = &mut self.n; self.iter.try_fold(init, check(n, fold)).into_try() } } #[inline] fn fold(mut self, init: Acc, fold: Fold) -> Acc where Self: Sized, Fold: FnMut(Acc, Self::Item) -> Acc, { #[inline] fn ok(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result { move |acc, x| Ok(f(acc, x)) } self.try_fold(init, ok(fold)).unwrap() } #[inline] #[rustc_inherit_overflow_checks] fn advance_by(&mut self, n: usize) -> Result<(), usize> { let min = self.n.min(n); match self.iter.advance_by(min) { Ok(_) => { self.n -= min; if min < n { Err(min) } else { Ok(()) } } ret @ Err(advanced) => { self.n -= advanced; ret } } } } #[unstable(issue = "none", feature = "inplace_iteration")] unsafe impl SourceIter for Take where I: SourceIter, { type Source = I::Source; #[inline] unsafe fn as_inner(&mut self) -> &mut I::Source { // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } } #[unstable(issue = "none", feature = "inplace_iteration")] unsafe impl InPlaceIterable for Take {} #[stable(feature = "double_ended_take_iterator", since = "1.38.0")] impl DoubleEndedIterator for Take where I: DoubleEndedIterator + ExactSizeIterator, { #[inline] fn next_back(&mut self) -> Option { if self.n == 0 { None } else { let n = self.n; self.n -= 1; self.iter.nth_back(self.iter.len().saturating_sub(n)) } } #[inline] fn nth_back(&mut self, n: usize) -> Option { let len = self.iter.len(); if self.n > n { let m = len.saturating_sub(self.n) + n; self.n -= n + 1; self.iter.nth_back(m) } else { if len > 0 { self.iter.nth_back(len - 1); } None } } #[inline] fn try_rfold(&mut self, init: Acc, fold: Fold) -> R where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try, { if self.n == 0 { try { init } } else { let len = self.iter.len(); if len > self.n && self.iter.nth_back(len - self.n - 1).is_none() { try { init } } else { self.iter.try_rfold(init, fold) } } } #[inline] fn rfold(mut self, init: Acc, fold: Fold) -> Acc where Self: Sized, Fold: FnMut(Acc, Self::Item) -> Acc, { if self.n == 0 { init } else { let len = self.iter.len(); if len > self.n && self.iter.nth_back(len - self.n - 1).is_none() { init } else { self.iter.rfold(init, fold) } } } #[inline] #[rustc_inherit_overflow_checks] fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { // The amount by which the inner iterator needs to be shortened for it to be // at most as long as the take() amount. let trim_inner = self.iter.len().saturating_sub(self.n); // The amount we need to advance inner to fulfill the caller's request. // take(), advance_by() and len() all can be at most usize, so we don't have to worry // about having to advance more than usize::MAX here. let advance_by = trim_inner.saturating_add(n); let advanced = match self.iter.advance_back_by(advance_by) { Ok(_) => advance_by - trim_inner, Err(advanced) => advanced - trim_inner, }; self.n -= advanced; return if advanced < n { Err(advanced) } else { Ok(()) }; } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Take where I: ExactSizeIterator {} #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Take where I: FusedIterator {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl TrustedLen for Take {}