core/iter/adapters/
inspect.rs

1use crate::fmt;
2use crate::iter::adapters::SourceIter;
3use crate::iter::{FusedIterator, InPlaceIterable, TrustedFused};
4use crate::num::NonZero;
5use crate::ops::Try;
6
7/// An iterator that calls a function with a reference to each element before
8/// yielding it.
9///
10/// This `struct` is created by the [`inspect`] method on [`Iterator`]. See its
11/// documentation for more.
12///
13/// [`inspect`]: Iterator::inspect
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 Inspect<I, F> {
19    iter: I,
20    f: F,
21}
22impl<I, F> Inspect<I, F> {
23    pub(in crate::iter) fn new(iter: I, f: F) -> Inspect<I, F> {
24        Inspect { iter, f }
25    }
26}
27
28#[stable(feature = "core_impl_debug", since = "1.9.0")]
29impl<I: fmt::Debug, F> fmt::Debug for Inspect<I, F> {
30    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31        f.debug_struct("Inspect").field("iter", &self.iter).finish()
32    }
33}
34
35impl<I: Iterator, F> Inspect<I, F>
36where
37    F: FnMut(&I::Item),
38{
39    #[inline]
40    fn do_inspect(&mut self, elt: Option<I::Item>) -> Option<I::Item> {
41        if let Some(ref a) = elt {
42            (self.f)(a);
43        }
44
45        elt
46    }
47}
48
49fn inspect_fold<T, Acc>(
50    mut f: impl FnMut(&T),
51    mut fold: impl FnMut(Acc, T) -> Acc,
52) -> impl FnMut(Acc, T) -> Acc {
53    move |acc, item| {
54        f(&item);
55        fold(acc, item)
56    }
57}
58
59fn inspect_try_fold<'a, T, Acc, R>(
60    f: &'a mut impl FnMut(&T),
61    mut fold: impl FnMut(Acc, T) -> R + 'a,
62) -> impl FnMut(Acc, T) -> R + 'a {
63    move |acc, item| {
64        f(&item);
65        fold(acc, item)
66    }
67}
68
69#[stable(feature = "rust1", since = "1.0.0")]
70impl<I: Iterator, F> Iterator for Inspect<I, F>
71where
72    F: FnMut(&I::Item),
73{
74    type Item = I::Item;
75
76    #[inline]
77    fn next(&mut self) -> Option<I::Item> {
78        let next = self.iter.next();
79        self.do_inspect(next)
80    }
81
82    #[inline]
83    fn size_hint(&self) -> (usize, Option<usize>) {
84        self.iter.size_hint()
85    }
86
87    #[inline]
88    fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
89    where
90        Self: Sized,
91        Fold: FnMut(Acc, Self::Item) -> R,
92        R: Try<Output = Acc>,
93    {
94        self.iter.try_fold(init, inspect_try_fold(&mut self.f, fold))
95    }
96
97    #[inline]
98    fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
99    where
100        Fold: FnMut(Acc, Self::Item) -> Acc,
101    {
102        self.iter.fold(init, inspect_fold(self.f, fold))
103    }
104}
105
106#[stable(feature = "rust1", since = "1.0.0")]
107impl<I: DoubleEndedIterator, F> DoubleEndedIterator for Inspect<I, F>
108where
109    F: FnMut(&I::Item),
110{
111    #[inline]
112    fn next_back(&mut self) -> Option<I::Item> {
113        let next = self.iter.next_back();
114        self.do_inspect(next)
115    }
116
117    #[inline]
118    fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
119    where
120        Self: Sized,
121        Fold: FnMut(Acc, Self::Item) -> R,
122        R: Try<Output = Acc>,
123    {
124        self.iter.try_rfold(init, inspect_try_fold(&mut self.f, fold))
125    }
126
127    #[inline]
128    fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
129    where
130        Fold: FnMut(Acc, Self::Item) -> Acc,
131    {
132        self.iter.rfold(init, inspect_fold(self.f, fold))
133    }
134}
135
136#[stable(feature = "rust1", since = "1.0.0")]
137impl<I: ExactSizeIterator, F> ExactSizeIterator for Inspect<I, F>
138where
139    F: FnMut(&I::Item),
140{
141    fn len(&self) -> usize {
142        self.iter.len()
143    }
144
145    fn is_empty(&self) -> bool {
146        self.iter.is_empty()
147    }
148}
149
150#[stable(feature = "fused", since = "1.26.0")]
151impl<I: FusedIterator, F> FusedIterator for Inspect<I, F> where F: FnMut(&I::Item) {}
152
153#[unstable(issue = "none", feature = "trusted_fused")]
154unsafe impl<I: TrustedFused, F> TrustedFused for Inspect<I, F> {}
155
156#[unstable(issue = "none", feature = "inplace_iteration")]
157unsafe impl<I, F> SourceIter for Inspect<I, F>
158where
159    I: SourceIter,
160{
161    type Source = I::Source;
162
163    #[inline]
164    unsafe fn as_inner(&mut self) -> &mut I::Source {
165        // SAFETY: unsafe function forwarding to unsafe function with the same requirements
166        unsafe { SourceIter::as_inner(&mut self.iter) }
167    }
168}
169
170#[unstable(issue = "none", feature = "inplace_iteration")]
171unsafe impl<I: InPlaceIterable, F> InPlaceIterable for Inspect<I, F> {
172    const EXPAND_BY: Option<NonZero<usize>> = I::EXPAND_BY;
173    const MERGE_BY: Option<NonZero<usize>> = I::MERGE_BY;
174}