1#[cfg(not(feature = "ferrocene_subset"))]
2use core::array;
3#[cfg(not(feature = "ferrocene_subset"))]
4use core::mem::MaybeUninit;
5#[cfg(not(feature = "ferrocene_subset"))]
6use core::ops::ControlFlow;
7
8#[cfg(not(feature = "ferrocene_subset"))]
9use crate::fmt;
10#[cfg(not(feature = "ferrocene_subset"))]
11use crate::iter::adapters::SourceIter;
12#[cfg(not(feature = "ferrocene_subset"))]
13use crate::iter::{FusedIterator, InPlaceIterable, TrustedFused, TrustedLen};
14#[cfg(not(feature = "ferrocene_subset"))]
15use crate::num::NonZero;
16use crate::ops::Try;
17
18#[must_use = "iterators are lazy and do nothing unless consumed"]
26#[stable(feature = "rust1", since = "1.0.0")]
27#[derive(Clone)]
28pub struct Filter<I, P> {
29 pub(crate) iter: I,
31 predicate: P,
32}
33impl<I, P> Filter<I, P> {
34 pub(in crate::iter) fn new(iter: I, predicate: P) -> Filter<I, P> {
35 Filter { iter, predicate }
36 }
37}
38
39#[cfg(not(feature = "ferrocene_subset"))]
40impl<I, P> Filter<I, P>
41where
42 I: Iterator,
43 P: FnMut(&I::Item) -> bool,
44{
45 #[inline]
46 fn next_chunk_dropless<const N: usize>(
47 &mut self,
48 ) -> Result<[I::Item; N], array::IntoIter<I::Item, N>> {
49 let mut array: [MaybeUninit<I::Item>; N] = [const { MaybeUninit::uninit() }; N];
50 let mut initialized = 0;
51
52 let result = self.iter.try_for_each(|element| {
53 let idx = initialized;
54 initialized = idx + (self.predicate)(&element) as usize;
57 unsafe { array.get_unchecked_mut(idx) }.write(element);
59
60 if initialized < N { ControlFlow::Continue(()) } else { ControlFlow::Break(()) }
61 });
62
63 match result {
64 ControlFlow::Break(()) => {
65 Ok(unsafe { MaybeUninit::array_assume_init(array) })
67 }
68 ControlFlow::Continue(()) => {
69 Err(unsafe { array::IntoIter::new_unchecked(array, 0..initialized) })
71 }
72 }
73 }
74}
75
76#[cfg(not(feature = "ferrocene_subset"))]
77#[stable(feature = "core_impl_debug", since = "1.9.0")]
78impl<I: fmt::Debug, P> fmt::Debug for Filter<I, P> {
79 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80 f.debug_struct("Filter").field("iter", &self.iter).finish()
81 }
82}
83
84fn filter_fold<T, Acc>(
85 mut predicate: impl FnMut(&T) -> bool,
86 mut fold: impl FnMut(Acc, T) -> Acc,
87) -> impl FnMut(Acc, T) -> Acc {
88 move |acc, item| if predicate(&item) { fold(acc, item) } else { acc }
89}
90
91fn filter_try_fold<'a, T, Acc, R: Try<Output = Acc>>(
92 predicate: &'a mut impl FnMut(&T) -> bool,
93 mut fold: impl FnMut(Acc, T) -> R + 'a,
94) -> impl FnMut(Acc, T) -> R + 'a {
95 move |acc, item| if predicate(&item) { fold(acc, item) } else { try { acc } }
96}
97
98#[stable(feature = "rust1", since = "1.0.0")]
99impl<I: Iterator, P> Iterator for Filter<I, P>
100where
101 P: FnMut(&I::Item) -> bool,
102{
103 type Item = I::Item;
104
105 #[inline]
106 fn next(&mut self) -> Option<I::Item> {
107 self.iter.find(&mut self.predicate)
108 }
109
110 #[cfg(not(feature = "ferrocene_subset"))]
111 #[inline]
112 fn next_chunk<const N: usize>(
113 &mut self,
114 ) -> Result<[Self::Item; N], array::IntoIter<Self::Item, N>> {
115 let fun = const {
117 if crate::mem::needs_drop::<I::Item>() {
118 array::iter_next_chunk::<I::Item, N>
119 } else {
120 Self::next_chunk_dropless::<N>
121 }
122 };
123
124 fun(self)
125 }
126
127 #[inline]
128 fn size_hint(&self) -> (usize, Option<usize>) {
129 let (_, upper) = self.iter.size_hint();
130 (0, upper) }
132
133 #[cfg(not(feature = "ferrocene_subset"))]
145 #[inline]
146 fn count(self) -> usize {
147 #[inline]
148 fn to_usize<T>(mut predicate: impl FnMut(&T) -> bool) -> impl FnMut(T) -> usize {
149 move |x| predicate(&x) as usize
150 }
151
152 let before = self.iter.size_hint().1.unwrap_or(usize::MAX);
153 let total = self.iter.map(to_usize(self.predicate)).sum();
154 unsafe {
156 <I as SpecAssumeCount>::assume_count_le_upper_bound(total, before);
157 }
158 total
159 }
160
161 #[inline]
162 fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
163 where
164 Self: Sized,
165 Fold: FnMut(Acc, Self::Item) -> R,
166 R: Try<Output = Acc>,
167 {
168 self.iter.try_fold(init, filter_try_fold(&mut self.predicate, fold))
169 }
170
171 #[inline]
172 fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
173 where
174 Fold: FnMut(Acc, Self::Item) -> Acc,
175 {
176 self.iter.fold(init, filter_fold(self.predicate, fold))
177 }
178}
179
180#[cfg(not(feature = "ferrocene_subset"))]
181#[stable(feature = "rust1", since = "1.0.0")]
182impl<I: DoubleEndedIterator, P> DoubleEndedIterator for Filter<I, P>
183where
184 P: FnMut(&I::Item) -> bool,
185{
186 #[inline]
187 fn next_back(&mut self) -> Option<I::Item> {
188 self.iter.rfind(&mut self.predicate)
189 }
190
191 #[inline]
192 fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
193 where
194 Self: Sized,
195 Fold: FnMut(Acc, Self::Item) -> R,
196 R: Try<Output = Acc>,
197 {
198 self.iter.try_rfold(init, filter_try_fold(&mut self.predicate, fold))
199 }
200
201 #[inline]
202 fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
203 where
204 Fold: FnMut(Acc, Self::Item) -> Acc,
205 {
206 self.iter.rfold(init, filter_fold(self.predicate, fold))
207 }
208}
209
210#[cfg(not(feature = "ferrocene_subset"))]
211#[stable(feature = "fused", since = "1.26.0")]
212impl<I: FusedIterator, P> FusedIterator for Filter<I, P> where P: FnMut(&I::Item) -> bool {}
213
214#[cfg(not(feature = "ferrocene_subset"))]
215#[unstable(issue = "none", feature = "trusted_fused")]
216unsafe impl<I: TrustedFused, F> TrustedFused for Filter<I, F> {}
217
218#[cfg(not(feature = "ferrocene_subset"))]
219#[unstable(issue = "none", feature = "inplace_iteration")]
220unsafe impl<P, I> SourceIter for Filter<I, P>
221where
222 I: SourceIter,
223{
224 type Source = I::Source;
225
226 #[inline]
227 unsafe fn as_inner(&mut self) -> &mut I::Source {
228 unsafe { SourceIter::as_inner(&mut self.iter) }
230 }
231}
232
233#[cfg(not(feature = "ferrocene_subset"))]
234#[unstable(issue = "none", feature = "inplace_iteration")]
235unsafe impl<I: InPlaceIterable, P> InPlaceIterable for Filter<I, P> {
236 const EXPAND_BY: Option<NonZero<usize>> = I::EXPAND_BY;
237 const MERGE_BY: Option<NonZero<usize>> = I::MERGE_BY;
238}
239
240#[cfg(not(feature = "ferrocene_subset"))]
241trait SpecAssumeCount {
242 unsafe fn assume_count_le_upper_bound(count: usize, upper: usize);
250}
251
252#[cfg(not(feature = "ferrocene_subset"))]
253impl<I: Iterator> SpecAssumeCount for I {
254 #[inline]
255 #[rustc_inherit_overflow_checks]
256 default unsafe fn assume_count_le_upper_bound(count: usize, upper: usize) {
257 let _ = upper - count;
262 }
263}
264
265#[cfg(not(feature = "ferrocene_subset"))]
266impl<I: TrustedLen> SpecAssumeCount for I {
267 #[inline]
268 unsafe fn assume_count_le_upper_bound(count: usize, upper: usize) {
269 unsafe { crate::hint::assert_unchecked(count <= upper) }
271 }
272}