1 use super::plumbing::*;
2 use super::*;
3 
4 use std::fmt::{self, Debug};
5 use 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)]
16 pub struct Inspect<I: ParallelIterator, F> {
17     base: I,
18     inspect_op: F,
19 }
20 
21 impl<I: ParallelIterator + Debug, F> Debug for Inspect<I, F> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result22     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23         f.debug_struct("Inspect").field("base", &self.base).finish()
24     }
25 }
26 
27 impl<I, F> Inspect<I, F>
28 where
29     I: ParallelIterator,
30 {
31     /// Creates a new `Inspect` iterator.
new(base: I, inspect_op: F) -> Self32     pub(super) fn new(base: I, inspect_op: F) -> Self {
33         Inspect { base, inspect_op }
34     }
35 }
36 
37 impl<I, F> ParallelIterator for Inspect<I, F>
38 where
39     I: ParallelIterator,
40     F: Fn(&I::Item) + Sync + Send,
41 {
42     type Item = I::Item;
43 
drive_unindexed<C>(self, consumer: C) -> C::Result where C: UnindexedConsumer<Self::Item>,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 
opt_len(&self) -> Option<usize>52     fn opt_len(&self) -> Option<usize> {
53         self.base.opt_len()
54     }
55 }
56 
57 impl<I, F> IndexedParallelIterator for Inspect<I, F>
58 where
59     I: IndexedParallelIterator,
60     F: Fn(&I::Item) + Sync + Send,
61 {
drive<C>(self, consumer: C) -> C::Result where C: Consumer<Self::Item>,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 
len(&self) -> usize70     fn len(&self) -> usize {
71         self.base.len()
72     }
73 
with_producer<CB>(self, callback: CB) -> CB::Output where CB: ProducerCallback<Self::Item>,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 
111 struct InspectProducer<'f, P, F> {
112     base: P,
113     inspect_op: &'f F,
114 }
115 
116 impl<'f, P, F> Producer for InspectProducer<'f, P, F>
117 where
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 
into_iter(self) -> Self::IntoIter124     fn into_iter(self) -> Self::IntoIter {
125         self.base.into_iter().inspect(self.inspect_op)
126     }
127 
min_len(&self) -> usize128     fn min_len(&self) -> usize {
129         self.base.min_len()
130     }
131 
max_len(&self) -> usize132     fn max_len(&self) -> usize {
133         self.base.max_len()
134     }
135 
split_at(self, index: usize) -> (Self, Self)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 
fold_with<G>(self, folder: G) -> G where G: Folder<Self::Item>,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 
165 struct InspectConsumer<'f, C, F> {
166     base: C,
167     inspect_op: &'f F,
168 }
169 
170 impl<'f, C, F> InspectConsumer<'f, C, F> {
new(base: C, inspect_op: &'f F) -> Self171     fn new(base: C, inspect_op: &'f F) -> Self {
172         InspectConsumer { base, inspect_op }
173     }
174 }
175 
176 impl<'f, T, C, F> Consumer<T> for InspectConsumer<'f, C, F>
177 where
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 
split_at(self, index: usize) -> (Self, Self, Self::Reducer)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 
into_folder(self) -> Self::Folder194     fn into_folder(self) -> Self::Folder {
195         InspectFolder {
196             base: self.base.into_folder(),
197             inspect_op: self.inspect_op,
198         }
199     }
200 
full(&self) -> bool201     fn full(&self) -> bool {
202         self.base.full()
203     }
204 }
205 
206 impl<'f, T, C, F> UnindexedConsumer<T> for InspectConsumer<'f, C, F>
207 where
208     C: UnindexedConsumer<T>,
209     F: Fn(&T) + Sync,
210 {
split_off_left(&self) -> Self211     fn split_off_left(&self) -> Self {
212         InspectConsumer::new(self.base.split_off_left(), &self.inspect_op)
213     }
214 
to_reducer(&self) -> Self::Reducer215     fn to_reducer(&self) -> Self::Reducer {
216         self.base.to_reducer()
217     }
218 }
219 
220 struct InspectFolder<'f, C, F> {
221     base: C,
222     inspect_op: &'f F,
223 }
224 
225 impl<'f, T, C, F> Folder<T> for InspectFolder<'f, C, F>
226 where
227     C: Folder<T>,
228     F: Fn(&T),
229 {
230     type Result = C::Result;
231 
consume(self, item: T) -> Self232     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 
consume_iter<I>(mut self, iter: I) -> Self where I: IntoIterator<Item = T>,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 
complete(self) -> C::Result250     fn complete(self) -> C::Result {
251         self.base.complete()
252     }
253 
full(&self) -> bool254     fn full(&self) -> bool {
255         self.base.full()
256     }
257 }
258