core/iter/adapters/
enumerate.rs

1#[cfg(not(feature = "ferrocene_certified"))]
2use crate::iter::adapters::zip::try_get_unchecked;
3#[cfg(not(feature = "ferrocene_certified"))]
4use crate::iter::adapters::{SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce};
5#[cfg(not(feature = "ferrocene_certified"))]
6use crate::iter::{FusedIterator, InPlaceIterable, TrustedFused, TrustedLen};
7use crate::num::NonZero;
8use crate::ops::Try;
9
10/// An iterator that yields the current count and the element during iteration.
11///
12/// This `struct` is created by the [`enumerate`] method on [`Iterator`]. See its
13/// documentation for more.
14///
15/// [`enumerate`]: Iterator::enumerate
16/// [`Iterator`]: trait.Iterator.html
17#[cfg_attr(not(feature = "ferrocene_certified"), derive(Clone, Debug))]
18#[must_use = "iterators are lazy and do nothing unless consumed"]
19#[stable(feature = "rust1", since = "1.0.0")]
20#[rustc_diagnostic_item = "Enumerate"]
21pub struct Enumerate<I> {
22    iter: I,
23    count: usize,
24}
25impl<I> Enumerate<I> {
26    pub(in crate::iter) fn new(iter: I) -> Enumerate<I> {
27        Enumerate { iter, count: 0 }
28    }
29
30    /// Retrieve the current position of the iterator.
31    ///
32    /// If the iterator has not advanced, the position returned will be 0.
33    ///
34    /// The position may also exceed the bounds of the iterator to allow for calculating
35    /// the displacement of the iterator from following calls to [`Iterator::next`].
36    ///
37    /// # Examples
38    ///
39    /// ```
40    /// #![feature(next_index)]
41    ///
42    /// let arr = ['a', 'b'];
43    ///
44    /// let mut iter = arr.iter().enumerate();
45    ///
46    /// assert_eq!(iter.next_index(), 0);
47    /// assert_eq!(iter.next(), Some((0, &'a')));
48    ///
49    /// assert_eq!(iter.next_index(), 1);
50    /// assert_eq!(iter.next_index(), 1);
51    /// assert_eq!(iter.next(), Some((1, &'b')));
52    ///
53    /// assert_eq!(iter.next_index(), 2);
54    /// assert_eq!(iter.next(), None);
55    /// assert_eq!(iter.next_index(), 2);
56    /// ```
57    #[inline]
58    #[unstable(feature = "next_index", issue = "130711")]
59    #[cfg(not(feature = "ferrocene_certified"))]
60    pub fn next_index(&self) -> usize {
61        self.count
62    }
63}
64
65#[stable(feature = "rust1", since = "1.0.0")]
66impl<I> Iterator for Enumerate<I>
67where
68    I: Iterator,
69{
70    type Item = (usize, <I as Iterator>::Item);
71
72    /// # Overflow Behavior
73    ///
74    /// The method does no guarding against overflows, so enumerating more than
75    /// `usize::MAX` elements either produces the wrong result or panics. If
76    /// overflow checks are enabled, a panic is guaranteed.
77    ///
78    /// # Panics
79    ///
80    /// Might panic if the index of the element overflows a `usize`.
81    #[inline]
82    #[rustc_inherit_overflow_checks]
83    fn next(&mut self) -> Option<(usize, <I as Iterator>::Item)> {
84        let a = self.iter.next()?;
85        let i = self.count;
86        self.count += 1;
87        Some((i, a))
88    }
89
90    #[inline]
91    fn size_hint(&self) -> (usize, Option<usize>) {
92        self.iter.size_hint()
93    }
94
95    #[inline]
96    #[rustc_inherit_overflow_checks]
97    fn nth(&mut self, n: usize) -> Option<(usize, I::Item)> {
98        let a = self.iter.nth(n)?;
99        let i = self.count + n;
100        self.count = i + 1;
101        Some((i, a))
102    }
103
104    #[inline]
105    #[cfg(not(feature = "ferrocene_certified"))]
106    fn count(self) -> usize {
107        self.iter.count()
108    }
109
110    #[inline]
111    fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
112    where
113        Self: Sized,
114        Fold: FnMut(Acc, Self::Item) -> R,
115        R: Try<Output = Acc>,
116    {
117        #[inline]
118        fn enumerate<'a, T, Acc, R>(
119            count: &'a mut usize,
120            mut fold: impl FnMut(Acc, (usize, T)) -> R + 'a,
121        ) -> impl FnMut(Acc, T) -> R + 'a {
122            #[rustc_inherit_overflow_checks]
123            move |acc, item| {
124                let acc = fold(acc, (*count, item));
125                *count += 1;
126                acc
127            }
128        }
129
130        self.iter.try_fold(init, enumerate(&mut self.count, fold))
131    }
132
133    #[inline]
134    fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
135    where
136        Fold: FnMut(Acc, Self::Item) -> Acc,
137    {
138        #[inline]
139        fn enumerate<T, Acc>(
140            mut count: usize,
141            mut fold: impl FnMut(Acc, (usize, T)) -> Acc,
142        ) -> impl FnMut(Acc, T) -> Acc {
143            #[rustc_inherit_overflow_checks]
144            move |acc, item| {
145                let acc = fold(acc, (count, item));
146                count += 1;
147                acc
148            }
149        }
150
151        self.iter.fold(init, enumerate(self.count, fold))
152    }
153
154    #[inline]
155    #[rustc_inherit_overflow_checks]
156    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
157        let remaining = self.iter.advance_by(n);
158        let advanced = match remaining {
159            Ok(()) => n,
160            Err(rem) => n - rem.get(),
161        };
162        self.count += advanced;
163        remaining
164    }
165
166    #[rustc_inherit_overflow_checks]
167    #[inline]
168    #[cfg(not(feature = "ferrocene_certified"))]
169    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item
170    where
171        Self: TrustedRandomAccessNoCoerce,
172    {
173        // SAFETY: the caller must uphold the contract for
174        // `Iterator::__iterator_get_unchecked`.
175        let value = unsafe { try_get_unchecked(&mut self.iter, idx) };
176        (self.count + idx, value)
177    }
178}
179
180#[stable(feature = "rust1", since = "1.0.0")]
181#[cfg(not(feature = "ferrocene_certified"))]
182impl<I> DoubleEndedIterator for Enumerate<I>
183where
184    I: ExactSizeIterator + DoubleEndedIterator,
185{
186    #[inline]
187    fn next_back(&mut self) -> Option<(usize, <I as Iterator>::Item)> {
188        let a = self.iter.next_back()?;
189        let len = self.iter.len();
190        // Can safely add, `ExactSizeIterator` promises that the number of
191        // elements fits into a `usize`.
192        Some((self.count + len, a))
193    }
194
195    #[inline]
196    fn nth_back(&mut self, n: usize) -> Option<(usize, <I as Iterator>::Item)> {
197        let a = self.iter.nth_back(n)?;
198        let len = self.iter.len();
199        // Can safely add, `ExactSizeIterator` promises that the number of
200        // elements fits into a `usize`.
201        Some((self.count + len, a))
202    }
203
204    #[inline]
205    fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
206    where
207        Self: Sized,
208        Fold: FnMut(Acc, Self::Item) -> R,
209        R: Try<Output = Acc>,
210    {
211        // Can safely add and subtract the count, as `ExactSizeIterator` promises
212        // that the number of elements fits into a `usize`.
213        fn enumerate<T, Acc, R>(
214            mut count: usize,
215            mut fold: impl FnMut(Acc, (usize, T)) -> R,
216        ) -> impl FnMut(Acc, T) -> R {
217            move |acc, item| {
218                count -= 1;
219                fold(acc, (count, item))
220            }
221        }
222
223        let count = self.count + self.iter.len();
224        self.iter.try_rfold(init, enumerate(count, fold))
225    }
226
227    #[inline]
228    fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
229    where
230        Fold: FnMut(Acc, Self::Item) -> Acc,
231    {
232        // Can safely add and subtract the count, as `ExactSizeIterator` promises
233        // that the number of elements fits into a `usize`.
234        fn enumerate<T, Acc>(
235            mut count: usize,
236            mut fold: impl FnMut(Acc, (usize, T)) -> Acc,
237        ) -> impl FnMut(Acc, T) -> Acc {
238            move |acc, item| {
239                count -= 1;
240                fold(acc, (count, item))
241            }
242        }
243
244        let count = self.count + self.iter.len();
245        self.iter.rfold(init, enumerate(count, fold))
246    }
247
248    #[inline]
249    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
250        // we do not need to update the count since that only tallies the number of items
251        // consumed from the front. consuming items from the back can never reduce that.
252        self.iter.advance_back_by(n)
253    }
254}
255
256#[stable(feature = "rust1", since = "1.0.0")]
257#[cfg(not(feature = "ferrocene_certified"))]
258impl<I> ExactSizeIterator for Enumerate<I>
259where
260    I: ExactSizeIterator,
261{
262    fn len(&self) -> usize {
263        self.iter.len()
264    }
265
266    fn is_empty(&self) -> bool {
267        self.iter.is_empty()
268    }
269}
270
271#[doc(hidden)]
272#[unstable(feature = "trusted_random_access", issue = "none")]
273#[cfg(not(feature = "ferrocene_certified"))]
274unsafe impl<I> TrustedRandomAccess for Enumerate<I> where I: TrustedRandomAccess {}
275
276#[doc(hidden)]
277#[unstable(feature = "trusted_random_access", issue = "none")]
278#[cfg(not(feature = "ferrocene_certified"))]
279unsafe impl<I> TrustedRandomAccessNoCoerce for Enumerate<I>
280where
281    I: TrustedRandomAccessNoCoerce,
282{
283    const MAY_HAVE_SIDE_EFFECT: bool = I::MAY_HAVE_SIDE_EFFECT;
284}
285
286#[stable(feature = "fused", since = "1.26.0")]
287#[cfg(not(feature = "ferrocene_certified"))]
288impl<I> FusedIterator for Enumerate<I> where I: FusedIterator {}
289
290#[unstable(issue = "none", feature = "trusted_fused")]
291#[cfg(not(feature = "ferrocene_certified"))]
292unsafe impl<I: TrustedFused> TrustedFused for Enumerate<I> {}
293
294#[unstable(feature = "trusted_len", issue = "37572")]
295#[cfg(not(feature = "ferrocene_certified"))]
296unsafe impl<I> TrustedLen for Enumerate<I> where I: TrustedLen {}
297
298#[unstable(issue = "none", feature = "inplace_iteration")]
299#[cfg(not(feature = "ferrocene_certified"))]
300unsafe impl<I> SourceIter for Enumerate<I>
301where
302    I: SourceIter,
303{
304    type Source = I::Source;
305
306    #[inline]
307    unsafe fn as_inner(&mut self) -> &mut I::Source {
308        // SAFETY: unsafe function forwarding to unsafe function with the same requirements
309        unsafe { SourceIter::as_inner(&mut self.iter) }
310    }
311}
312
313#[unstable(issue = "none", feature = "inplace_iteration")]
314#[cfg(not(feature = "ferrocene_certified"))]
315unsafe impl<I: InPlaceIterable> InPlaceIterable for Enumerate<I> {
316    const EXPAND_BY: Option<NonZero<usize>> = I::EXPAND_BY;
317    const MERGE_BY: Option<NonZero<usize>> = I::MERGE_BY;
318}
319
320#[stable(feature = "default_iters", since = "1.70.0")]
321#[cfg(not(feature = "ferrocene_certified"))]
322impl<I: Default> Default for Enumerate<I> {
323    /// Creates an `Enumerate` iterator from the default value of `I`
324    /// ```
325    /// # use core::slice;
326    /// # use std::iter::Enumerate;
327    /// let iter: Enumerate<slice::Iter<'_, u8>> = Default::default();
328    /// assert_eq!(iter.len(), 0);
329    /// ```
330    fn default() -> Self {
331        Enumerate::new(Default::default())
332    }
333}