1use super::plumbing::*;
2use super::ParallelIterator;
3use super::Try;
4
5use std::fmt::{self, Debug};
6use std::marker::PhantomData;
7use std::ops::ControlFlow::{self, Break, Continue};
8
9impl<U, I, ID, F> TryFold<I, U, ID, F>
10where
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{
16 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)]
33pub struct TryFold<I, U, ID, F> {
34 base: I,
35 identity: ID,
36 fold_op: F,
37 marker: PhantomData<U>,
38}
39
40impl<U, I: ParallelIterator + Debug, ID, F> Debug for TryFold<I, U, ID, F> {
41 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42 f.debug_struct("TryFold").field("base", &self.base).finish()
43 }
44}
45
46impl<U, I, ID, F> ParallelIterator for TryFold<I, U, ID, F>
47where
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
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
69struct TryFoldConsumer<'c, U, C, ID, F> {
70 base: C,
71 identity: &'c ID,
72 fold_op: &'c F,
73 marker: PhantomData<U>,
74}
75
76impl<'r, U, T, C, ID, F> Consumer<T> for TryFoldConsumer<'r, U, C, ID, F>
77where
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
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
99 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
107 fn full(&self) -> bool {
108 self.base.full()
109 }
110}
111
112impl<'r, U, T, C, ID, F> UnindexedConsumer<T> for TryFoldConsumer<'r, U, C, ID, F>
113where
114 C: UnindexedConsumer<U>,
115 F: Fn(U::Output, T) -> U + Sync,
116 ID: Fn() -> U::Output + Sync,
117 U: Try + Send,
118{
119 fn split_off_left(&self) -> Self {
120 TryFoldConsumer {
121 base: self.base.split_off_left(),
122 ..*self
123 }
124 }
125
126 fn to_reducer(&self) -> Self::Reducer {
127 self.base.to_reducer()
128 }
129}
130
131struct TryFoldFolder<'r, C, U: Try, F> {
132 base: C,
133 fold_op: &'r F,
134 control: ControlFlow<U::Residual, U::Output>,
135}
136
137impl<'r, C, U, F, T> Folder<T> for TryFoldFolder<'r, C, U, F>
138where
139 C: Folder<U>,
140 F: Fn(U::Output, T) -> U + Sync,
141 U: Try,
142{
143 type Result = C::Result;
144
145 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
153 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
161 fn full(&self) -> bool {
162 match self.control {
163 Break(_) => true,
164 _ => self.base.full(),
165 }
166 }
167}
168
169// ///////////////////////////////////////////////////////////////////////////
170
171impl<U, I, F> TryFoldWith<I, U, F>
172where
173 I: ParallelIterator,
174 F: Fn(U::Output, I::Item) -> U + Sync,
175 U: Try + Send,
176 U::Output: Clone + Send,
177{
178 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)]
194pub struct TryFoldWith<I, U: Try, F> {
195 base: I,
196 item: U::Output,
197 fold_op: F,
198}
199
200impl<I: ParallelIterator + Debug, U: Try, F> Debug for TryFoldWith<I, U, F>
201where
202 U::Output: Debug,
203{
204 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
212impl<U, I, F> ParallelIterator for TryFoldWith<I, U, F>
213where
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
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
234struct TryFoldWithConsumer<'c, C, U: Try, F> {
235 base: C,
236 item: U::Output,
237 fold_op: &'c F,
238}
239
240impl<'r, U, T, C, F> Consumer<T> for TryFoldWithConsumer<'r, C, U, F>
241where
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
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
267 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
275 fn full(&self) -> bool {
276 self.base.full()
277 }
278}
279
280impl<'r, U, T, C, F> UnindexedConsumer<T> for TryFoldWithConsumer<'r, C, U, F>
281where
282 C: UnindexedConsumer<U>,
283 F: Fn(U::Output, T) -> U + Sync,
284 U: Try + Send,
285 U::Output: Clone + Send,
286{
287 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
295 fn to_reducer(&self) -> Self::Reducer {
296 self.base.to_reducer()
297 }
298}
299