core/iter/adapters/
skip.rs

1use crate::intrinsics::unlikely;
2#[cfg(not(feature = "ferrocene_subset"))]
3use crate::iter::adapters::SourceIter;
4#[cfg(not(feature = "ferrocene_subset"))]
5use crate::iter::adapters::zip::try_get_unchecked;
6#[cfg(not(feature = "ferrocene_subset"))]
7use crate::iter::{
8    FusedIterator, InPlaceIterable, TrustedFused, TrustedLen, TrustedRandomAccess,
9    TrustedRandomAccessNoCoerce,
10};
11use crate::num::NonZero;
12#[cfg(not(feature = "ferrocene_subset"))]
13use crate::ops::{ControlFlow, Try};
14
15// Ferrocene addition: imports for certified subset
16#[cfg(feature = "ferrocene_subset")]
17#[rustfmt::skip]
18use crate::ops::Try;
19
20/// An iterator that skips over `n` elements of `iter`.
21///
22/// This `struct` is created by the [`skip`] method on [`Iterator`]. See its
23/// documentation for more.
24///
25/// [`skip`]: Iterator::skip
26/// [`Iterator`]: trait.Iterator.html
27#[cfg_attr(not(feature = "ferrocene_subset"), derive(Clone, Debug))]
28#[must_use = "iterators are lazy and do nothing unless consumed"]
29#[stable(feature = "rust1", since = "1.0.0")]
30pub struct Skip<I> {
31    iter: I,
32    n: usize,
33}
34
35impl<I> Skip<I> {
36    pub(in crate::iter) fn new(iter: I, n: usize) -> Skip<I> {
37        Skip { iter, n }
38    }
39}
40
41#[stable(feature = "rust1", since = "1.0.0")]
42impl<I> Iterator for Skip<I>
43where
44    I: Iterator,
45{
46    type Item = <I as Iterator>::Item;
47
48    #[inline]
49    fn next(&mut self) -> Option<I::Item> {
50        if unlikely(self.n > 0) {
51            self.iter.nth(crate::mem::take(&mut self.n))
52        } else {
53            self.iter.next()
54        }
55    }
56
57    #[inline]
58    fn nth(&mut self, n: usize) -> Option<I::Item> {
59        if self.n > 0 {
60            let skip: usize = crate::mem::take(&mut self.n);
61            // Checked add to handle overflow case.
62            let n = match skip.checked_add(n) {
63                Some(nth) => nth,
64                None => {
65                    // In case of overflow, load skip value, before loading `n`.
66                    // Because the amount of elements to iterate is beyond `usize::MAX`, this
67                    // is split into two `nth` calls where the `skip` `nth` call is discarded.
68                    self.iter.nth(skip - 1)?;
69                    n
70                }
71            };
72            // Load nth element including skip.
73            self.iter.nth(n)
74        } else {
75            self.iter.nth(n)
76        }
77    }
78
79    #[inline]
80    #[cfg(not(feature = "ferrocene_subset"))]
81    fn count(mut self) -> usize {
82        if self.n > 0 {
83            // nth(n) skips n+1
84            if self.iter.nth(self.n - 1).is_none() {
85                return 0;
86            }
87        }
88        self.iter.count()
89    }
90
91    #[inline]
92    fn last(mut self) -> Option<I::Item> {
93        if self.n > 0 {
94            // nth(n) skips n+1
95            self.iter.nth(self.n - 1)?;
96        }
97        self.iter.last()
98    }
99
100    #[inline]
101    fn size_hint(&self) -> (usize, Option<usize>) {
102        let (lower, upper) = self.iter.size_hint();
103
104        let lower = lower.saturating_sub(self.n);
105        let upper = match upper {
106            Some(x) => Some(x.saturating_sub(self.n)),
107            None => None,
108        };
109
110        (lower, upper)
111    }
112
113    #[inline]
114    fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
115    where
116        Self: Sized,
117        Fold: FnMut(Acc, Self::Item) -> R,
118        R: Try<Output = Acc>,
119    {
120        let n = self.n;
121        self.n = 0;
122        if n > 0 {
123            // nth(n) skips n+1
124            if self.iter.nth(n - 1).is_none() {
125                return try { init };
126            }
127        }
128        self.iter.try_fold(init, fold)
129    }
130
131    #[inline]
132    fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
133    where
134        Fold: FnMut(Acc, Self::Item) -> Acc,
135    {
136        if self.n > 0 {
137            // nth(n) skips n+1
138            if self.iter.nth(self.n - 1).is_none() {
139                return init;
140            }
141        }
142        self.iter.fold(init, fold)
143    }
144
145    #[inline]
146    #[rustc_inherit_overflow_checks]
147    fn advance_by(&mut self, mut n: usize) -> Result<(), NonZero<usize>> {
148        let skip_inner = self.n;
149        let skip_and_advance = skip_inner.saturating_add(n);
150
151        let remainder = match self.iter.advance_by(skip_and_advance) {
152            Ok(()) => 0,
153            Err(n) => n.get(),
154        };
155        let advanced_inner = skip_and_advance - remainder;
156        n -= advanced_inner.saturating_sub(skip_inner);
157        self.n = self.n.saturating_sub(advanced_inner);
158
159        // skip_and_advance may have saturated
160        if unlikely(remainder == 0 && n > 0) {
161            n = match self.iter.advance_by(n) {
162                Ok(()) => 0,
163                Err(n) => n.get(),
164            }
165        }
166
167        NonZero::new(n).map_or(Ok(()), Err)
168    }
169
170    #[doc(hidden)]
171    #[cfg(not(feature = "ferrocene_subset"))]
172    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
173    where
174        Self: TrustedRandomAccessNoCoerce,
175    {
176        // SAFETY: the caller must uphold the contract for
177        // `Iterator::__iterator_get_unchecked`.
178        //
179        // Dropping the skipped prefix when index 0 is passed is safe
180        // since
181        // * the caller passing index 0 means that the inner iterator has more items than `self.n`
182        // * TRA contract requires that get_unchecked will only be called once
183        //   (unless elements are copyable)
184        // * it does not conflict with in-place iteration since index 0 must be accessed
185        //   before something is written into the storage used by the prefix
186        unsafe {
187            if Self::MAY_HAVE_SIDE_EFFECT && idx == 0 {
188                for skipped_idx in 0..self.n {
189                    drop(try_get_unchecked(&mut self.iter, skipped_idx));
190                }
191            }
192
193            try_get_unchecked(&mut self.iter, idx + self.n)
194        }
195    }
196}
197
198#[stable(feature = "rust1", since = "1.0.0")]
199#[cfg(not(feature = "ferrocene_subset"))]
200impl<I> ExactSizeIterator for Skip<I> where I: ExactSizeIterator {}
201
202#[stable(feature = "double_ended_skip_iterator", since = "1.9.0")]
203#[cfg(not(feature = "ferrocene_subset"))]
204impl<I> DoubleEndedIterator for Skip<I>
205where
206    I: DoubleEndedIterator + ExactSizeIterator,
207{
208    fn next_back(&mut self) -> Option<Self::Item> {
209        if self.len() > 0 { self.iter.next_back() } else { None }
210    }
211
212    #[inline]
213    fn nth_back(&mut self, n: usize) -> Option<I::Item> {
214        let len = self.len();
215        if n < len {
216            self.iter.nth_back(n)
217        } else {
218            if len > 0 {
219                // consume the original iterator
220                self.iter.nth_back(len - 1);
221            }
222            None
223        }
224    }
225
226    fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
227    where
228        Self: Sized,
229        Fold: FnMut(Acc, Self::Item) -> R,
230        R: Try<Output = Acc>,
231    {
232        fn check<T, Acc, R: Try<Output = Acc>>(
233            mut n: usize,
234            mut fold: impl FnMut(Acc, T) -> R,
235        ) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> {
236            move |acc, x| {
237                n -= 1;
238                let r = fold(acc, x);
239                if n == 0 { ControlFlow::Break(r) } else { ControlFlow::from_try(r) }
240            }
241        }
242
243        let n = self.len();
244        if n == 0 { try { init } } else { self.iter.try_rfold(init, check(n, fold)).into_try() }
245    }
246
247    impl_fold_via_try_fold! { rfold -> try_rfold }
248
249    #[inline]
250    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
251        let min = crate::cmp::min(self.len(), n);
252        let rem = self.iter.advance_back_by(min);
253        assert!(rem.is_ok(), "ExactSizeIterator contract violation");
254        NonZero::new(n - min).map_or(Ok(()), Err)
255    }
256}
257
258#[stable(feature = "fused", since = "1.26.0")]
259#[cfg(not(feature = "ferrocene_subset"))]
260impl<I> FusedIterator for Skip<I> where I: FusedIterator {}
261
262#[unstable(issue = "none", feature = "trusted_fused")]
263#[cfg(not(feature = "ferrocene_subset"))]
264unsafe impl<I: TrustedFused> TrustedFused for Skip<I> {}
265
266#[unstable(issue = "none", feature = "inplace_iteration")]
267#[cfg(not(feature = "ferrocene_subset"))]
268unsafe impl<I> SourceIter for Skip<I>
269where
270    I: SourceIter,
271{
272    type Source = I::Source;
273
274    #[inline]
275    unsafe fn as_inner(&mut self) -> &mut I::Source {
276        // SAFETY: unsafe function forwarding to unsafe function with the same requirements
277        unsafe { SourceIter::as_inner(&mut self.iter) }
278    }
279}
280
281#[unstable(issue = "none", feature = "inplace_iteration")]
282#[cfg(not(feature = "ferrocene_subset"))]
283unsafe impl<I: InPlaceIterable> InPlaceIterable for Skip<I> {
284    const EXPAND_BY: Option<NonZero<usize>> = I::EXPAND_BY;
285    const MERGE_BY: Option<NonZero<usize>> = I::MERGE_BY;
286}
287
288#[doc(hidden)]
289#[unstable(feature = "trusted_random_access", issue = "none")]
290#[cfg(not(feature = "ferrocene_subset"))]
291unsafe impl<I> TrustedRandomAccess for Skip<I> where I: TrustedRandomAccess {}
292
293#[doc(hidden)]
294#[unstable(feature = "trusted_random_access", issue = "none")]
295#[cfg(not(feature = "ferrocene_subset"))]
296unsafe impl<I> TrustedRandomAccessNoCoerce for Skip<I>
297where
298    I: TrustedRandomAccessNoCoerce,
299{
300    const MAY_HAVE_SIDE_EFFECT: bool = I::MAY_HAVE_SIDE_EFFECT;
301}
302
303// SAFETY: This adapter is shortening. TrustedLen requires the upper bound to be calculated correctly.
304// These requirements can only be satisfied when the upper bound of the inner iterator's upper
305// bound is never `None`. I: TrustedRandomAccess happens to provide this guarantee while
306// I: TrustedLen would not.
307#[unstable(feature = "trusted_len", issue = "37572")]
308#[cfg(not(feature = "ferrocene_subset"))]
309unsafe impl<I> TrustedLen for Skip<I> where I: Iterator + TrustedRandomAccess {}