1 use super::plumbing::*;
2 use super::ParallelIterator;
3 use super::Try;
4 
5 use std::fmt::{self, Debug};
6 use std::marker::PhantomData;
7 use std::ops::ControlFlow::{self, Break, Continue};
8 
9 impl<U, I, ID, F> TryFold<I, U, ID, F>
10 where
11     I: ParallelIterator,
12     F: Fn(U::Output, I::Item) -> U + Sync + Send,
13     ID: Fn() -> U::Output + Sync + Send,
14     U: Try + Send,
15 {
new(base: I, identity: ID, fold_op: F) -> Self16     pub(super) fn new(base: I, identity: ID, fold_op: F) -> Self {
17         TryFold {
18             base,
19             identity,
20             fold_op,
21             marker: PhantomData,
22         }
23     }
24 }
25 
26 /// `TryFold` is an iterator that applies a function over an iterator producing a single value.
27 /// This struct is created by the [`try_fold()`] method on [`ParallelIterator`]
28 ///
29 /// [`try_fold()`]: trait.ParallelIterator.html#method.try_fold
30 /// [`ParallelIterator`]: trait.ParallelIterator.html
31 #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
32 #[derive(Clone)]
33 pub struct TryFold<I, U, ID, F> {
34     base: I,
35     identity: ID,
36     fold_op: F,
37     marker: PhantomData<U>,
38 }
39 
40 impl<U, I: ParallelIterator + Debug, ID, F> Debug for TryFold<I, U, ID, F> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result41     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42         f.debug_struct("TryFold").field("base", &self.base).finish()
43     }
44 }
45 
46 impl<U, I, ID, F> ParallelIterator for TryFold<I, U, ID, F>
47 where
48     I: ParallelIterator,
49     F: Fn(U::Output, I::Item) -> U + Sync + Send,
50     ID: Fn() -> U::Output + Sync + Send,
51     U: Try + Send,
52 {
53     type Item = U;
54 
drive_unindexed<C>(self, consumer: C) -> C::Result where C: UnindexedConsumer<Self::Item>,55     fn drive_unindexed<C>(self, consumer: C) -> C::Result
56     where
57         C: UnindexedConsumer<Self::Item>,
58     {
59         let consumer1 = TryFoldConsumer {
60             base: consumer,
61             identity: &self.identity,
62             fold_op: &self.fold_op,
63             marker: PhantomData,
64         };
65         self.base.drive_unindexed(consumer1)
66     }
67 }
68 
69 struct TryFoldConsumer<'c, U, C, ID, F> {
70     base: C,
71     identity: &'c ID,
72     fold_op: &'c F,
73     marker: PhantomData<U>,
74 }
75 
76 impl<'r, U, T, C, ID, F> Consumer<T> for TryFoldConsumer<'r, U, C, ID, F>
77 where
78     C: Consumer<U>,
79     F: Fn(U::Output, T) -> U + Sync,
80     ID: Fn() -> U::Output + Sync,
81     U: Try + Send,
82 {
83     type Folder = TryFoldFolder<'r, C::Folder, U, F>;
84     type Reducer = C::Reducer;
85     type Result = C::Result;
86 
split_at(self, index: usize) -> (Self, Self, Self::Reducer)87     fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
88         let (left, right, reducer) = self.base.split_at(index);
89         (
90             TryFoldConsumer { base: left, ..self },
91             TryFoldConsumer {
92                 base: right,
93                 ..self
94             },
95             reducer,
96         )
97     }
98 
into_folder(self) -> Self::Folder99     fn into_folder(self) -> Self::Folder {
100         TryFoldFolder {
101             base: self.base.into_folder(),
102             control: Continue((self.identity)()),
103             fold_op: self.fold_op,
104         }
105     }
106 
full(&self) -> bool107     fn full(&self) -> bool {
108         self.base.full()
109     }
110 }
111 
112 impl<'r, U, T, C, ID, F> UnindexedConsumer<T> for TryFoldConsumer<'r, U, C, ID, F>
113 where
114     C: UnindexedConsumer<U>,
115     F: Fn(U::Output, T) -> U + Sync,
116     ID: Fn() -> U::Output + Sync,
117     U: Try + Send,
118 {
split_off_left(&self) -> Self119     fn split_off_left(&self) -> Self {
120         TryFoldConsumer {
121             base: self.base.split_off_left(),
122             ..*self
123         }
124     }
125 
to_reducer(&self) -> Self::Reducer126     fn to_reducer(&self) -> Self::Reducer {
127         self.base.to_reducer()
128     }
129 }
130 
131 struct TryFoldFolder<'r, C, U: Try, F> {
132     base: C,
133     fold_op: &'r F,
134     control: ControlFlow<U::Residual, U::Output>,
135 }
136 
137 impl<'r, C, U, F, T> Folder<T> for TryFoldFolder<'r, C, U, F>
138 where
139     C: Folder<U>,
140     F: Fn(U::Output, T) -> U + Sync,
141     U: Try,
142 {
143     type Result = C::Result;
144 
consume(mut self, item: T) -> Self145     fn consume(mut self, item: T) -> Self {
146         let fold_op = self.fold_op;
147         if let Continue(acc) = self.control {
148             self.control = fold_op(acc, item).branch();
149         }
150         self
151     }
152 
complete(self) -> C::Result153     fn complete(self) -> C::Result {
154         let item = match self.control {
155             Continue(c) => U::from_output(c),
156             Break(r) => U::from_residual(r),
157         };
158         self.base.consume(item).complete()
159     }
160 
full(&self) -> bool161     fn full(&self) -> bool {
162         match self.control {
163             Break(_) => true,
164             _ => self.base.full(),
165         }
166     }
167 }
168 
169 // ///////////////////////////////////////////////////////////////////////////
170 
171 impl<U, I, F> TryFoldWith<I, U, F>
172 where
173     I: ParallelIterator,
174     F: Fn(U::Output, I::Item) -> U + Sync,
175     U: Try + Send,
176     U::Output: Clone + Send,
177 {
new(base: I, item: U::Output, fold_op: F) -> Self178     pub(super) fn new(base: I, item: U::Output, fold_op: F) -> Self {
179         TryFoldWith {
180             base,
181             item,
182             fold_op,
183         }
184     }
185 }
186 
187 /// `TryFoldWith` is an iterator that applies a function over an iterator producing a single value.
188 /// This struct is created by the [`try_fold_with()`] method on [`ParallelIterator`]
189 ///
190 /// [`try_fold_with()`]: trait.ParallelIterator.html#method.try_fold_with
191 /// [`ParallelIterator`]: trait.ParallelIterator.html
192 #[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
193 #[derive(Clone)]
194 pub struct TryFoldWith<I, U: Try, F> {
195     base: I,
196     item: U::Output,
197     fold_op: F,
198 }
199 
200 impl<I: ParallelIterator + Debug, U: Try, F> Debug for TryFoldWith<I, U, F>
201 where
202     U::Output: Debug,
203 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result204     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
205         f.debug_struct("TryFoldWith")
206             .field("base", &self.base)
207             .field("item", &self.item)
208             .finish()
209     }
210 }
211 
212 impl<U, I, F> ParallelIterator for TryFoldWith<I, U, F>
213 where
214     I: ParallelIterator,
215     F: Fn(U::Output, I::Item) -> U + Sync + Send,
216     U: Try + Send,
217     U::Output: Clone + Send,
218 {
219     type Item = U;
220 
drive_unindexed<C>(self, consumer: C) -> C::Result where C: UnindexedConsumer<Self::Item>,221     fn drive_unindexed<C>(self, consumer: C) -> C::Result
222     where
223         C: UnindexedConsumer<Self::Item>,
224     {
225         let consumer1 = TryFoldWithConsumer {
226             base: consumer,
227             item: self.item,
228             fold_op: &self.fold_op,
229         };
230         self.base.drive_unindexed(consumer1)
231     }
232 }
233 
234 struct TryFoldWithConsumer<'c, C, U: Try, F> {
235     base: C,
236     item: U::Output,
237     fold_op: &'c F,
238 }
239 
240 impl<'r, U, T, C, F> Consumer<T> for TryFoldWithConsumer<'r, C, U, F>
241 where
242     C: Consumer<U>,
243     F: Fn(U::Output, T) -> U + Sync,
244     U: Try + Send,
245     U::Output: Clone + Send,
246 {
247     type Folder = TryFoldFolder<'r, C::Folder, U, F>;
248     type Reducer = C::Reducer;
249     type Result = C::Result;
250 
split_at(self, index: usize) -> (Self, Self, Self::Reducer)251     fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
252         let (left, right, reducer) = self.base.split_at(index);
253         (
254             TryFoldWithConsumer {
255                 base: left,
256                 item: self.item.clone(),
257                 ..self
258             },
259             TryFoldWithConsumer {
260                 base: right,
261                 ..self
262             },
263             reducer,
264         )
265     }
266 
into_folder(self) -> Self::Folder267     fn into_folder(self) -> Self::Folder {
268         TryFoldFolder {
269             base: self.base.into_folder(),
270             control: Continue(self.item),
271             fold_op: self.fold_op,
272         }
273     }
274 
full(&self) -> bool275     fn full(&self) -> bool {
276         self.base.full()
277     }
278 }
279 
280 impl<'r, U, T, C, F> UnindexedConsumer<T> for TryFoldWithConsumer<'r, C, U, F>
281 where
282     C: UnindexedConsumer<U>,
283     F: Fn(U::Output, T) -> U + Sync,
284     U: Try + Send,
285     U::Output: Clone + Send,
286 {
split_off_left(&self) -> Self287     fn split_off_left(&self) -> Self {
288         TryFoldWithConsumer {
289             base: self.base.split_off_left(),
290             item: self.item.clone(),
291             ..*self
292         }
293     }
294 
to_reducer(&self) -> Self::Reducer295     fn to_reducer(&self) -> Self::Reducer {
296         self.base.to_reducer()
297     }
298 }
299