core/iter/adapters/
map.rs

1#[cfg(not(feature = "ferrocene_certified"))]
2use crate::fmt;
3#[cfg(not(feature = "ferrocene_certified"))]
4use crate::iter::adapters::zip::try_get_unchecked;
5#[cfg(not(feature = "ferrocene_certified"))]
6use crate::iter::adapters::{SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce};
7#[cfg(not(feature = "ferrocene_certified"))]
8use crate::iter::{FusedIterator, InPlaceIterable, TrustedFused, TrustedLen, UncheckedIterator};
9#[cfg(not(feature = "ferrocene_certified"))]
10use crate::num::NonZero;
11use crate::ops::Try;
12
13// Ferrocene addition: imports for certified subset
14#[cfg(feature = "ferrocene_certified")]
15#[rustfmt::skip]
16use crate::iter::{TrustedLen, UncheckedIterator};
17
18/// An iterator that maps the values of `iter` with `f`.
19///
20/// This `struct` is created by the [`map`] method on [`Iterator`]. See its
21/// documentation for more.
22///
23/// [`map`]: Iterator::map
24/// [`Iterator`]: trait.Iterator.html
25///
26/// # Notes about side effects
27///
28/// The [`map`] iterator implements [`DoubleEndedIterator`], meaning that
29/// you can also [`map`] backwards:
30///
31/// ```rust
32/// let v: Vec<i32> = [1, 2, 3].into_iter().map(|x| x + 1).rev().collect();
33///
34/// assert_eq!(v, [4, 3, 2]);
35/// ```
36///
37/// [`DoubleEndedIterator`]: trait.DoubleEndedIterator.html
38///
39/// But if your closure has state, iterating backwards may act in a way you do
40/// not expect. Let's go through an example. First, in the forward direction:
41///
42/// ```rust
43/// let mut c = 0;
44///
45/// for pair in ['a', 'b', 'c'].into_iter()
46///                                .map(|letter| { c += 1; (letter, c) }) {
47///     println!("{pair:?}");
48/// }
49/// ```
50///
51/// This will print `('a', 1), ('b', 2), ('c', 3)`.
52///
53/// Now consider this twist where we add a call to `rev`. This version will
54/// print `('c', 1), ('b', 2), ('a', 3)`. Note that the letters are reversed,
55/// but the values of the counter still go in order. This is because `map()` is
56/// still being called lazily on each item, but we are popping items off the
57/// back of the vector now, instead of shifting them from the front.
58///
59/// ```rust
60/// let mut c = 0;
61///
62/// for pair in ['a', 'b', 'c'].into_iter()
63///                                .map(|letter| { c += 1; (letter, c) })
64///                                .rev() {
65///     println!("{pair:?}");
66/// }
67/// ```
68#[must_use = "iterators are lazy and do nothing unless consumed"]
69#[stable(feature = "rust1", since = "1.0.0")]
70#[derive(Clone)]
71pub struct Map<I, F> {
72    // Used for `SplitWhitespace` and `SplitAsciiWhitespace` `as_str` methods
73    pub(crate) iter: I,
74    f: F,
75}
76
77impl<I, F> Map<I, F> {
78    pub(in crate::iter) fn new(iter: I, f: F) -> Map<I, F> {
79        Map { iter, f }
80    }
81
82    #[cfg(not(feature = "ferrocene_certified"))]
83    pub(crate) fn into_inner(self) -> I {
84        self.iter
85    }
86}
87
88#[stable(feature = "core_impl_debug", since = "1.9.0")]
89#[cfg(not(feature = "ferrocene_certified"))]
90impl<I: fmt::Debug, F> fmt::Debug for Map<I, F> {
91    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92        f.debug_struct("Map").field("iter", &self.iter).finish()
93    }
94}
95
96fn map_fold<T, B, Acc>(
97    mut f: impl FnMut(T) -> B,
98    mut g: impl FnMut(Acc, B) -> Acc,
99) -> impl FnMut(Acc, T) -> Acc {
100    move |acc, elt| g(acc, f(elt))
101}
102
103fn map_try_fold<'a, T, B, Acc, R>(
104    f: &'a mut impl FnMut(T) -> B,
105    mut g: impl FnMut(Acc, B) -> R + 'a,
106) -> impl FnMut(Acc, T) -> R + 'a {
107    move |acc, elt| g(acc, f(elt))
108}
109
110#[stable(feature = "rust1", since = "1.0.0")]
111impl<B, I: Iterator, F> Iterator for Map<I, F>
112where
113    F: FnMut(I::Item) -> B,
114{
115    type Item = B;
116
117    #[inline]
118    fn next(&mut self) -> Option<B> {
119        self.iter.next().map(&mut self.f)
120    }
121
122    #[inline]
123    fn size_hint(&self) -> (usize, Option<usize>) {
124        self.iter.size_hint()
125    }
126
127    fn try_fold<Acc, G, R>(&mut self, init: Acc, g: G) -> R
128    where
129        Self: Sized,
130        G: FnMut(Acc, Self::Item) -> R,
131        R: Try<Output = Acc>,
132    {
133        self.iter.try_fold(init, map_try_fold(&mut self.f, g))
134    }
135
136    fn fold<Acc, G>(self, init: Acc, g: G) -> Acc
137    where
138        G: FnMut(Acc, Self::Item) -> Acc,
139    {
140        self.iter.fold(init, map_fold(self.f, g))
141    }
142
143    #[inline]
144    #[cfg(not(feature = "ferrocene_certified"))]
145    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> B
146    where
147        Self: TrustedRandomAccessNoCoerce,
148    {
149        // SAFETY: the caller must uphold the contract for
150        // `Iterator::__iterator_get_unchecked`.
151        unsafe { (self.f)(try_get_unchecked(&mut self.iter, idx)) }
152    }
153}
154
155#[stable(feature = "rust1", since = "1.0.0")]
156#[cfg(not(feature = "ferrocene_certified"))]
157impl<B, I: DoubleEndedIterator, F> DoubleEndedIterator for Map<I, F>
158where
159    F: FnMut(I::Item) -> B,
160{
161    #[inline]
162    fn next_back(&mut self) -> Option<B> {
163        self.iter.next_back().map(&mut self.f)
164    }
165
166    fn try_rfold<Acc, G, R>(&mut self, init: Acc, g: G) -> R
167    where
168        Self: Sized,
169        G: FnMut(Acc, Self::Item) -> R,
170        R: Try<Output = Acc>,
171    {
172        self.iter.try_rfold(init, map_try_fold(&mut self.f, g))
173    }
174
175    fn rfold<Acc, G>(self, init: Acc, g: G) -> Acc
176    where
177        G: FnMut(Acc, Self::Item) -> Acc,
178    {
179        self.iter.rfold(init, map_fold(self.f, g))
180    }
181}
182
183#[stable(feature = "rust1", since = "1.0.0")]
184#[cfg(not(feature = "ferrocene_certified"))]
185impl<B, I: ExactSizeIterator, F> ExactSizeIterator for Map<I, F>
186where
187    F: FnMut(I::Item) -> B,
188{
189    fn len(&self) -> usize {
190        self.iter.len()
191    }
192
193    fn is_empty(&self) -> bool {
194        self.iter.is_empty()
195    }
196}
197
198#[stable(feature = "fused", since = "1.26.0")]
199#[cfg(not(feature = "ferrocene_certified"))]
200impl<B, I: FusedIterator, F> FusedIterator for Map<I, F> where F: FnMut(I::Item) -> B {}
201
202#[unstable(issue = "none", feature = "trusted_fused")]
203#[cfg(not(feature = "ferrocene_certified"))]
204unsafe impl<I: TrustedFused, F> TrustedFused for Map<I, F> {}
205
206#[unstable(feature = "trusted_len", issue = "37572")]
207unsafe impl<B, I, F> TrustedLen for Map<I, F>
208where
209    I: TrustedLen,
210    F: FnMut(I::Item) -> B,
211{
212}
213
214impl<B, I, F> UncheckedIterator for Map<I, F>
215where
216    I: UncheckedIterator,
217    F: FnMut(I::Item) -> B,
218{
219    unsafe fn next_unchecked(&mut self) -> B {
220        // SAFETY: `Map` is 1:1 with the inner iterator, so if the caller promised
221        // that there's an element left, the inner iterator has one too.
222        let item = unsafe { self.iter.next_unchecked() };
223        (self.f)(item)
224    }
225}
226
227#[doc(hidden)]
228#[unstable(feature = "trusted_random_access", issue = "none")]
229#[cfg(not(feature = "ferrocene_certified"))]
230unsafe impl<I, F> TrustedRandomAccess for Map<I, F> where I: TrustedRandomAccess {}
231
232#[doc(hidden)]
233#[unstable(feature = "trusted_random_access", issue = "none")]
234#[cfg(not(feature = "ferrocene_certified"))]
235unsafe impl<I, F> TrustedRandomAccessNoCoerce for Map<I, F>
236where
237    I: TrustedRandomAccessNoCoerce,
238{
239    const MAY_HAVE_SIDE_EFFECT: bool = true;
240}
241
242#[unstable(issue = "none", feature = "inplace_iteration")]
243#[cfg(not(feature = "ferrocene_certified"))]
244unsafe impl<I, F> SourceIter for Map<I, F>
245where
246    I: SourceIter,
247{
248    type Source = I::Source;
249
250    #[inline]
251    unsafe fn as_inner(&mut self) -> &mut I::Source {
252        // SAFETY: unsafe function forwarding to unsafe function with the same requirements
253        unsafe { SourceIter::as_inner(&mut self.iter) }
254    }
255}
256
257#[unstable(issue = "none", feature = "inplace_iteration")]
258#[cfg(not(feature = "ferrocene_certified"))]
259unsafe impl<I: InPlaceIterable, F> InPlaceIterable for Map<I, F> {
260    const EXPAND_BY: Option<NonZero<usize>> = I::EXPAND_BY;
261    const MERGE_BY: Option<NonZero<usize>> = I::MERGE_BY;
262}