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<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}