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