core/iter/adapters/
skip.rs

1use crate::intrinsics::unlikely;
2#[cfg(not(feature = "ferrocene_certified"))]
3use crate::iter::adapters::SourceIter;
4#[cfg(not(feature = "ferrocene_certified"))]
5use crate::iter::adapters::zip::try_get_unchecked;
6#[cfg(not(feature = "ferrocene_certified"))]
7use crate::iter::{
8    FusedIterator, InPlaceIterable, TrustedFused, TrustedLen, TrustedRandomAccess,
9    TrustedRandomAccessNoCoerce,
10};
11use crate::num::NonZero;
12#[cfg(not(feature = "ferrocene_certified"))]
13use crate::ops::{ControlFlow, Try};
14
15// Ferrocene addition: imports for certified subset
16#[cfg(feature = "ferrocene_certified")]
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_certified"), 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_certified"))]
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    #[cfg(not(feature = "ferrocene_certified"))]
93    fn last(mut self) -> Option<I::Item> {
94        if self.n > 0 {
95            // nth(n) skips n+1
96            self.iter.nth(self.n - 1)?;
97        }
98        self.iter.last()
99    }
100
101    #[inline]
102    fn size_hint(&self) -> (usize, Option<usize>) {
103        let (lower, upper) = self.iter.size_hint();
104
105        let lower = lower.saturating_sub(self.n);
106        let upper = match upper {
107            Some(x) => Some(x.saturating_sub(self.n)),
108            None => None,
109        };
110
111        (lower, upper)
112    }
113
114    #[inline]
115    fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
116    where
117        Self: Sized,
118        Fold: FnMut(Acc, Self::Item) -> R,
119        R: Try<Output = Acc>,
120    {
121        let n = self.n;
122        self.n = 0;
123        if n > 0 {
124            // nth(n) skips n+1
125            if self.iter.nth(n - 1).is_none() {
126                return try { init };
127            }
128        }
129        self.iter.try_fold(init, fold)
130    }
131
132    #[inline]
133    fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
134    where
135        Fold: FnMut(Acc, Self::Item) -> Acc,
136    {
137        if self.n > 0 {
138            // nth(n) skips n+1
139            if self.iter.nth(self.n - 1).is_none() {
140                return init;
141            }
142        }
143        self.iter.fold(init, fold)
144    }
145
146    #[inline]
147    #[rustc_inherit_overflow_checks]
148    fn advance_by(&mut self, mut n: usize) -> Result<(), NonZero<usize>> {
149        let skip_inner = self.n;
150        let skip_and_advance = skip_inner.saturating_add(n);
151
152        let remainder = match self.iter.advance_by(skip_and_advance) {
153            Ok(()) => 0,
154            Err(n) => n.get(),
155        };
156        let advanced_inner = skip_and_advance - remainder;
157        n -= advanced_inner.saturating_sub(skip_inner);
158        self.n = self.n.saturating_sub(advanced_inner);
159
160        // skip_and_advance may have saturated
161        if unlikely(remainder == 0 && n > 0) {
162            n = match self.iter.advance_by(n) {
163                Ok(()) => 0,
164                Err(n) => n.get(),
165            }
166        }
167
168        NonZero::new(n).map_or(Ok(()), Err)
169    }
170
171    #[doc(hidden)]
172    #[cfg(not(feature = "ferrocene_certified"))]
173    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
174    where
175        Self: TrustedRandomAccessNoCoerce,
176    {
177        // SAFETY: the caller must uphold the contract for
178        // `Iterator::__iterator_get_unchecked`.
179        //
180        // Dropping the skipped prefix when index 0 is passed is safe
181        // since
182        // * the caller passing index 0 means that the inner iterator has more items than `self.n`
183        // * TRA contract requires that get_unchecked will only be called once
184        //   (unless elements are copyable)
185        // * it does not conflict with in-place iteration since index 0 must be accessed
186        //   before something is written into the storage used by the prefix
187        unsafe {
188            if Self::MAY_HAVE_SIDE_EFFECT && idx == 0 {
189                for skipped_idx in 0..self.n {
190                    drop(try_get_unchecked(&mut self.iter, skipped_idx));
191                }
192            }
193
194            try_get_unchecked(&mut self.iter, idx + self.n)
195        }
196    }
197}
198
199#[stable(feature = "rust1", since = "1.0.0")]
200#[cfg(not(feature = "ferrocene_certified"))]
201impl<I> ExactSizeIterator for Skip<I> where I: ExactSizeIterator {}
202
203#[stable(feature = "double_ended_skip_iterator", since = "1.9.0")]
204#[cfg(not(feature = "ferrocene_certified"))]
205impl<I> DoubleEndedIterator for Skip<I>
206where
207    I: DoubleEndedIterator + ExactSizeIterator,
208{
209    fn next_back(&mut self) -> Option<Self::Item> {
210        if self.len() > 0 { self.iter.next_back() } else { None }
211    }
212
213    #[inline]
214    fn nth_back(&mut self, n: usize) -> Option<I::Item> {
215        let len = self.len();
216        if n < len {
217            self.iter.nth_back(n)
218        } else {
219            if len > 0 {
220                // consume the original iterator
221                self.iter.nth_back(len - 1);
222            }
223            None
224        }
225    }
226
227    fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
228    where
229        Self: Sized,
230        Fold: FnMut(Acc, Self::Item) -> R,
231        R: Try<Output = Acc>,
232    {
233        fn check<T, Acc, R: Try<Output = Acc>>(
234            mut n: usize,
235            mut fold: impl FnMut(Acc, T) -> R,
236        ) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> {
237            move |acc, x| {
238                n -= 1;
239                let r = fold(acc, x);
240                if n == 0 { ControlFlow::Break(r) } else { ControlFlow::from_try(r) }
241            }
242        }
243
244        let n = self.len();
245        if n == 0 { try { init } } else { self.iter.try_rfold(init, check(n, fold)).into_try() }
246    }
247
248    impl_fold_via_try_fold! { rfold -> try_rfold }
249
250    #[inline]
251    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
252        let min = crate::cmp::min(self.len(), n);
253        let rem = self.iter.advance_back_by(min);
254        assert!(rem.is_ok(), "ExactSizeIterator contract violation");
255        NonZero::new(n - min).map_or(Ok(()), Err)
256    }
257}
258
259#[stable(feature = "fused", since = "1.26.0")]
260#[cfg(not(feature = "ferrocene_certified"))]
261impl<I> FusedIterator for Skip<I> where I: FusedIterator {}
262
263#[unstable(issue = "none", feature = "trusted_fused")]
264#[cfg(not(feature = "ferrocene_certified"))]
265unsafe impl<I: TrustedFused> TrustedFused for Skip<I> {}
266
267#[unstable(issue = "none", feature = "inplace_iteration")]
268#[cfg(not(feature = "ferrocene_certified"))]
269unsafe impl<I> SourceIter for Skip<I>
270where
271    I: SourceIter,
272{
273    type Source = I::Source;
274
275    #[inline]
276    unsafe fn as_inner(&mut self) -> &mut I::Source {
277        // SAFETY: unsafe function forwarding to unsafe function with the same requirements
278        unsafe { SourceIter::as_inner(&mut self.iter) }
279    }
280}
281
282#[unstable(issue = "none", feature = "inplace_iteration")]
283#[cfg(not(feature = "ferrocene_certified"))]
284unsafe impl<I: InPlaceIterable> InPlaceIterable for Skip<I> {
285    const EXPAND_BY: Option<NonZero<usize>> = I::EXPAND_BY;
286    const MERGE_BY: Option<NonZero<usize>> = I::MERGE_BY;
287}
288
289#[doc(hidden)]
290#[unstable(feature = "trusted_random_access", issue = "none")]
291#[cfg(not(feature = "ferrocene_certified"))]
292unsafe impl<I> TrustedRandomAccess for Skip<I> where I: TrustedRandomAccess {}
293
294#[doc(hidden)]
295#[unstable(feature = "trusted_random_access", issue = "none")]
296#[cfg(not(feature = "ferrocene_certified"))]
297unsafe impl<I> TrustedRandomAccessNoCoerce for Skip<I>
298where
299    I: TrustedRandomAccessNoCoerce,
300{
301    const MAY_HAVE_SIDE_EFFECT: bool = I::MAY_HAVE_SIDE_EFFECT;
302}
303
304// SAFETY: This adapter is shortening. TrustedLen requires the upper bound to be calculated correctly.
305// These requirements can only be satisfied when the upper bound of the inner iterator's upper
306// bound is never `None`. I: TrustedRandomAccess happens to provide this guarantee while
307// I: TrustedLen would not.
308#[unstable(feature = "trusted_len", issue = "37572")]
309#[cfg(not(feature = "ferrocene_certified"))]
310unsafe impl<I> TrustedLen for Skip<I> where I: Iterator + TrustedRandomAccess {}