rayon/iter/
try_fold.rs

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