par_iter/iter/
try_fold.rs

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/// `TryFold` is an iterator that applies a function over an iterator producing
27/// a single value. This struct is created by the [`try_fold()`] method on
28/// [`ParallelIterator`]
29///
30/// [`try_fold()`]: trait.ParallelIterator.html#method.try_fold
31/// [`ParallelIterator`]: trait.ParallelIterator.html
32#[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
170// ///////////////////////////////////////////////////////////////////////////
171
172impl<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/// `TryFoldWith` is an iterator that applies a function over an iterator
189/// producing a single value. This struct is created by the [`try_fold_with()`]
190/// method on [`ParallelIterator`]
191///
192/// [`try_fold_with()`]: trait.ParallelIterator.html#method.try_fold_with
193/// [`ParallelIterator`]: trait.ParallelIterator.html
194#[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}