core/iter/adapters/
filter_map.rs

1use crate::iter::adapters::SourceIter;
2use crate::iter::{FusedIterator, InPlaceIterable, TrustedFused};
3use crate::mem::{ManuallyDrop, MaybeUninit};
4use crate::num::NonZero;
5use crate::ops::{ControlFlow, Try};
6use crate::{array, fmt};
7
8/// An iterator that uses `f` to both filter and map elements from `iter`.
9///
10/// This `struct` is created by the [`filter_map`] method on [`Iterator`]. See its
11/// documentation for more.
12///
13/// [`filter_map`]: Iterator::filter_map
14/// [`Iterator`]: trait.Iterator.html
15#[must_use = "iterators are lazy and do nothing unless consumed"]
16#[stable(feature = "rust1", since = "1.0.0")]
17#[derive(Clone)]
18pub struct FilterMap<I, F> {
19    iter: I,
20    f: F,
21}
22impl<I, F> FilterMap<I, F> {
23    pub(in crate::iter) fn new(iter: I, f: F) -> FilterMap<I, F> {
24        FilterMap { iter, f }
25    }
26}
27
28#[stable(feature = "core_impl_debug", since = "1.9.0")]
29impl<I: fmt::Debug, F> fmt::Debug for FilterMap<I, F> {
30    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31        f.debug_struct("FilterMap").field("iter", &self.iter).finish()
32    }
33}
34
35fn filter_map_fold<T, B, Acc>(
36    mut f: impl FnMut(T) -> Option<B>,
37    mut fold: impl FnMut(Acc, B) -> Acc,
38) -> impl FnMut(Acc, T) -> Acc {
39    move |acc, item| match f(item) {
40        Some(x) => fold(acc, x),
41        None => acc,
42    }
43}
44
45fn filter_map_try_fold<'a, T, B, Acc, R: Try<Output = Acc>>(
46    f: &'a mut impl FnMut(T) -> Option<B>,
47    mut fold: impl FnMut(Acc, B) -> R + 'a,
48) -> impl FnMut(Acc, T) -> R + 'a {
49    move |acc, item| match f(item) {
50        Some(x) => fold(acc, x),
51        None => try { acc },
52    }
53}
54
55#[stable(feature = "rust1", since = "1.0.0")]
56impl<B, I: Iterator, F> Iterator for FilterMap<I, F>
57where
58    F: FnMut(I::Item) -> Option<B>,
59{
60    type Item = B;
61
62    #[inline]
63    fn next(&mut self) -> Option<B> {
64        self.iter.find_map(&mut self.f)
65    }
66
67    #[inline]
68    fn next_chunk<const N: usize>(
69        &mut self,
70    ) -> Result<[Self::Item; N], array::IntoIter<Self::Item, N>> {
71        let mut array: [MaybeUninit<Self::Item>; N] = [const { MaybeUninit::uninit() }; N];
72
73        struct Guard<'a, T> {
74            array: &'a mut [MaybeUninit<T>],
75            initialized: usize,
76        }
77
78        impl<T> Drop for Guard<'_, T> {
79            #[inline]
80            fn drop(&mut self) {
81                if const { crate::mem::needs_drop::<T>() } {
82                    // SAFETY: self.initialized is always <= N, which also is the length of the array.
83                    unsafe {
84                        self.array.get_unchecked_mut(..self.initialized).assume_init_drop();
85                    }
86                }
87            }
88        }
89
90        let mut guard = Guard { array: &mut array, initialized: 0 };
91
92        let result = self.iter.try_for_each(|element| {
93            let idx = guard.initialized;
94            let val = (self.f)(element);
95            guard.initialized = idx + val.is_some() as usize;
96
97            // SAFETY: Loop conditions ensure the index is in bounds.
98
99            unsafe {
100                let opt_payload_at: *const MaybeUninit<B> =
101                    (&raw const val).byte_add(core::mem::offset_of!(Option<B>, Some.0)).cast();
102                let dst = guard.array.as_mut_ptr().add(idx);
103                crate::ptr::copy_nonoverlapping(opt_payload_at, dst, 1);
104                crate::mem::forget(val);
105            };
106
107            if guard.initialized < N { ControlFlow::Continue(()) } else { ControlFlow::Break(()) }
108        });
109
110        let guard = ManuallyDrop::new(guard);
111
112        match result {
113            ControlFlow::Break(()) => {
114                // SAFETY: The loop above is only explicitly broken when the array has been fully initialized
115                Ok(unsafe { MaybeUninit::array_assume_init(array) })
116            }
117            ControlFlow::Continue(()) => {
118                let initialized = guard.initialized;
119                // SAFETY: The range is in bounds since the loop breaks when reaching N elements.
120                Err(unsafe { array::IntoIter::new_unchecked(array, 0..initialized) })
121            }
122        }
123    }
124
125    #[inline]
126    fn size_hint(&self) -> (usize, Option<usize>) {
127        let (_, upper) = self.iter.size_hint();
128        (0, upper) // can't know a lower bound, due to the predicate
129    }
130
131    #[inline]
132    fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
133    where
134        Self: Sized,
135        Fold: FnMut(Acc, Self::Item) -> R,
136        R: Try<Output = Acc>,
137    {
138        self.iter.try_fold(init, filter_map_try_fold(&mut self.f, fold))
139    }
140
141    #[inline]
142    fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
143    where
144        Fold: FnMut(Acc, Self::Item) -> Acc,
145    {
146        self.iter.fold(init, filter_map_fold(self.f, fold))
147    }
148}
149
150#[stable(feature = "rust1", since = "1.0.0")]
151impl<B, I: DoubleEndedIterator, F> DoubleEndedIterator for FilterMap<I, F>
152where
153    F: FnMut(I::Item) -> Option<B>,
154{
155    #[inline]
156    fn next_back(&mut self) -> Option<B> {
157        #[inline]
158        fn find<T, B>(
159            f: &mut impl FnMut(T) -> Option<B>,
160        ) -> impl FnMut((), T) -> ControlFlow<B> + '_ {
161            move |(), x| match f(x) {
162                Some(x) => ControlFlow::Break(x),
163                None => ControlFlow::Continue(()),
164            }
165        }
166
167        self.iter.try_rfold((), find(&mut self.f)).break_value()
168    }
169
170    #[inline]
171    fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
172    where
173        Self: Sized,
174        Fold: FnMut(Acc, Self::Item) -> R,
175        R: Try<Output = Acc>,
176    {
177        self.iter.try_rfold(init, filter_map_try_fold(&mut self.f, fold))
178    }
179
180    #[inline]
181    fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
182    where
183        Fold: FnMut(Acc, Self::Item) -> Acc,
184    {
185        self.iter.rfold(init, filter_map_fold(self.f, fold))
186    }
187}
188
189#[stable(feature = "fused", since = "1.26.0")]
190impl<B, I: FusedIterator, F> FusedIterator for FilterMap<I, F> where F: FnMut(I::Item) -> Option<B> {}
191
192#[unstable(issue = "none", feature = "trusted_fused")]
193unsafe impl<I: TrustedFused, F> TrustedFused for FilterMap<I, F> {}
194
195#[unstable(issue = "none", feature = "inplace_iteration")]
196unsafe impl<I, F> SourceIter for FilterMap<I, F>
197where
198    I: SourceIter,
199{
200    type Source = I::Source;
201
202    #[inline]
203    unsafe fn as_inner(&mut self) -> &mut I::Source {
204        // SAFETY: unsafe function forwarding to unsafe function with the same requirements
205        unsafe { SourceIter::as_inner(&mut self.iter) }
206    }
207}
208
209#[unstable(issue = "none", feature = "inplace_iteration")]
210unsafe impl<I: InPlaceIterable, F> InPlaceIterable for FilterMap<I, F> {
211    const EXPAND_BY: Option<NonZero<usize>> = I::EXPAND_BY;
212    const MERGE_BY: Option<NonZero<usize>> = I::MERGE_BY;
213}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy