Skip to main content

core/iter/adapters/
take_while.rs

1use crate::fmt;
2#[cfg(not(feature = "ferrocene_subset"))]
3use crate::iter::adapters::SourceIter;
4#[cfg(not(feature = "ferrocene_subset"))]
5use crate::iter::{FusedIterator, InPlaceIterable, TrustedFused};
6#[cfg(not(feature = "ferrocene_subset"))]
7use crate::num::NonZero;
8use crate::ops::{ControlFlow, Try};
9
10/// An iterator that only accepts elements while `predicate` returns `true`.
11///
12/// This `struct` is created by the [`take_while`] method on [`Iterator`]. See its
13/// documentation for more.
14///
15/// [`take_while`]: Iterator::take_while
16/// [`Iterator`]: trait.Iterator.html
17#[must_use = "iterators are lazy and do nothing unless consumed"]
18#[stable(feature = "rust1", since = "1.0.0")]
19#[derive(Clone)]
20pub struct TakeWhile<I, P> {
21    iter: I,
22    flag: bool,
23    predicate: P,
24}
25
26impl<I, P> TakeWhile<I, P> {
27    pub(in crate::iter) fn new(iter: I, predicate: P) -> TakeWhile<I, P> {
28        TakeWhile { iter, flag: false, predicate }
29    }
30}
31
32#[stable(feature = "core_impl_debug", since = "1.9.0")]
33impl<I: fmt::Debug, P> fmt::Debug for TakeWhile<I, P> {
34    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35        f.debug_struct("TakeWhile").field("iter", &self.iter).field("flag", &self.flag).finish()
36    }
37}
38
39#[stable(feature = "rust1", since = "1.0.0")]
40impl<I: Iterator, P> Iterator for TakeWhile<I, P>
41where
42    P: FnMut(&I::Item) -> bool,
43{
44    type Item = I::Item;
45
46    #[inline]
47    fn next(&mut self) -> Option<I::Item> {
48        if self.flag {
49            None
50        } else {
51            let x = self.iter.next()?;
52            if (self.predicate)(&x) {
53                Some(x)
54            } else {
55                self.flag = true;
56                None
57            }
58        }
59    }
60
61    #[inline]
62    fn size_hint(&self) -> (usize, Option<usize>) {
63        if self.flag {
64            (0, Some(0))
65        } else {
66            let (_, upper) = self.iter.size_hint();
67            (0, upper) // can't know a lower bound, due to the predicate
68        }
69    }
70
71    #[inline]
72    fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
73    where
74        Self: Sized,
75        Fold: FnMut(Acc, Self::Item) -> R,
76        R: Try<Output = Acc>,
77    {
78        fn check<'a, T, Acc, R: Try<Output = Acc>>(
79            flag: &'a mut bool,
80            p: &'a mut impl FnMut(&T) -> bool,
81            mut fold: impl FnMut(Acc, T) -> R + 'a,
82        ) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> + 'a {
83            move |acc, x| {
84                if p(&x) {
85                    ControlFlow::from_try(fold(acc, x))
86                } else {
87                    *flag = true;
88                    ControlFlow::Break(try { acc })
89                }
90            }
91        }
92
93        if self.flag {
94            try { init }
95        } else {
96            let flag = &mut self.flag;
97            let p = &mut self.predicate;
98            self.iter.try_fold(init, check(flag, p, fold)).into_try()
99        }
100    }
101
102    impl_fold_via_try_fold! { fold -> try_fold }
103}
104
105#[cfg(not(feature = "ferrocene_subset"))]
106#[stable(feature = "fused", since = "1.26.0")]
107impl<I, P> FusedIterator for TakeWhile<I, P>
108where
109    I: FusedIterator,
110    P: FnMut(&I::Item) -> bool,
111{
112}
113
114#[cfg(not(feature = "ferrocene_subset"))]
115#[unstable(issue = "none", feature = "trusted_fused")]
116unsafe impl<I: TrustedFused, P> TrustedFused for TakeWhile<I, P> {}
117
118#[cfg(not(feature = "ferrocene_subset"))]
119#[unstable(issue = "none", feature = "inplace_iteration")]
120unsafe impl<P, I> SourceIter for TakeWhile<I, P>
121where
122    I: SourceIter,
123{
124    type Source = I::Source;
125
126    #[inline]
127    unsafe fn as_inner(&mut self) -> &mut I::Source {
128        // SAFETY: unsafe function forwarding to unsafe function with the same requirements
129        unsafe { SourceIter::as_inner(&mut self.iter) }
130    }
131}
132
133#[cfg(not(feature = "ferrocene_subset"))]
134#[unstable(issue = "none", feature = "inplace_iteration")]
135unsafe impl<I: InPlaceIterable, F> InPlaceIterable for TakeWhile<I, F> {
136    const EXPAND_BY: Option<NonZero<usize>> = I::EXPAND_BY;
137    const MERGE_BY: Option<NonZero<usize>> = I::MERGE_BY;
138}