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