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