rayon/iter/
inspect.rs

1use super::plumbing::*;
2use super::*;
3
4use std::fmt::{self, Debug};
5use std::iter;
6
7/// `Inspect` is an iterator that calls a function with a reference to each
8/// element before yielding it.
9///
10/// This struct is created by the [`inspect()`] method on [`ParallelIterator`]
11///
12/// [`inspect()`]: trait.ParallelIterator.html#method.inspect
13/// [`ParallelIterator`]: trait.ParallelIterator.html
14#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
15#[derive(Clone)]
16pub struct Inspect<I: ParallelIterator, F> {
17    base: I,
18    inspect_op: F,
19}
20
21impl<I: ParallelIterator + Debug, F> Debug for Inspect<I, F> {
22    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23        f.debug_struct("Inspect").field("base", &self.base).finish()
24    }
25}
26
27impl<I, F> Inspect<I, F>
28where
29    I: ParallelIterator,
30{
31    /// Creates a new `Inspect` iterator.
32    pub(super) fn new(base: I, inspect_op: F) -> Self {
33        Inspect { base, inspect_op }
34    }
35}
36
37impl<I, F> ParallelIterator for Inspect<I, F>
38where
39    I: ParallelIterator,
40    F: Fn(&I::Item) + Sync + Send,
41{
42    type Item = I::Item;
43
44    fn drive_unindexed<C>(self, consumer: C) -> C::Result
45    where
46        C: UnindexedConsumer<Self::Item>,
47    {
48        let consumer1 = InspectConsumer::new(consumer, &self.inspect_op);
49        self.base.drive_unindexed(consumer1)
50    }
51
52    fn opt_len(&self) -> Option<usize> {
53        self.base.opt_len()
54    }
55}
56
57impl<I, F> IndexedParallelIterator for Inspect<I, F>
58where
59    I: IndexedParallelIterator,
60    F: Fn(&I::Item) + Sync + Send,
61{
62    fn drive<C>(self, consumer: C) -> C::Result
63    where
64        C: Consumer<Self::Item>,
65    {
66        let consumer1 = InspectConsumer::new(consumer, &self.inspect_op);
67        self.base.drive(consumer1)
68    }
69
70    fn len(&self) -> usize {
71        self.base.len()
72    }
73
74    fn with_producer<CB>(self, callback: CB) -> CB::Output
75    where
76        CB: ProducerCallback<Self::Item>,
77    {
78        return self.base.with_producer(Callback {
79            callback,
80            inspect_op: self.inspect_op,
81        });
82
83        struct Callback<CB, F> {
84            callback: CB,
85            inspect_op: F,
86        }
87
88        impl<T, F, CB> ProducerCallback<T> for Callback<CB, F>
89        where
90            CB: ProducerCallback<T>,
91            F: Fn(&T) + Sync,
92        {
93            type Output = CB::Output;
94
95            fn callback<P>(self, base: P) -> CB::Output
96            where
97                P: Producer<Item = T>,
98            {
99                let producer = InspectProducer {
100                    base,
101                    inspect_op: &self.inspect_op,
102                };
103                self.callback.callback(producer)
104            }
105        }
106    }
107}
108
109/// ////////////////////////////////////////////////////////////////////////
110
111struct InspectProducer<'f, P, F> {
112    base: P,
113    inspect_op: &'f F,
114}
115
116impl<'f, P, F> Producer for InspectProducer<'f, P, F>
117where
118    P: Producer,
119    F: Fn(&P::Item) + Sync,
120{
121    type Item = P::Item;
122    type IntoIter = iter::Inspect<P::IntoIter, &'f F>;
123
124    fn into_iter(self) -> Self::IntoIter {
125        self.base.into_iter().inspect(self.inspect_op)
126    }
127
128    fn min_len(&self) -> usize {
129        self.base.min_len()
130    }
131
132    fn max_len(&self) -> usize {
133        self.base.max_len()
134    }
135
136    fn split_at(self, index: usize) -> (Self, Self) {
137        let (left, right) = self.base.split_at(index);
138        (
139            InspectProducer {
140                base: left,
141                inspect_op: self.inspect_op,
142            },
143            InspectProducer {
144                base: right,
145                inspect_op: self.inspect_op,
146            },
147        )
148    }
149
150    fn fold_with<G>(self, folder: G) -> G
151    where
152        G: Folder<Self::Item>,
153    {
154        let folder1 = InspectFolder {
155            base: folder,
156            inspect_op: self.inspect_op,
157        };
158        self.base.fold_with(folder1).base
159    }
160}
161
162/// ////////////////////////////////////////////////////////////////////////
163/// Consumer implementation
164
165struct InspectConsumer<'f, C, F> {
166    base: C,
167    inspect_op: &'f F,
168}
169
170impl<'f, C, F> InspectConsumer<'f, C, F> {
171    fn new(base: C, inspect_op: &'f F) -> Self {
172        InspectConsumer { base, inspect_op }
173    }
174}
175
176impl<'f, T, C, F> Consumer<T> for InspectConsumer<'f, C, F>
177where
178    C: Consumer<T>,
179    F: Fn(&T) + Sync,
180{
181    type Folder = InspectFolder<'f, C::Folder, F>;
182    type Reducer = C::Reducer;
183    type Result = C::Result;
184
185    fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
186        let (left, right, reducer) = self.base.split_at(index);
187        (
188            InspectConsumer::new(left, self.inspect_op),
189            InspectConsumer::new(right, self.inspect_op),
190            reducer,
191        )
192    }
193
194    fn into_folder(self) -> Self::Folder {
195        InspectFolder {
196            base: self.base.into_folder(),
197            inspect_op: self.inspect_op,
198        }
199    }
200
201    fn full(&self) -> bool {
202        self.base.full()
203    }
204}
205
206impl<'f, T, C, F> UnindexedConsumer<T> for InspectConsumer<'f, C, F>
207where
208    C: UnindexedConsumer<T>,
209    F: Fn(&T) + Sync,
210{
211    fn split_off_left(&self) -> Self {
212        InspectConsumer::new(self.base.split_off_left(), self.inspect_op)
213    }
214
215    fn to_reducer(&self) -> Self::Reducer {
216        self.base.to_reducer()
217    }
218}
219
220struct InspectFolder<'f, C, F> {
221    base: C,
222    inspect_op: &'f F,
223}
224
225impl<'f, T, C, F> Folder<T> for InspectFolder<'f, C, F>
226where
227    C: Folder<T>,
228    F: Fn(&T),
229{
230    type Result = C::Result;
231
232    fn consume(self, item: T) -> Self {
233        (self.inspect_op)(&item);
234        InspectFolder {
235            base: self.base.consume(item),
236            inspect_op: self.inspect_op,
237        }
238    }
239
240    fn consume_iter<I>(mut self, iter: I) -> Self
241    where
242        I: IntoIterator<Item = T>,
243    {
244        self.base = self
245            .base
246            .consume_iter(iter.into_iter().inspect(self.inspect_op));
247        self
248    }
249
250    fn complete(self) -> C::Result {
251        self.base.complete()
252    }
253
254    fn full(&self) -> bool {
255        self.base.full()
256    }
257}