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}
258